1. 程式人生 > >型別轉換類ConversionService

型別轉換類ConversionService

spring可以對不同Class型別進行相應的轉換。比如String轉成Boolean. Boolean轉成string類.以下是個簡單的例子

  1. @Test
  2. public void testConverter() {
  3. DefaultConversionService serivce = new DefaultConversionService();
  4. boolean actual = serivce.canConvert(String.class, Boolean.class);
  5. Assert.assertEquals(true, actual);
  6. Object acc = serivce.convert("true", Boolean.class);
  7. Assert.assertEquals(true, ((Boolean)acc).booleanValue());
  8. }

spring型別轉換涉及到的類圖如下

1、spring是通過ConversionService進行型別轉換,通過ConverterRegistry進行轉換器註冊

其中ConversionService中的方法canConverter判斷是否可以轉失,convert呼叫相應的轉換器進行型別轉換操作

ConverterRegistry中的方法add(Converter)是註冊一個轉換器

2、對於ConversionService和ConverterRegistry的主要實現類是GenericConversionService。GenericConversionService維護了一個內部類的物件Converters.

當註冊一個converter時。會生成一個GenericeConverter的適配類ConverterAdapter,並註冊到內部類Converters中

  1. public void addConverter(Converter<?, ?> converter) {
  2. GenericConverter.ConvertiblePair typeInfo = getRequiredTypeInfo(converter, Converter.class);
  3. Assert.notNull(typeInfo, "Unable to the determine sourceType <S
    >
    and targetType " +
  4. "<T> which your Converter<S, T> converts between; declare these generic types.");
  5. addConverter(new ConverterAdapter(typeInfo, converter));
  6. }
  7. public void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter) {
  8. GenericConverter.ConvertiblePair typeInfo = new GenericConverter.ConvertiblePair(sourceType, targetType);
  9. addConverter(new ConverterAdapter(typeInfo, converter));
  10. }
  11. public void addConverter(GenericConverter converter) {
  12. this.converters.add(converter);
  13. invalidateCache();
  14. }

內部類Converters中維護了一個Map用於存放先前註冊的所有Converter

  1. private static class Converters {
  2. private final Set<GenericConverter> globalConverters =
  3. new LinkedHashSet<GenericConverter>();
  4. private final Map<ConvertiblePair, ConvertersForPair> converters =
  5. new LinkedHashMap<ConvertiblePair, ConvertersForPair>(36);
  6. public void add(GenericConverter converter) {
  7. Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();
  8. if (convertibleTypes == null) {
  9. Assert.state(converter instanceof ConditionalConverter,
  10. "Only conditional converters may return null convertible types");
  11. globalConverters.add(converter);
  12. }
  13. else {
  14. for (ConvertiblePair convertiblePair : convertibleTypes) {
  15. ConvertersForPair convertersForPair = getMatchableConverters(convertiblePair);
  16. convertersForPair.add(converter);
  17. }
  18. }
  19. }
3、當呼叫canConvert時,會呼叫內部類的方法find方法查詢轉換的型別sourceType和targetType是否進行了註冊
  1. protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
  2. ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
  3. GenericConverter converter = this.converterCache.get(key);
  4. if (converter != null) {
  5. return (converter != NO_MATCH ? converter : null);
  6. }
  7. converter = this.converters.find(sourceType, targetType);
  8. if (converter == null) {
  9. converter = getDefaultConverter(sourceType, targetType);
  10. }
  11. if (converter != null) {
  12. this.converterCache.put(key, converter);
  13. return converter;
  14. }
  15. this.converterCache.put(key, NO_MATCH);
  16. return null;
  17. }
其中內部類Converters的find方法根據sourceType和targetType去查詢Converters中維護的Map中是否包括支援的註冊型別,如果存在返回GenericConverter的適配類ConverterAdapter,如果沒有存在返回null
  1. public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {
  2. // Search the full type hierarchy
  3. List<Class<?>> sourceCandidates = getClassHierarchy(sourceType.getType());
  4. List<Class<?>> targetCandidates = getClassHierarchy(targetType.getType());
  5. for (Class<?> sourceCandidate : sourceCandidates) {
  6. for (Class<?> targetCandidate : targetCandidates) {
  7. ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);
  8. GenericConverter converter = getRegisteredConverter(
  9. sourceType, targetType, convertiblePair);
  10. if(converter != null) {
  11. return converter;
  12. }
  13. }
  14. }
  15. return null;
  16. }
  17. private GenericConverter getRegisteredConverter(TypeDescriptor sourceType,
  18. TypeDescriptor targetType, ConvertiblePair convertiblePair) {
  19. // Check specifically registered converters
  20. ConvertersForPair convertersForPair = converters.get(convertiblePair);
  21. GenericConverter converter = convertersForPair == null ? null
  22. : convertersForPair.getConverter(sourceType, targetType);
  23. if (converter != null) {
  24. return converter;
  25. }
  26. // Check ConditionalGenericConverter that match all types
  27. for (GenericConverter globalConverter : this.globalConverters) {
  28. if (((ConditionalConverter)globalConverter).matches(
  29. sourceType, targetType)) {
  30. return globalConverter;
  31. }
  32. }
  33. return null;
  34. }
4、當查詢到註冊的型別轉換器時GenericConverter時。會呼叫ConverterAdapter中的convert方法。ConverterAdapter中的convert方法會呼叫相當維護的converter並轉換
  1. public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
  2. if (source == null) {
  3. return convertNullSource(sourceType, targetType);
  4. }
  5. return this.converter.convert(source);
  6. }
5、spring的註冊型別轉換器時,是通過GenericConversionService的子類DefaultConversionService實現的
  1. private static void addScalarConverters(ConverterRegistry converterRegistry) {
  2. ConversionService conversionService = (ConversionService) converterRegistry;
  3. converterRegistry.addConverter(new StringToBooleanConverter());
  4. converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());
  5. converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
  6. converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());
  7. converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());
  8. converterRegistry.addConverter(new StringToCharacterConverter());
  9. converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());
  10. converterRegistry.addConverter(new NumberToCharacterConverter());
  11. converterRegistry.addConverterFactory(new CharacterToNumberFactory());
  12. converterRegistry.addConverterFactory(new StringToEnumConverterFactory());
  13. converterRegistry.addConverter(Enum.class, String.class, new EnumToStringConverter(conversionService));
  14. converterRegistry.addConverter(new StringToLocaleConverter());
  15. converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());
  16. converterRegistry.addConverter(new PropertiesToStringConverter());
  17. converterRegistry.addConverter(new StringToPropertiesConverter());
  18. converterRegistry.addConverter(new StringToUUIDConverter());
  19. converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());
  20. }