SpringMVC 之类型转换Converter 源代码分析

  • 最近研究SpringMVC的类型转换器,在以往我们需要 SpringMVC 为我们自动进行类型转换的时候都是用的PropertyEditor 。通过 PropertyEditor 的 setAsText() 方法我们可以实现字符串向特定类型的转换。但是这里有一个限制是它只支持从 String 类型转为其他类型。在Spring3中 引入了Converter<S, T>接口, 它支持从一个 Object 转为另一个 Object 。除了 Converter接口之外,实现 ConverterFactory 接口和 GenericConverter 接口也可以实现我们自己的类型转换逻辑。
  • 我们先来看一下Converter<S, T>接口的定义
  • public interface Converter<S, T> {T convert(S source);}

  • S为源对象 T为目标对象 实现该接口即可实现我们的类型转换,我们写一个最为常见的时间类型转换器
  •  1 public class StringToDateConvert implements Converter<String, Date> {
     2
     3     private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
     4
     5     @Override
     6     public Date convert(String source) {
     7         if(source.length() == 0) {
     8             return null;
     9         }
    10         try {
    11             return format.parse(source);
    12         } catch (ParseException e) {
    13             throw new RuntimeException(source + "类型转换失败");
    14         }
    15     }
    16
    17 }

  • 在定义好 Converter 之后,就是使用 Converter 了。为了统一调用 Converter 进行类型转换, Spring 为我们提供了一个 ConversionService 接口。通过实现这个接口我们可以实现自己的 Converter 调用逻辑。我们先来看一下 ConversionService 接口的定义:
  • public interface ConversionService {
    boolean canConvert(Class<?> sourceType, Class<?> targetType);boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
    <T> T convert(Object source, Class<T> targetType);Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
    }

    我们可以看到 ConversionService 接口里面定义了两个 canConvert 方法和两个convert 方法, canConvert 方法用于判断当前的 ConversionService 是否能够对原类型和目标类型进行转换, convert 方法则是用于进行类型转换的。上面出现的参数类型TypeDescriptor 是对于一种类型的封装,里面包含该种类型的值、实际类型等等信息。

  • 一般而言我们在实现 ConversionService 接口的时候也会实现 ConverterRegistry 接口。使用 ConverterRegistry 可以使我们对类型转换器做一个统一的注册。ConverterRegistry 接口的定义如下:
  • public interface ConverterRegistry {void addConverter(Converter<?, ?> converter);void addConverter(GenericConverter converter);void addConverterFactory(ConverterFactory<?, ?> converterFactory);void removeConvertible(Class<?> sourceType, Class<?> targetType);}

    有了这俩个接口以后我们就可以发挥我们自己的设计能力实现里面的逻辑了。不过Spring已经为我们提供了一个实现,这个类就是GenericConversionService

  • 首先我们看一下这个类的定义
  • public class GenericConversionService implements ConfigurableConversionService {}

  • 可以看到 GenericConversionService 继承至ConfigurableConversionService 接口,那ConfigurableConversionService 又是什么呢,我们在看源码
  • public interface ConfigurableConversionService extends ConversionService, ConverterRegistry {}

    呵呵 这回清楚了吧,GenericConversionService 就是实现了ConversionService接口与ConverterRegistry接口。完成了我们类型转换器的注册 与 转换逻辑,下面我们将通过源代码来详细分析该实现的逻辑。

  • 在分析源代码之前,让我们在看另外俩个转换器,也就是上面提到的 ConverterFactory 接口和 GenericConverter
  • ConverterFactory接口的定义
  • public interface ConverterFactory<S, R> {<T extends R> Converter<S, T> getConverter(Class<T> targetType);}

    我们可以看到 ConverterFactory 接口里面就定义了一个产生 Converter 的getConverter 方法,参数是目标类型的 class 。我们可以看到 ConverterFactory 中一共用到了三个泛型, S 、 R 、 T ,其中 S 表示原类型, R 表示目标类型, T 是类型 R 的一个子类。

  • 考虑这样一种情况,我们有一个表示用户状态的枚举类型 UserStatus ,如果要定义一个从 String 转为 UserStatus 的 Converter ,根据之前 Converter 接口的说明,我们的StringToUserStatus 大概是这个样子:

  • public class StringToUserStatus implements Converter<String, UserStatus> {@Overridepublic UserStatus convert(String source) {if (source == null) {return null;}return UserStatus.valueOf(source);}}

    如果这个时候有另外一个枚举类型 UserType ,那么我们就需要定义另外一个从String 转为 UserType 的 Converter —— StringToUserType ,那么我们的StringToUserType 大概是这个样子:

  • public class StringToUserType implements Converter<String, UserType> {@Overridepublic UserType convert(String source) {if (source == null) {return null;}return UserType.valueOf(source);}}

    如果还有其他枚举类型需要定义原类型为 String 的 Converter 的时候,我们还得像上面那样定义对应的 Converter 。有了 ConverterFactory 之后,这一切都变得非常简单,因为 UserStatus 、 UserType 等其他枚举类型同属于枚举,所以这个时候我们就可以统一定义一个从 String 到 Enum 的 ConverterFactory ,然后从中获取对应的Converter 进行 convert 操作。 Spring 官方已经为我们实现了这么一个StringToEnumConverterFactory :

  •  1 @SuppressWarnings("unchecked")
     2 final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
     3
     4     public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
     5        return new StringToEnum(targetType);
     6     }
     7
     8     private class StringToEnum<T extends Enum> implements Converter<String, T> {
     9
    10        private final Class<T> enumType;
    11
    12        public StringToEnum(Class<T> enumType) {
    13            this.enumType = enumType;
    14        }
    15
    16        public T convert(String source) {
    17            if (source.length() == 0) {
    18               // It's an empty enum identifier: reset the enum value to null.
    19               return null;
    20            }
    21            return (T) Enum.valueOf(this.enumType, source.trim());
    22        }
    23     }
    24
    25 }

    这样,如果是要进行 String 到 UserStatus 的转换,我们就可以通过StringToEnumConverterFactory 实例的 getConverter(UserStatus.class).convert(string)获取到对应的 UserStatus ,如果是要转换为 UserType 的话就是getConverter(UserType.class).convert(string) 。这样就非常方便,可以很好的支持扩展。

  • 看GenericConverter 接口的定义
  • GenericConverter 接口是所有的 Converter 接口中最灵活也是最复杂的一个类型转换接口。像我们之前介绍的 Converter 接口只支持从一个原类型转换为一个目标类型;ConverterFactory 接口只支持从一个原类型转换为一个目标类型对应的子类型;而GenericConverter 接口支持在多个不同的原类型和目标类型之间进行转换,这也就是GenericConverter 接口灵活和复杂的地方。
  • 我们先来看一下 GenericConverter 接口的定义:
  •  1 public interface GenericConverter {
     2
     3     Set<ConvertiblePair> getConvertibleTypes();
     4
     5     Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
     6
     7     public static final class ConvertiblePair {
     8
     9        private final Class<?> sourceType;
    10
    11        private final Class<?> targetType;
    12
    13        public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {
    14            Assert.notNull(sourceType, "Source type must not be null");
    15            Assert.notNull(targetType, "Target type must not be null");
    16            this.sourceType = sourceType;
    17            this.targetType = targetType;
    18        }
    19
    20        public Class<?> getSourceType() {
    21            return this.sourceType;
    22        }
    23
    24        public Class<?> getTargetType() {
    25            return this.targetType;
    26        }
    27     }
    28
    29 }

    我们可以看到 GenericConverter 接口中一共定义了两个方法,getConvertibleTypes() 和 convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) 。 getConvertibleTypes 方法用于返回这个GenericConverter 能够转换的原类型和目标类型的这么一个组合; convert 方法则是用于进行类型转换的,我们可以在这个方法里面实现我们自己的转换逻辑。之所以说GenericConverter 是最复杂的是因为它的转换方法 convert 的参数类型 TypeDescriptor是比较复杂的。 TypeDescriptor 对类型 Type 进行了一些封装,包括 value 、 Field 及其对应的真实类型等等,具体的可以查看 API 。

