一、场景复现
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?
二、原因分析
- web项目启动注册requestMappingHandlerAdapter的时候会初始化WebBindingInitializer
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
-
而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);
}
}
- 添加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);
}
-
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 版权协议,转载请附上原文出处链接和本声明。