【SpringBoot】添加Converter解析器中使用lambda表达式代替匿名内部类是启动报错: does the class parameterize those types?

本文分析了Spring Boot项目启动时,由于Converter注册导致的类型无法确定问题,详细解释了问题的原因和Lambda表达式在其中的影响。提出了三种解决办法,包括使用具体类型接口、等待`requestMappingHandlerAdapter`注册结束后再注册Converter以及自定义Converter接口。这些解决方案有助于避免启动时的类型转换异常,确保项目正常运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、场景复现

1、相关代码

	/**
	 * 注入自定义的LocalDateTime转换器
	 *
	 * @return 时间转换器
	 */
	@Bean
	public Converter<String, LocalDateTime> localDateTimeConverter() {
		return source -> LocalDateTime.parse(source.trim(), DateTimeFormatter.ofPattern(LOCAL_DATE_TIME_FORMAT));
	}

2、报错信息

Caused by: java.lang.IllegalArgumentException: 
Unable to determine source type <S> and target type <T> for your Converter [com.example.demo126.config.MappingConverterAdapter$$Lambda$522/817994751];
does the class parameterize those types?

二、原因分析

  1. web项目启动注册requestMappingHandlerAdapter的时候会初始化WebBindingInitializer
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
  1. 而ConfigurableWebBindingInitializer需要FormattingConversionService, 而FormattingConversionService会将所有的Converter添加进来
    添加的时候需要获取泛型信息
@Override
public void addFormatters(FormatterRegistry registry) {
    for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
        registry.addConverter(converter);
    }
    for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
         registry.addConverter(converter);
    }
    for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
        registry.addFormatter(formatter);
    }
}
  1. 添加Converter.class 一般是通过接口获取两个泛型的具体类型,
public ResolvableType as(Class<?> type) {
    if (this == NONE) {
        return NONE;
    }
    Class<?> resolved = resolve();
    if (resolved == null || resolved == type) {
        return this;
    }
    for (ResolvableType interfaceType : getInterfaces()) {
        ResolvableType interfaceAsType = interfaceType.as(type);
    if (interfaceAsType != NONE) {
        return interfaceAsType;
        }
    }
    return getSuperType().as(type);
}
  1. Lambda表达式的接口是Converter<?, ?>,不能的到具体的类型\color{#FF0000}{不能的到具体的类型}不能的到具体的类型

三、解决办法

3.1、具体类型接口,不再是泛型

  @Bean
  public StringToLocalDateTimeConverter localDateTimeConverter1() {
      return  (source ->  LocalDateTime.parse((String)source, DateTimeUtils.DEFAULT_FORMATTER));
  }

  interface StringToLocalDateTimeConverter extends Converter<String, LocalDateTime> {

  }

3.2、等待requestMappingHandlerAdapter注册结束在注册

就是等requestMappingHandlerAdapterbean注册完成之后再添加自己的converter就不会注册到FormattingConversionService中

    @Bean
    @ConditionalOnBean(name = "requestMappingHandlerAdapter")
    public Converter<String, LocalDateTime> localDateTimeConverter() {
        return source -> LocalDateTime.parse(source, DateTimeUtils.DEFAULT_FORMATTER);
    }

2022年8月8日14:15:00修改
如果实在stater中进行使用则应该使用@DependsOn注解,依旧是启动顺序的问题

	@Bean
	@DependsOn("requestMappingHandlerAdapter")
	public Converter<String, Date> dateConverter() {
		return source -> DateUtil.parse(source.trim());
	}

3.3、自定义Converter<S,T>接口

其实有点类似第一种解决方案

@FunctionalInterface
public interface Converter<S, T> {
    
    T convert(S source);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值