有了上面的基础以后就让我们一起来分析一下Spring为我们提供的GenericConversionService这个类

/*** Spring GenericConversionService 类型转换器核心源代码分析*/
public class GenericConversionService implements ConfigurableConversionService {//这个转换器在没有找到对应转化器 并且 源类型与目标类型是同一种类型时使用private static final GenericConverter NO_OP_CONVERTER = new GenericConverter() {public Set<ConvertiblePair> getConvertibleTypes() {return null;}public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {//可以看到这里并没有做处理,直接将原类型返回return source;}public String toString() {return "NO_OP";}};//这个转换器在没有找到对应转化器 并且 源类型与目标类型不是同一种类型时使用。将抛出异常private static final GenericConverter NO_MATCH = new GenericConverter() {public Set<ConvertiblePair> getConvertibleTypes() {throw new UnsupportedOperationException();}public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {throw new UnsupportedOperationException();}public String toString() {return "NO_MATCH";}};// converters存放系统所有的类型转换器// 其结构为 key = sourceType ; value = Map<Class<?>, MatchableConverters>;// 至于MatchableConverters是什么 在后面会讲到// 整个converters的数据接口大概是这样的/*** 一个原类型对应一个Map<targetType<?>, MatchableConverters>数据结构* converters *         [key: String value = Map<targetType<?>, MatchableConverters>]*         [key: sourceType1 value = Map<targetType<?>, MatchableConverters>]*         [key: sourceType2 value = Map<targetType<?>, MatchableConverters>]* * * * 一个Map<targetType<?>, MatchableConverters>数据结构包含每种目标类型对应的转换器* Map<targetType<?>, MatchableConverters>*         [key:int value=MatchableConverters]*         [key:targetType1 value=MatchableConverters(1)]*         [key:targetType2 value=MatchableConverters(2)]* */private final Map<Class<?>, Map<Class<?>, MatchableConverters>> converters =new HashMap<Class<?>, Map<Class<?>, MatchableConverters>>(36);// 转换器缓存// 系统在对某个类型第一次做转换的时候会先去查找匹配的转换器,找到以后会放到这个数据结构之中 提高效率private final Map<ConverterCacheKey, GenericConverter> converterCache =new ConcurrentHashMap<ConverterCacheKey, GenericConverter>();//注册类型转换器 Converter接口 这个接口就是像我们上面例子里提到的StringToDateConvertpublic void addConverter(Converter<?, ?> converter) {//首先根据converter的实例 获取原类型(sourceType) 与 目标类型(targetType)的对象//关于GenericConverter.ConvertiblePair类 就是对 原类型与目标类型的一种封装GenericConverter.ConvertiblePair typeInfo = getRequiredTypeInfo(converter, Converter.class);if (typeInfo == null) {throw new IllegalArgumentException("Unable to the determine sourceType <S> and targetType <T> which " +"your Converter<S, T> converts between; declare these generic types.");}//注册转换器//关于ConverterAdapter的解释 在该类上面有详细的解释addConverter(new ConverterAdapter(typeInfo, converter));}public void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter) {GenericConverter.ConvertiblePair typeInfo = new GenericConverter.ConvertiblePair(sourceType, targetType);addConverter(new ConverterAdapter(typeInfo, converter));}//最终所有的转换器 ConverterFactory,Converter,ConditionalGenericConverter 都会被转换为GenericConverter//对象进行注册 也就是说 GenericConversionService类里的转换器 最终都被包装为GenericConverter对象public void addConverter(GenericConverter converter) {//拿到GenericConverter所支持的转换类型(GenericConverter.ConvertiblePair)的集合Set<GenericConverter.ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();//循环拿出没一种 转换类型组合进行注册for (GenericConverter.ConvertiblePair convertibleType : convertibleTypes) {//将converter对象添加到MatchableConverters对象当中去
            getMatchableConverters(convertibleType.getSourceType(), convertibleType.getTargetType()).add(converter);}invalidateCache();}//注册实现ConverterFactory<?, ?>接口的转换器//该方法还是将ConverterFactory的实现类包装为GenericConverter对象public void addConverterFactory(ConverterFactory<?, ?> converterFactory) {GenericConverter.ConvertiblePair typeInfo = getRequiredTypeInfo(converterFactory, ConverterFactory.class);if (typeInfo == null) {throw new IllegalArgumentException("Unable to the determine sourceType <S> and targetRangeType R which " +"your ConverterFactory<S, R> converts between; declare these generic types.");}addConverter(new ConverterFactoryAdapter(typeInfo, converterFactory));}//移除某种类型的转换器public void removeConvertible(Class<?> sourceType, Class<?> targetType) {getSourceConverterMap(sourceType).remove(targetType);invalidateCache();}//判断是否能够转换public boolean canConvert(Class<?> sourceType, Class<?> targetType) {if (targetType == null) {throw new IllegalArgumentException("The targetType to convert to cannot be null");}        return canConvert(sourceType != null ? TypeDescriptor.valueOf(sourceType) : null, TypeDescriptor.valueOf(targetType));}//判断是否能够转换public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {if (targetType == null) {throw new IllegalArgumentException("The targetType to convert to cannot be null");}if (sourceType == null) {return true;}GenericConverter converter = getConverter(sourceType, targetType);return (converter != null);}@SuppressWarnings("unchecked")public <T> T convert(Object source, Class<T> targetType) {if (targetType == null) {throw new IllegalArgumentException("The targetType to convert to cannot be null");}        return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));}public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {if (targetType == null) {throw new IllegalArgumentException("The targetType to convert to cannot be null");}if (sourceType == null) {Assert.isTrue(source == null, "The source must be [null] if sourceType == [null]");return handleResult(sourceType, targetType, convertNullSource(sourceType, targetType));}if (source != null && !sourceType.getObjectType().isInstance(source)) {throw new IllegalArgumentException("The 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);}else {return handleConverterNotFound(source, sourceType, targetType);            }}/*** Convenience operation for converting a source object to the specified targetType, where the targetType is a descriptor that provides additional conversion context.* Simply delegates to {@link #convert(Object, TypeDescriptor, TypeDescriptor)} and encapsulates the construction of the sourceType descriptor using {@link TypeDescriptor#forObject(Object)}.* @param source the source object* @param targetType the target type* @return the converted value* @throws ConversionException if a conversion exception occurred* @throws IllegalArgumentException if targetType is null* @throws IllegalArgumentException if sourceType is null but source is not null*/public Object convert(Object source, TypeDescriptor targetType) {return convert(source, TypeDescriptor.forObject(source), targetType);}public String toString() {List<String> converterStrings = new ArrayList<String>();for (Map<Class<?>, MatchableConverters> targetConverters : this.converters.values()) {for (MatchableConverters matchable : targetConverters.values()) {converterStrings.add(matchable.toString());}}Collections.sort(converterStrings);StringBuilder builder = new StringBuilder();builder.append("ConversionService converters = ").append("\n");for (String converterString : converterStrings) {builder.append("\t");builder.append(converterString);builder.append("\n");            }return builder.toString();}// subclassing hooks/*** Template method to convert a null source.* <p>Default implementation returns <code>null</code>.* Subclasses may override to return custom null objects for specific target types.* @param sourceType the sourceType to convert from* @param targetType the targetType to convert to* @return the converted null object*/protected Object convertNullSource(TypeDescriptor sourceType, TypeDescriptor targetType) {return null;}/*** Hook method to lookup the converter for a given sourceType/targetType pair.* First queries this ConversionService's converter cache.* On a cache miss, then performs an exhaustive search for a matching converter.* If no converter matches, returns the default converter.* Subclasses may override.* @param sourceType the source type to convert from* @param targetType the target type to convert to* @return the generic converter that will perform the conversion, or <code>null</code> if no suitable converter was found* @see #getDefaultConverter(TypeDescriptor, TypeDescriptor)*/protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);GenericConverter converter = this.converterCache.get(key);if (converter != null) {return (converter != NO_MATCH ? converter : null);}else {converter = findConverterForClassPair(sourceType, targetType);if (converter == null) {converter = getDefaultConverter(sourceType, targetType);                }if (converter != null) {this.converterCache.put(key, converter);return converter;}else {this.converterCache.put(key, NO_MATCH);return null;}}}/*** Return the default converter if no converter is found for the given sourceType/targetType pair.* Returns a NO_OP Converter if the sourceType is assignable to the targetType.* Returns <code>null</code> otherwise, indicating no suitable converter could be found.* Subclasses may override.* @param sourceType the source type to convert from* @param targetType the target type to convert to* @return the default generic converter that will perform the conversion*/protected GenericConverter getDefaultConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {return (sourceType.isAssignableTo(targetType) ? NO_OP_CONVERTER : null);}//通过反射的到Converter<S, T>接口的 S与T 封装成GenericConverter.ConvertiblePair对象返回private GenericConverter.ConvertiblePair getRequiredTypeInfo(Object converter, Class<?> genericIfc) {Class<?>[] args = GenericTypeResolver.resolveTypeArguments(converter.getClass(), genericIfc);return (args != null ? new GenericConverter.ConvertiblePair(args[0], args[1]) : null);}private MatchableConverters getMatchableConverters(Class<?> sourceType, Class<?> targetType) {//通过sourceType(原类型)在converters当中获取Map<Class<?>, MatchableConverters>对象Map<Class<?>, MatchableConverters> sourceMap = getSourceConverterMap(sourceType);//在Map<Class<?>, MatchableConverters>对象当中根据targetType(目标类型)获取MatchableConverters对象MatchableConverters matchable = sourceMap.get(targetType);if (matchable == null) {matchable = new MatchableConverters();sourceMap.put(targetType, matchable);}return matchable;}private void invalidateCache() {this.converterCache.clear();}//通过sourceType(原类型)在converters当中获取Map<Class<?>, MatchableConverters>private Map<Class<?>, MatchableConverters> getSourceConverterMap(Class<?> sourceType) {Map<Class<?>, MatchableConverters> sourceMap = converters.get(sourceType);//为null就创建一个if (sourceMap == null) {sourceMap = new HashMap<Class<?>, MatchableConverters>();this.converters.put(sourceType, sourceMap);}return sourceMap;}private GenericConverter findConverterForClassPair(TypeDescriptor sourceType, TypeDescriptor targetType) {Class<?> sourceObjectType = sourceType.getObjectType();if (sourceObjectType.isInterface()) {LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>();classQueue.addFirst(sourceObjectType);while (!classQueue.isEmpty()) {Class<?> currentClass = classQueue.removeLast();Map<Class<?>, MatchableConverters> converters = getTargetConvertersForSource(currentClass);GenericConverter converter = getMatchingConverterForTarget(sourceType, targetType, converters);if (converter != null) {return converter;}Class<?>[] interfaces = currentClass.getInterfaces();for (Class<?> ifc : interfaces) {classQueue.addFirst(ifc);}}Map<Class<?>, MatchableConverters> objectConverters = getTargetConvertersForSource(Object.class);return getMatchingConverterForTarget(sourceType, targetType, objectConverters);}else if (sourceObjectType.isArray()) {LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>();classQueue.addFirst(sourceObjectType);while (!classQueue.isEmpty()) {Class<?> currentClass = classQueue.removeLast();Map<Class<?>, MatchableConverters> converters = getTargetConvertersForSource(currentClass);GenericConverter converter = getMatchingConverterForTarget(sourceType, targetType, converters);if (converter != null) {return converter;}Class<?> componentType = ClassUtils.resolvePrimitiveIfNecessary(currentClass.getComponentType());if (componentType.getSuperclass() != null) {classQueue.addFirst(Array.newInstance(componentType.getSuperclass(), 0).getClass());}else if (componentType.isInterface()) {classQueue.addFirst(Object[].class);}}return null;}else {HashSet<Class<?>> interfaces = new LinkedHashSet<Class<?>>();LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>();classQueue.addFirst(sourceObjectType);while (!classQueue.isEmpty()) {Class<?> currentClass = classQueue.removeLast();Map<Class<?>, MatchableConverters> converters = getTargetConvertersForSource(currentClass);GenericConverter converter = getMatchingConverterForTarget(sourceType, targetType, converters);if (converter != null) {return converter;}Class<?> superClass = currentClass.getSuperclass();if (superClass != null && superClass != Object.class) {classQueue.addFirst(superClass);}for (Class<?> interfaceType : currentClass.getInterfaces()) {addInterfaceHierarchy(interfaceType, interfaces);}}for (Class<?> interfaceType : interfaces) {Map<Class<?>, MatchableConverters> converters = getTargetConvertersForSource(interfaceType);GenericConverter converter = getMatchingConverterForTarget(sourceType, targetType, converters);if (converter != null) {return converter;}}Map<Class<?>, MatchableConverters> objectConverters = getTargetConvertersForSource(Object.class);return getMatchingConverterForTarget(sourceType, targetType, objectConverters);                }}private Map<Class<?>, MatchableConverters> getTargetConvertersForSource(Class<?> sourceType) {Map<Class<?>, MatchableConverters> converters = this.converters.get(sourceType);if (converters == null) {converters = Collections.emptyMap();}return converters;}private GenericConverter getMatchingConverterForTarget(TypeDescriptor sourceType, TypeDescriptor targetType,Map<Class<?>, MatchableConverters> converters) {Class<?> targetObjectType = targetType.getObjectType();if (targetObjectType.isInterface()) {LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>();classQueue.addFirst(targetObjectType);while (!classQueue.isEmpty()) {Class<?> currentClass = classQueue.removeLast();MatchableConverters matchable = converters.get(currentClass);GenericConverter converter = matchConverter(matchable, sourceType, targetType);if (converter != null) {return converter;}Class<?>[] interfaces = currentClass.getInterfaces();for (Class<?> ifc : interfaces) {classQueue.addFirst(ifc);}}return matchConverter(converters.get(Object.class), sourceType, targetType);}else if (targetObjectType.isArray()) {LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>();classQueue.addFirst(targetObjectType);while (!classQueue.isEmpty()) {Class<?> currentClass = classQueue.removeLast();MatchableConverters matchable = converters.get(currentClass);GenericConverter converter = matchConverter(matchable, sourceType, targetType);if (converter != null) {return converter;}Class<?> componentType = ClassUtils.resolvePrimitiveIfNecessary(currentClass.getComponentType());if (componentType.getSuperclass() != null) {classQueue.addFirst(Array.newInstance(componentType.getSuperclass(), 0).getClass());}else if (componentType.isInterface()) {classQueue.addFirst(Object[].class);}}return null;}else {Set<Class<?>> interfaces = new LinkedHashSet<Class<?>>();LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>();classQueue.addFirst(targetObjectType);while (!classQueue.isEmpty()) {Class<?> currentClass = classQueue.removeLast();MatchableConverters matchable = converters.get(currentClass);GenericConverter converter = matchConverter(matchable, sourceType, targetType);if (converter != null) {return converter;}Class<?> superClass = currentClass.getSuperclass();if (superClass != null && superClass != Object.class) {classQueue.addFirst(superClass);}for (Class<?> interfaceType : currentClass.getInterfaces()) {addInterfaceHierarchy(interfaceType, interfaces);}}for (Class<?> interfaceType : interfaces) {MatchableConverters matchable = converters.get(interfaceType);GenericConverter converter = matchConverter(matchable, sourceType, targetType);if (converter != null) {return converter;}}return matchConverter(converters.get(Object.class), sourceType, targetType);}}private void addInterfaceHierarchy(Class<?> interfaceType, Set<Class<?>> interfaces) {interfaces.add(interfaceType);for (Class<?> inheritedInterface : interfaceType.getInterfaces()) {addInterfaceHierarchy(inheritedInterface, interfaces);}}private GenericConverter matchConverter(MatchableConverters matchable, TypeDescriptor sourceFieldType, TypeDescriptor targetFieldType) {if (matchable == null) {return null;}return matchable.matchConverter(sourceFieldType, targetFieldType);}private Object handleConverterNotFound(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {if (source == null) {assertNotPrimitiveTargetType(sourceType, targetType);return source;}else if (sourceType.isAssignableTo(targetType) && targetType.getObjectType().isInstance(source)) {return source;}else {throw new ConverterNotFoundException(sourceType, targetType);}        }private Object handleResult(TypeDescriptor sourceType, TypeDescriptor targetType, Object result) {if (result == null) {assertNotPrimitiveTargetType(sourceType, targetType);}return result;}private void assertNotPrimitiveTargetType(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"));}        }//包装我们的Converter类 将我们的Converter类的实例 包装成为GenericConverter对象 以便统一注册@SuppressWarnings("unchecked")private final class ConverterAdapter implements GenericConverter {//原类型(sourceType) 与 目标类型(targetType)private final ConvertiblePair typeInfo;//我们实现Converter<S,T>接口的转换器private final Converter<Object, Object> converter;//构造函数public ConverterAdapter(ConvertiblePair typeInfo, Converter<?, ?> converter) {this.converter = (Converter<Object, Object>) converter;this.typeInfo = typeInfo;}//返回一个Set 里面包含了当前ConverterAdapter对象能够转换的类型信息public Set<ConvertiblePair> getConvertibleTypes() {return Collections.singleton(this.typeInfo);}public boolean matchesTargetType(TypeDescriptor targetType) {return this.typeInfo.getTargetType().equals(targetType.getObjectType());}//具体转换逻辑public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {if (source == null) {return convertNullSource(sourceType, targetType);}//拿到实现Converter<S,T>接口的转换器进行转换return this.converter.convert(source);}public String toString() {return this.typeInfo.getSourceType().getName() + " -> " + this.typeInfo.getTargetType().getName() +" : " + this.converter.toString();}}//包装我们的Converter类 将我们的ConverterFactory类的实例 包装成为GenericConverter对象 以便统一注册@SuppressWarnings("unchecked")private final class ConverterFactoryAdapter implements GenericConverter {//原类型(sourceType) 与 目标类型(targetType)private final ConvertiblePair typeInfo;//实现了ConverterFactory接口的类对象private final ConverterFactory<Object, Object> converterFactory;public ConverterFactoryAdapter(ConvertiblePair typeInfo, ConverterFactory<?, ?> converterFactory) {this.converterFactory = (ConverterFactory<Object, Object>) converterFactory;this.typeInfo = typeInfo;}//返回一个Set 里面包含了当前ConverterAdapter对象能够转换的类型信息public Set<ConvertiblePair> getConvertibleTypes() {return Collections.singleton(this.typeInfo);}//转换逻辑public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {if (source == null) {return convertNullSource(sourceType, targetType);}//通过ConverterFactory的getConverter拿到转换器对象在进行转换return this.converterFactory.getConverter(targetType.getObjectType()).convert(source);}public String toString() {return this.typeInfo.getSourceType().getName() + " -> " + this.typeInfo.getTargetType().getName() +" : " + this.converterFactory.toString();}}private static class MatchableConverters {//支持条件的转换器private LinkedList<ConditionalGenericConverter> conditionalConverters;//默认转换器private GenericConverter defaultConverter;public void add(GenericConverter converter) {if (converter instanceof ConditionalGenericConverter) {if (this.conditionalConverters == null) {this.conditionalConverters = new LinkedList<ConditionalGenericConverter>();}this.conditionalConverters.addFirst((ConditionalGenericConverter) converter);}else {this.defaultConverter = converter;}}//匹配转换器public GenericConverter matchConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {//如果conditionalConverters转换器不为空 那么优先查找if (this.conditionalConverters != null) {for (ConditionalGenericConverter conditional : this.conditionalConverters) {//通过matches方法进行匹配 如果匹配到了则返回该转换器if (conditional.matches(sourceType, targetType)) {return conditional;}}}//判断是不是ConverterAdapter 如果是这调用matchesTargetType方法看是否能够转换if (this.defaultConverter instanceof ConverterAdapter) {ConverterAdapter adapter = (ConverterAdapter) this.defaultConverter;if (!adapter.matchesTargetType(targetType)) {return null;}}//返回转换器return this.defaultConverter;}public String toString() {if (this.conditionalConverters != null) {StringBuilder builder = new StringBuilder();for (Iterator<ConditionalGenericConverter> it = this.conditionalConverters.iterator(); it.hasNext();) {builder.append(it.next());if (it.hasNext()) {builder.append(", ");}}if (this.defaultConverter != null) {builder.append(", ").append(this.defaultConverter);}return builder.toString();}else {return this.defaultConverter.toString();}}}private static final class ConverterCacheKey {private final TypeDescriptor sourceType;private final TypeDescriptor targetType;public ConverterCacheKey(TypeDescriptor sourceType, TypeDescriptor targetType) {this.sourceType = sourceType;this.targetType = targetType;}public boolean equals(Object other) {if (this == other) {return true;}if (!(other instanceof ConverterCacheKey)) {return false;}ConverterCacheKey otherKey = (ConverterCacheKey) other;return this.sourceType.equals(otherKey.sourceType) && this.targetType.equals(otherKey.targetType);}public int hashCode() {return this.sourceType.hashCode() * 29 + this.targetType.hashCode();}public String toString() {return "ConverterCacheKey [sourceType = " + this.sourceType + ", targetType = " + this.targetType + "]";}}}

