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

  • Post author:
  • Post category:其他




一、场景复现



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);

}



版权声明:本文为qq_37274323原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。