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爲目標對象 實現該接口便可實現咱們的類型轉換,咱們寫一個最爲常見的時間類型轉換器
  •  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接口。完成了咱們類型轉換器的註冊 與 轉換邏輯,下面咱們將經過源代碼來詳細分析該實現的邏輯。app

  • 在分析源代碼以前,讓咱們在看另外倆個轉換器,也就是上面提到的 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 的一個子類。ide

  • 考慮這樣一種狀況,咱們有一個表示用戶狀態的枚舉類型 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 大概是這個樣子:ui

  • 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 :this

  •  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) 。這樣就很是方便,能夠很好的支持擴展。spa

  • 看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接口 這個接口就是像咱們上面例子裏提到的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 + "]";
        }
    }

}
相關文章
相關標籤/搜索