转载于:https://www.cnblogs.com/daxin/p/3404374.html

SpringMVC 之类型转换Converter 源代码分析相关推荐

  1. SpringMVC 之类型转换Converter详解转载

    SpringMVC之类型转换Converter详解 本文转载 http://www.tuicool.com/articles/uUjaum 1.1     目录 1.1      目录 1.2     ...

  2. nux 平台的 libpcap 源代码分析

    nux 平台的 libpcap 源代码分析 施聪 (javer@163.com), 高级程序员.网络设计师 简介: libpcap 是 unix/linux 平台下的网络数据包捕获函数包,大多数网络监 ...

  3. Spring类型转换源码分析

    前言 本文基于 spring 4.3.13 版本 在项目中我们经常使用 spring 提供的 IOC 功能,目前主要有两种方式:xml.注解,而这两种方式的原理是不同的,xml 的注入主要依赖 Bea ...

  4. Android系统默认Home应用程序(Launcher)的启动过程源代码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应 ...

  5. 《LINUX3.0内核源代码分析》第一章:内存寻址

    https://blog.csdn.net/ekenlinbing/article/details/7613334 摘要:本章主要介绍了LINUX3.0内存寻址方面的内容,重点对follow_page ...

  6. Scrapy源代码分析-经常使用的爬虫类-CrawlSpider(三)

    CrawlSpider classscrapy.contrib.spiders.CrawlSpider 爬取一般站点经常使用的spider.其定义了一些规则(rule)来提供跟进link的方便的机制. ...

  7. Android 中View的绘制机制源代码分析 三

    到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编 ...

  8. Android应用程序进程启动过程的源代码分析(1)

    Android应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是ActivityThread.main,二是进程天然支持Binder进程间通信机制:这两个特点都是在进程的初始化过程中实 ...

  9. AFNetworking 源代码分析

    关于其他 AFNetworking 源代码分析的其他文章: AFNetworking 概述(一) AFNetworking 的核心 AFURLSessionManager(二) 处理请求和响应 AFU ...

