SpringMVC 之类型转换Converter 源代码分析
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为目标对象 实现该接口即可实现我们的类型转换,我们写一个最为常见的时间类型转换器
- public class StringToDateConvert implements Converter<String, Date> {
- private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
- @Override
- public Date convert(String source) {
- if(source.length() == 0) {
- return null;
- }
- try {
- return format.parse(source);
- } catch (ParseException e) {
- throw new RuntimeException(source + "类型转换失败");
- }
- }
- }
- 在定义好 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> {
- @Override
- public 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> {
- @Override
- public 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 :
- @SuppressWarnings("unchecked")
- final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
- public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
- return new StringToEnum(targetType);
- }
- private class StringToEnum<T extends Enum> implements Converter<String, T> {
- private final Class<T> enumType;
- public StringToEnum(Class<T> enumType) {
- this.enumType = enumType;
- }
- public T convert(String source) {
- if (source.length() == 0) {
- // It's an empty enum identifier: reset the enum value to null.
- return null;
- }
- return (T) Enum.valueOf(this.enumType, source.trim());
- }
- }
- }
这样,如果是要进行 String 到 UserStatus 的转换,我们就可以通过StringToEnumConverterFactory 实例的 getConverter(UserStatus.class).convert(string)获取到对应的 UserStatus ,如果是要转换为 UserType 的话就是getConverter(UserType.class).convert(string) 。这样就非常方便,可以很好的支持扩展。
- @SuppressWarnings("unchecked")
- 看GenericConverter 接口的定义
- GenericConverter 接口是所有的 Converter 接口中最灵活也是最复杂的一个类型转换接口。像我们之前介绍的 Converter 接口只支持从一个原类型转换为一个目标类型;ConverterFactory 接口只支持从一个原类型转换为一个目标类型对应的子类型;而GenericConverter 接口支持在多个不同的原类型和目标类型之间进行转换,这也就是GenericConverter 接口灵活和复杂的地方。
- 我们先来看一下 GenericConverter 接口的定义:
- public interface GenericConverter {
- Set<ConvertiblePair> getConvertibleTypes();
- Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
- public static final class ConvertiblePair {
- private final Class<?> sourceType;
- private final Class<?> targetType;
- 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;
- }
- }
- }
我们可以看到 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接口 这个接口就是像我们上面例子里提到的StringToDateConvert
- public 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 + "]";
- }
- }
- }
SpringMVC 之类型转换Converter 源代码分析的更多相关文章
- 转:SpringMVC之类型转换Converter(GenericConverter)
转: http://blog.csdn.net/fsp88927/article/details/37692215 SpringMVC 之类型转换 Converter 1.1 目录 1.1 目录 1. ...
- SpringMVC 之类型转换Converter详解转载
SpringMVC之类型转换Converter详解 本文转载 http://www.tuicool.com/articles/uUjaum 1.1 目录 1.1 目录 1.2 ...
- SpringMVC之类型转换Converter
(转载:http://blog.csdn.net/renhui999/article/details/9837897) 1.1 目录 1.1 目录 1.2 前言 1.3 ...
- 【Spring学习笔记-MVC-8】SpringMVC之类型转换Converter
作者:ssslinppp 1. 摘要 在spring 中定义了3中类型转换接口,分别为: Converter接口 :使用最简单,最不灵活: ConverterFa ...
- springmvc的类型转换
一.springmvc的类型转换 (一)默认情况下,springmvc内置的类型转换器只能 将"yyyy/MM/dd"类型的字符串转换为Date类型的日期 情境一: 而现在我们无 ...
- android-plugmgr源代码分析
android-plugmgr是一个Android插件加载框架,它最大的特点就是对插件不需要进行任何约束.关于这个类库的介绍见作者博客,市面上也有一些插件加载框架,但是感觉没有这个好.在这篇文章中,我 ...
- Twitter Storm源代码分析之ZooKeeper中的目录结构
徐明明博客:Twitter Storm源代码分析之ZooKeeper中的目录结构 我们知道Twitter Storm的所有的状态信息都是保存在Zookeeper里面,nimbus通过在zookeepe ...
- 转:SDL2源代码分析
1:初始化(SDL_Init()) SDL简介 有关SDL的简介在<最简单的视音频播放示例7:SDL2播放RGB/YUV>以及<最简单的视音频播放示例9:SDL2播放PCM>中 ...
- 转:RTMPDump源代码分析
0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...
随机推荐
- 给电脑装完系统之后,发现U盘少了几个G!
我的U盘是8个G的,有一次用U盘给电脑装完系统,过了几天后再次用的时候发现U盘 突然少了几个G,刚开始不知道怎么回事,然后就格式化U盘,但是格式化之后没有任何 变化. 在网上搜了一下,说是U盘有可能被 ...
- SQLServer2008备份时发生无法打开备份设备
如下图所示,在执行SQL一个简单的备份命令时发生下面的情况 问题分析: 1:可能是文件夹目录权限问题 2:可能是登录SQLServer服务器用户策略问题 于是就查看了E:\dw_backup的文件夹权 ...
- 关于DrawIndexedPrimitive函数的调用
函数的原型例如以下所看到的: HRESULT DrawIndexedPrimitive( [in] D3DPRIMITIVETYPE Type, [in] INT BaseVertexIndex, [ ...
- APNS 生成证书 p12 或者 PEM
.net环境下须要p12文件,下面是生成p12过程 1.$ openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem ...
- ASP服务器I I S出现authentication mode=Windows错误解决办法
网上下载的asp.net源码出现 <authentication mode="Windows"/>错误信息 属性 说明 mode 必选的属性. 指定应用程序的默认身份验 ...
- SpriteKit改变Node锚点其物理对象位置不对的解决
在创建Node的物理对象后,默认情况下物理对象和Node的实际边界相应的非常好,由于此时Node的默认锚点是当中心位置即(0.5,0.5),只是假设我们改变了Node的锚点,就会发现其物理边界还是保持 ...
- [Android exception] /data/app/com.tongyan.tutelage-1/lib/arm/libstlport_shared.so: has text relocations
java.lang.UnsatisfiedLinkError: dlopen failed: /data/app/com.tongyan.tutelage-1/lib/arm/libstlport_s ...
- SQL Server Management Studio 简单使用说明
1.对数据库中的数据生成脚本 a.选中要生成脚本的数据库右键->任务->生成脚本(如下图)->下一步->下一步->选中你想要生成的内容->下一步->完成
- 14-spring学习-变量操作
表达式所有操作都是可以以变量形式出现的. 观察变量的定义: package com.Spring.ELDemo; import org.springframework.expression.Evalu ...
- android下载
1. 源码下载链接: http://source.android.com/source/downloading.html 参考链接: Android源码下载方法详解 2. SDK下载 http://d ...