Spring源码解析(十九)-转换体系

寒窗苦读十余载,奋笔疾书若干年

Spring版本

5.2.5.RELEASE

参考

《芋道源码》

源码解读

在之前的文章《Spring源码解析(十)-填充bean属性》中的applyPropertyValues方法,使用到了convertForProperty做了类型转换,本篇,就让我们深入了解一下spring的转换体系。

spring中存在以下几种转换器,他们分别支持不同的转换功能:

  • Converter:用于 1:1 的 source -> target 类型转换。
  • ConverterFactory:用于 1:N 的 source -> target 类型转换。
  • ConditionalConverter:有条件的 source -> target 类型转换。
  • GenericConverter:用于 N:N 的 source -> target 类型转换。

1 Converter

1.1 Demo

在查看源码之前,先从一个例子入手,方便我们debug跟踪源码逻辑

1.1.1 Student

public class Student {

    private String id;

    private String name;

    private String desc;

    private StudentService studentService;

    static class  StudentService{

        private Integer age;
        private String name;

        // 省略getters和setters
    }
    // 省略getters和setters
}

1.1.2 StudentConverter

public class StudentConverter implements Converter {

    @Override
    public StudentService convert(String source) {
        if (StringUtils.hasLength(source)) {
            String[] sources = StringUtils.split(source, "#");
            if (sources != null && sources.length >= 2) {
                StudentService student = new StudentService();
                student.setAge(Integer.valueOf(sources[0]));
                student.setName(sources[1]);
                return student;
            }
        }
        return null;
    }
}

1.1.3 spring.xml




    
        
            
                
            
        
    

    

    
        
    

1.1.4 测试

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.getStudentService().getAge());
        System.out.println(student.getStudentService().getName());
}

结果:

18
123

逻辑比较简单,在spring.xml中,我们注册了一个StudentConverter类型的转换器bean,之后将这个转换器bean添加到ConversionServiceFactoryBean的转换器列表converters中。然后声明了一个Student类型的bean,该bean的studentService属性是一个内部类,不过该属性初始参数传入了string类型的18#123,最后通过转换器成功将18#123转换为StudentServiceage属性和name属性,实现了stringStudentService的转换。

1.2 源码

1.2.1 Converter

@FunctionalInterface
public interface Converter {

    /**
     * Convert the source object of type {@code S} to target type {@code T}.
     * @param source the source object to convert, which must be an instance of {@code S} (never {@code null})
     * @return the converted object, which must be an instance of {@code T} (potentially {@code null})
     * @throws IllegalArgumentException if the source cannot be converted to the desired target type
     */
    @Nullable
    T convert(S source);

}

可以看到converter的源码很简单,是一个函数式接口,定义了convert函数,由子类去具体实现

