引言
在开发过程中,难免需要用到对象转换器,比如apache的BeanUtils、ConvertUtils还有spring的BeanUtils。我们在公司的项目中就使用了apache的BeanUtils和ConvertUtils作为公共的对象转换工具。但是在没有充分理解源代码的情况下,添加个性化Converter就会出现意想不到的bug。下面我来介绍一下我在排查问题中遇到的这个bug。
问题
本文采用的是jdk1.8 commons-beanutils 1.9.3的代码。先来描述一下我遇到的问题,我的使用场景是将String类型的日期转换成Date类型的日期,当然我事先已经配置好了String类型转换Date类型的转换器。但是还是出现了如下报错。而且这个报错非常有特点:
- 出现一次以后就会一直出现,重启后又恢复
- 同样的代码在某一个线程会报错,在其他线程又不报错非常奇怪。
2019-12-03 09:02:27.119 [TID:136.209.15753349468560005] [http-nio-9092-exec-59] WARN org.apache.commons.beanutils.converters.DateConverter - DateConverter does not support default String to 'Date' conversion.
2019-12-03 09:02:27.119 [TID:136.209.15753349468560005] [http-nio-9092-exec-59] WARN org.apache.commons.beanutils.converters.DateConverter - (N.B. Re-configure Converter or use alternative implementation)
org.apache.commons.beanutils.ConversionException: DateConverter does not support default String to 'Date' conversion.
at org.apache.commons.beanutils.converters.DateTimeConverter.toDate(DateTimeConverter.java:474)
at org.apache.commons.beanutils.converters.DateTimeConverter.convertToType(DateTimeConverter.java:347)
at org.apache.commons.beanutils.converters.AbstractConverter.convert(AbstractConverter.java:169)
at org.apache.commons.beanutils.converters.ConverterFacade.convert(ConverterFacade.java:61)
at org.apache.commons.beanutils.ConvertUtilsBean.convert(ConvertUtilsBean.java:566)
at org.apache.commons.beanutils.ConvertUtils.convert(ConvertUtils.java:282)
其次,我们在代码中是自定义了BeanUtils,只是使用了ConvertUtils,当然大部分的BeanUtils代码还是和apache的BeanUtils代码一致的。以下是这个问题代码。
public class RabbitBeanUtils {
static {
ConvertUtils.register(new ConverterWrapper(ConvertUtils.lookup(Date.class)) {
@Override
public Object convert(Class type, Object arg) {
if (arg instanceof Date) {
return arg;
}
if (arg instanceof Number) {
Number value = (Number) arg;
return new Date(value.longValue());
} else if (arg instanceof String) {
return TypeConverter.parse((String) arg);
}
return super.convert(type, arg);
}
}, Date.class);
ConvertUtils.register(new ConverterWrapper(ConvertUtils.lookup(List.class)) {
@Override
public Object convert(Class type, Obj