最新文章

  1. OpenCV 笔记(08)— 二维点、三维点、基于 Mat 的 std::vector 等常用数据结构的定义和输出
  2. 谈谈Java程序员进阶的那些知识和方向
  3. 如何正确使用as follows 与 following
  4. python跟java 效率_Python与Java:哪个更好,如何选择?
  5. JSON、Protobuf、Thrift、MessagePack 对比和开发指南
  6. 9 个基于JavaScript 和 CSS 的 Web 图表框架
  7. CNN的发展历史(LeNet,Alexnet,VGGNet,GoogleNet,ReSNet)
  8. 关于VM安装Linux系统成功后无法连接WIFI
  9. Caffe的各个版本简介
  10. java获取pdf的属性_Java 文件属性.pdf
  11. c语言程序无法正常运行怎么办,win7系统运行软件提示应用程序无法正常启动0xc000005怎么办...
  12. mac快速切换大小写_快速模式匹配–如果是大小写,请切换为大小写
  13. 永不消逝的电波(二)HackRF入门:家用无线门铃信号重放
  14. Excel小笔记——冻结窗格
  15. 微信小程序 | 模仿百思不得其姐
  16. 信息安全等级保护概述
  17. Onenet麒麟迷你板开发过程【附程序】
  18. yum是干什么的_linux下的yum命令详解
  19. 发现讯时CMS4.5的几个问题
  20. 音视频技术学习总结入门

热门文章

  1. 数据结构---AVL树调整方法(详)
  2. 【博客项目】—数据分页(十)
  3. 浅谈Rem 及其转换原理
  4. java定义私有变量_java – 为什么在类中声明变量私有?
  5. python调用图灵api_python调用API实现智能回复机器人
  6. 摇一摇事件封装了设备的运动传感器
  7. 在微信上如何查看2个人之间所有的红包转账记录,请注意是所有的?
  8. 蒲公英枸杞菊花可以一起泡茶喝吗?
  9. tp886n路由器是第几代?
  10. 自动挡轿车等红灯时,是挂D挡踩刹车好还是挂N挡好呢?