1.2.2 AbstractAutowireCapableBeanFactory#convertForProperty

    @Nullable
    private Object convertForProperty(
            @Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {

        // 判断是否是BeanWrapperImpl类型
        // BeanWrapperImpl实现了TypeConverterSupport接口,所以也支持类型转换
        if (converter instanceof BeanWrapperImpl) {
            return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
        }
        else {
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            // 获取set方法
            MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
            return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
        }
    }

前文提到,在applyPropertyValues中调用了convertForProperty进行类型转换,可以看到,这个方法的逻辑如下:

  • 判断入参converter是否是BeanWrapperImpl类型,如果是,交由BeanWrapperImpl进行转换。之所以需要判断是否是BeanWrapperImpl类型,是因为BeanWrapperImpl实现了TypeConverterSupport接口,所以它也是支持类型转换的
  • 如果不是BeanWrapperImpl类型,那么交由converterconvertIfNecessary进行转换

converter有以下三个实现类:

convertIfNecessary具体实现类

可以看到

  • CustomTypeConverter:测试包下的,明显不是我们关心的实现
  • DataBinder:数据绑定器,应该是spring mvc入参做转换的实现类,也不是本篇的关心内容
  • TypeConverterSupport:类型转换支持,通过debug可以确定是进入该类的实现

1.2.3 TypeConverterSupport#convertIfNecessary

    @Override
    @Nullable
    public  T convertIfNecessary(@Nullable Object value, @Nullable Class requiredType,
            @Nullable MethodParameter methodParam) throws TypeMismatchException {

        return convertIfNecessary(value, requiredType,
                (methodParam != null ? new TypeDescriptor(methodParam) : TypeDescriptor.valueOf(requiredType)));
    }

    @Nullable
    @Override
    public  T convertIfNecessary(@Nullable Object value, @Nullable Class requiredType,
            @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {

        Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate");
        try {
            // 委托给typeConverterDelegate进行类型转换
            return this.typeConverterDelegate.convertIfNecessary(null, null, value, requiredType, typeDescriptor);
        }
        catch (ConverterNotFoundException | IllegalStateException ex) {
            throw new ConversionNotSupportedException(value, requiredType, ex);
        }
        catch (ConversionException | IllegalArgumentException ex) {
            throw new TypeMismatchException(value, requiredType, ex);
        }
    }

可以看到重载方法中委托给了typeConverterDelegate进行类型转换

1.2.4 TypeConverterDelegate#convertIfNecessary

    @Nullable
    public  T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue,
            @Nullable Class requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException {

        // Custom editor for this type?
        PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);

        ConversionFailedException conversionAttemptEx = null;

        // No custom editor but custom ConversionService specified?
        // 获取注册的ConversionService
        // ConversionService是一个定义了canConvert以及convert方法的接口
        ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
        if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
            // 获取转换前的数据的源类型
            TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
            // 判断是否可做转化
            if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
                try {
                    // 执行转化
                    return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
                }
                catch (ConversionFailedException ex) {
                    // fallback to default conversion logic below
                    conversionAttemptEx = ex;
                }
            }
        }
        // 其余省略
}
  • 首先获取到ConversionServiceConversionService是一个定义了canConvert以及convert方法的接口(该接口由GenericConversionService实现):
public interface ConversionService {
    
    boolean canConvert(@Nullable Class sourceType, Class targetType);

    boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
    
    @Nullable
     T convert(@Nullable Object source, Class targetType);
    
    @Nullable
    Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);

}
  • 之后通过ConversionServicecanConvert方法判断是否可以进行转换,如果可以,则通过convert方法进行转换

1.2.5 GenericConversionService#canConvert

    @Override
    public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
        Assert.notNull(targetType, "Target type to convert to cannot be null");
        if (sourceType == null) {
            return true;
        }
        // 获取转化器,如果不为空,那就是可以转化的
        GenericConverter converter = getConverter(sourceType, targetType);
        return (converter != null);
    }

通过sourceTypetargetType来获取转换器converter,如果能获取到转换器(converter != null),自然说明是可以进行转换的

1.2.6 GenericConversionService#getConverter

    @Nullable
    protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
        // 构建key
        ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
        // 通过key去缓存中查找
        GenericConverter converter = this.converterCache.get(key);
        if (converter != null) {
            return (converter != NO_MATCH ? converter : null);
        }

        // 缓存查找不到,从converters中查找
        converter = this.converters.find(sourceType, targetType);
        if (converter == null) {
            // 获取获取不到,那么获取默认converter
            // 该默认converter可能是NO_OP_CONVERTER(targetType是sourceType的超类),否则为空
            converter = getDefaultConverter(sourceType, targetType);
        }

        // 如果converters查找的到,那么加入缓存
        if (converter != null) {
            this.converterCache.put(key, converter);
            return converter;
        }

        this.converterCache.put(key, NO_MATCH);
        return null;
    }
  • 首先从缓存converterCache中查找
    • 若有,直接返回
    • 若没有,通过find方法进行匹配
      • 若匹配不到,通过getDefaultConverter获取默认转换器
  • 如果转换器不为空,加入缓存converterCache当中,并返回该转换器
  • 否则,往converterCache写入没有匹配结果的缓存,并返回null

1.2.7 GenericConversionService#find

        @Nullable
        public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {
            // Search the full type hierarchy
            List> sourceCandidates = getClassHierarchy(sourceType.getType());
            List> targetCandidates = getClassHierarchy(targetType.getType());
            for (Class sourceCandidate : sourceCandidates) {
                for (Class targetCandidate : targetCandidates) {
                    // 构建ConvertiblePair对象
                    ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);
                    // 获取已注册的converter
                    GenericConverter converter = getRegisteredConverter(sourceType, targetType, convertiblePair);
                    if (converter != null) {
                        return converter;
                    }
                }
            }
            return null;
        }
  • 通过getClassHierarchy分别获取sourceTypetargetType的超类及这些超类对应的接口
  • 通过双重for循环,依次对sourceCandidatestargetCandidates构造ConvertiblePair对象
  • 通过getRegisteredConverter查找ConvertiblePair对象对应的转换器converter,不为null则直接返回

1.2.8 GenericConversionService#getClassHierarchy

        private List> getClassHierarchy(Class type) {
            List> hierarchy = new ArrayList<>(20);
            Set> visited = new HashSet<>(20);
            // 加入type对应的类型
            addToClassHierarchy(0, ClassUtils.resolvePrimitiveIfNecessary(type), false, hierarchy, visited);
            boolean array = type.isArray();

            int i = 0;
            // 开始递归,将type对应的父类型以及接口不断加入hierarchy中知道碰到Object
            while (i < hierarchy.size()) {
                Class candidate = hierarchy.get(i);
                candidate = (array ? candidate.getComponentType() : ClassUtils.resolvePrimitiveIfNecessary(candidate));
                Class superclass = candidate.getSuperclass();
                // 跳出循环条件
                if (superclass != null && superclass != Object.class && superclass != Enum.class) {
                    // 加入父类型
                    addToClassHierarchy(i + 1, candidate.getSuperclass(), array, hierarchy, visited);
                }
                // 加入接口
                addInterfacesToClassHierarchy(candidate, array, hierarchy, visited);
                i++;
            }

            // 处理Enum
            if (Enum.class.isAssignableFrom(type)) {
                addToClassHierarchy(hierarchy.size(), Enum.class, array, hierarchy, visited);
                addToClassHierarchy(hierarchy.size(), Enum.class, false, hierarchy, visited);
                addInterfacesToClassHierarchy(Enum.class, array, hierarchy, visited);
            }

            // 处理Object
            addToClassHierarchy(hierarchy.size(), Object.class, array, hierarchy, visited);
            addToClassHierarchy(hierarchy.size(), Object.class, false, hierarchy, visited);
            return hierarchy;
        }

代码有点长,划分成几个部分进行解读

addToClassHierarchy(0, ClassUtils.resolvePrimitiveIfNecessary(type), false, hierarchy, visited);
  • 首先往hierarchyvisited这俩个集合压入第一个元素,该元素为type对应的class类型,resolvePrimitiveIfNecessary方法顾名知义:在有必要的情况下,将基本类型转化为包装类型:
    private static final Map, Class> primitiveTypeToWrapperMap = new IdentityHashMap<>(8);
    static {
        primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
        primitiveWrapperTypeMap.put(Byte.class, byte.class);
        primitiveWrapperTypeMap.put(Character.class, char.class);
        primitiveWrapperTypeMap.put(Double.class, double.class);
        primitiveWrapperTypeMap.put(Float.class, float.class);
        primitiveWrapperTypeMap.put(Integer.class, int.class);
        primitiveWrapperTypeMap.put(Long.class, long.class);
        primitiveWrapperTypeMap.put(Short.class, short.class);
        primitiveWrapperTypeMap.put(Void.class, void.class);

        // Map entry iteration is less expensive to initialize than forEach with lambdas
        for (Map.Entry, Class> entry : primitiveWrapperTypeMap.entrySet()) {
            // key和value互换
            primitiveTypeToWrapperMap.put(entry.getValue(), entry.getKey());
            registerCommonClasses(entry.getKey());
        }
    }
    public static Class resolvePrimitiveIfNecessary(Class clazz) {
        Assert.notNull(clazz, "Class must not be null");
        return (clazz.isPrimitive() && clazz != void.class ? primitiveTypeToWrapperMap.get(clazz) : clazz);
    }

addToClassHierarchy方法则是将元素按照index加入到hierarchyvisited俩个集合中:

        private void addToClassHierarchy(int index, Class type, boolean asArray,
                List> hierarchy, Set> visited) {

            if (asArray) {
                // 如果是数组,获取数组的元素类型componentType
                type = Array.newInstance(type, 0).getClass();
            }
            if (visited.add(type)) {
                hierarchy.add(index, type);
            }
        }
            while (i < hierarchy.size()) {
                Class candidate = hierarchy.get(i);
                candidate = (array ? candidate.getComponentType() : ClassUtils.resolvePrimitiveIfNecessary(candidate));
                Class superclass = candidate.getSuperclass();
                // 跳出循环条件
                if (superclass != null && superclass != Object.class && superclass != Enum.class) {
                    // 加入父类型
                    addToClassHierarchy(i + 1, candidate.getSuperclass(), array, hierarchy, visited);
                }
                // 加入接口
                addInterfacesToClassHierarchy(candidate, array, hierarchy, visited);
                i++;
            }
  • 接着开始递归,从之前加入的第一个元素开始,如果该元素是数组类型,获取其元素类型,否则,获取其本身类型;之后获取该类型对应的超类,如果超类不为空且既不是Object也不是Enum(递归终止条件),加入该类型到hierarchyvisited俩个集合,之后通过addInterfacesToClassHierarchy方法将该超类实现的接口也加入hierarchyvisited俩个集合
// 处理Enum
if(Enum.class.isAssignableFrom(type)) {
    addToClassHierarchy(hierarchy.size(), Enum.class, array, hierarchy, visited);
    addToClassHierarchy(hierarchy.size(), Enum.class, false, hierarchy, visited);
    addInterfacesToClassHierarchy(Enum.class, array, hierarchy, visited);
}
  • 对枚举这个顶级类也加入hierarchyvisited俩个集合(addToClassHierarchy内部有判重处理,所以这里连续调用俩次并不影响)
addToClassHierarchy(hierarchy.size(), Object.class, array, hierarchy, visited);
addToClassHierarchy(hierarchy.size(), Object.class, false, hierarchy, visited);
  • Object这个顶级类也加入hierarchyvisited俩个集合

1.2.9 GenericConversionService#getRegisteredConverter

        @Nullable
        private GenericConverter getRegisteredConverter(TypeDescriptor sourceType,
                TypeDescriptor targetType, ConvertiblePair convertiblePair) {

            // Check specifically registered converters
            ConvertersForPair convertersForPair = this.converters.get(convertiblePair);
            if (convertersForPair != null) {
                GenericConverter converter = convertersForPair.getConverter(sourceType, targetType);
                if (converter != null) {
                    return converter;
                }
            }
            // Check ConditionalConverters for a dynamic match
            for (GenericConverter globalConverter : this.globalConverters) {
                if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) {
                    return globalConverter;
                }
            }
            return null;
        }

convertersglobalConverters俩个集合中查找到对应的转换器

问题来了:这俩个集合的元素是什么时候添加进去的呢?

回过头看demo中的spring.xml

    
        
            
                
            
        
    

可以看到,在ConversionServiceFactoryBean中,我们为其属性converters设置了我们自定义的转换器studentConverter,而ConversionServiceFactoryBean实现了InitializingBean接口(《Spring源码解析(十一)-初始化bean》)的afterPropertiesSet方法:

    @Override
    public void afterPropertiesSet() {
        this.conversionService = createConversionService();
        ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
    }

可以看到通过registerConverters方法注册了转换器:

    public static void registerConverters(@Nullable Set converters, ConverterRegistry registry) {
        if (converters != null) {
            for (Object converter : converters) {
                if (converter instanceof GenericConverter) {
                    registry.addConverter((GenericConverter) converter);
                }
                else if (converter instanceof Converter) {
                    registry.addConverter((Converter) converter);
                }
                else if (converter instanceof ConverterFactory) {
                    registry.addConverterFactory((ConverterFactory) converter);
                }
                else {
                    throw new IllegalArgumentException("Each converter object must implement one of the " +
                            "Converter, ConverterFactory, or GenericConverter interfaces");
                }
            }
        }
    }

在其实现中,又往registry添加了转换器:

    @Override
    public void addConverter(GenericConverter converter) {
        this.converters.add(converter);
        invalidateCache();
    }

查看add方法:

        public void add(GenericConverter converter) {
            Set convertibleTypes = converter.getConvertibleTypes();
            if (convertibleTypes == null) {
                Assert.state(converter instanceof ConditionalConverter,
                        "Only conditional converters may return null convertible types");
                this.globalConverters.add(converter);
            }
            else {
                for (ConvertiblePair convertiblePair : convertibleTypes) {
                    ConvertersForPair convertersForPair = getMatchableConverters(convertiblePair);
                    convertersForPair.add(converter);
                }
            }
        }
        private ConvertersForPair getMatchableConverters(ConvertiblePair convertiblePair) {
            return this.converters.computeIfAbsent(convertiblePair, k -> new ConvertersForPair());
        }

可以看到,往我们之前查找转换器的俩个集合convertersglobalConverters添加了元素

到这里,我们仅是将ConversionServicecanConvert解析完毕,接下来回过头看看真正完成解析功能的convert接口

1.2.10 GenericConversionService#convert

    public  T convert(@Nullable Object source, Class targetType) {
        Assert.notNull(targetType, "Target type to convert to cannot be null");
        return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
    }

    @Override
    @Nullable
    public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
        Assert.notNull(targetType, "Target type to convert to cannot be null");
        // sourceType为空,限制source也必须为空,并对null进行处理
        if (sourceType == null) {
            Assert.isTrue(source == null, "Source must be [null] if source type == [null]");
            return handleResult(null, targetType, convertNullSource(null, targetType));
        }
        // source和sourceType不匹配
        if (source != null && !sourceType.getObjectType().isInstance(source)) {
            throw new IllegalArgumentException("Source to convert from must be an instance of [" +
                    sourceType + "]; instead it was a [" + source.getClass().getName() + "]");
        }
        GenericConverter converter = getConverter(sourceType, targetType);
        if (converter != null) {
            // 进行转换
            Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
            // 处理结果
            return handleResult(sourceType, targetType, result);
        }
        // 处理没查找到转化器的结果
        return handleConverterNotFound(source, sourceType, targetType);
    }

调用重载方法之后,进行了以下几步的处理:

  • 如果sourceType为空,调用handleResult进一步判断结果并返回
  • 如果source不为空,但source不是sourceType的实例,那么抛出异常
  • 通过getConverter获取转换器,应用转换器的convert方法进行转换,对转换结果调用handleResult处理并返回
  • 对没有查找转换器的结果进行处理

1.2.11 GenericConversionService#handleResult

    @Nullable
    private Object handleResult(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType, @Nullable Object result) {
        // 如果targetType是基本类型,而结果为null,此时转化失败,抛出异常
        if (result == null) {
            assertNotPrimitiveTargetType(sourceType, targetType);
        }
        return result;
    }

    private void assertNotPrimitiveTargetType(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
        if (targetType.isPrimitive()) {
            throw new ConversionFailedException(sourceType, targetType, null,
                    new IllegalArgumentException("A null value cannot be assigned to a primitive type"));
        }
    }

handleResult的逻辑其实就是如果转换结果为null,但是targetType是基本类型,那么抛出异常,因为基本类型是不能转换成null

1.2.12 ConversionUtils#invokeConverter

    @Nullable
    public static Object invokeConverter(GenericConverter converter, @Nullable Object source,
            TypeDescriptor sourceType, TypeDescriptor targetType) {

        try {
            return converter.convert(source, sourceType, targetType);
        }
        catch (ConversionFailedException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new ConversionFailedException(sourceType, targetType, source, ex);
        }
    }

交由converterconvert方法完成转换,对demo进行debug,通过调用栈可以发现使用的是GenericConversionService的内部类ConverterAdapterconvert方法实现:

        @Override
        @Nullable
        public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
            if (source == null) {
                return convertNullSource(sourceType, targetType);
            }
            return this.converter.convert(source);
        }

而这里的convert方法具体实现,便是demo中自定义的convert方法

2 ConverterFactory

Converter实现的是一种类型到另一种类型到转换,但有些场景下,可能需要从一种类型转换成多种类型,这多种类型继承或实现自同一个父类,如果使用Converter一个个去转换,显然不可取。对于这种情况,spring提供了ConverterFactory,其定义如下:

public interface ConverterFactory {

    /**
     * Get the converter to convert from S to target type T, where T is also an instance of R.
     * @param  the target type
     * @param targetType the target type to convert to
     * @return a converter from S to T
     */
     Converter getConverter(Class targetType);

}

可以看到,ConverterFactory支持从S类型转换为T类型,而T类型是R类型的子类,实现了“一对多”的类型转换。

2.1 DEMO

@Component
public class StringToEnumConvertFactory implements ConverterFactory {
    @Override
    public  Converter getConverter(Class targetType) {
        return new StringToEnum<>(targetType);
    }

    private class StringToEnum implements Converter {

        private Class enumType;

        StringToEnum(Class enumType) {
            this.enumType = enumType;
        }

        @Override
        public T convert(String source) {
            if (source.length() == 0) {
                return null;
            }
            return Enum.valueOf(enumType, source.trim());
        }
    }
}

3 ConditionalConverter

public interface ConditionalConverter {

    /**
     * Should the conversion from {@code sourceType} to {@code targetType} currently under
     * consideration be selected?
     * @param sourceType the type descriptor of the field we are converting from
     * @param targetType the type descriptor of the field we are converting to
     * @return true if conversion should be performed, false otherwise
     */
    boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);

}

public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {

}

在源类型与目标类型已经匹配的基础上再进行判断是否支持转换

3.1 DEMO

final class StringToArrayConverter implements ConditionalGenericConverter {

    private final ConversionService conversionService;


    public StringToArrayConverter(ConversionService conversionService) {
        this.conversionService = conversionService;
    }


    @Override
    public Set getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(String.class, Object[].class));
    }

    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        return ConversionUtils.canConvertElements(sourceType, targetType.getElementTypeDescriptor(),
                this.conversionService);
    }

    @Override
    @Nullable
    public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        if (source == null) {
            return null;
        }
        String string = (String) source;
        String[] fields = StringUtils.commaDelimitedListToStringArray(string);
        TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
        Assert.state(targetElementType != null, "No target element type");
        Object target = Array.newInstance(targetElementType.getType(), fields.length);
        for (int i = 0; i < fields.length; i++) {
            String sourceElement = fields[i];
            Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetElementType);
            Array.set(target, i, targetElement);
        }
        return target;
    }

}

4 GenericConverter

public interface GenericConverter {

    /**
     * Return the source and target types that this converter can convert between.
     * 

Each entry is a convertible source-to-target type pair. *

For {@link ConditionalConverter conditional converters} this method may return * {@code null} to indicate all source-to-target pairs should be considered. */ @Nullable Set getConvertibleTypes(); /** * Convert the source object to the targetType described by the {@code TypeDescriptor}. * @param source the source object to convert (may be {@code null}) * @param sourceType the type descriptor of the field we are converting from * @param targetType the type descriptor of the field we are converting to * @return the converted object */ @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType); /** * Holder for a source-to-target class pair. */ final class ConvertiblePair { private final Class sourceType; private final Class targetType; /** * Create a new source-to-target pair. * @param sourceType the source type * @param targetType the target type */ public ConvertiblePair(Class sourceType, Class targetType) { Assert.notNull(sourceType, "Source type must not be null"); Assert.notNull(targetType, "Target type must not be null"); this.sourceType = sourceType; this.targetType = targetType; } public Class getSourceType() { return this.sourceType; } public Class getTargetType() { return this.targetType; } @Override public boolean equals(@Nullable Object other) { if (this == other) { return true; } if (other == null || other.getClass() != ConvertiblePair.class) { return false; } ConvertiblePair otherPair = (ConvertiblePair) other; return (this.sourceType == otherPair.sourceType && this.targetType == otherPair.targetType); } @Override public int hashCode() { return (this.sourceType.hashCode() * 31 + this.targetType.hashCode()); } @Override public String toString() { return (this.sourceType.getName() + " -> " + this.targetType.getName()); } } }

GenericConverter是底层的实现,ConverterConverterFactoryConditionalConverter都是在它的基础上的封装,spring建议使用这三者来实现功能而并非直接使用GenericConverter

5 总结

本篇主要围绕spring提供的几种转换器进行了源码解析与demo演示,初步了解并熟悉了spring这一套转换体系。除了spring提供的转化器之外, com.google.common.base.Convert类也提供了相应的功能,并且支持正逆向转换:

public abstract class Converter implements Function {
    protected abstract B doForward(A a);
    protected abstract A doBackward(B b);
    //其他略
}

日常编码中学会使用转换器,让代码看起来简洁、易懂,是一种值得学习的编程习惯。

你可能感兴趣的:(Spring源码解析(十九)-转换体系)