Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html
Spring ConversionService 類型轉換系列文章:java
JDK 提供的 PropertyEditor 只能將 String 類型轉爲 Object,若是要將一種 Object 類型轉換成另外一種 Object 類型就只能使用 Spring 提供的 ConversionService 了,這些類都位於 org.springframework.core.convert 包下。spring
private ConversionService conversionService; @Before public void before() { conversionService = new DefaultConversionService(); } @Test public void test() { ConversionService conversionService = new DefaultConversionService(); Integer value = conversionService.convert("1", Integer.class); Assert.assertTrue(value == 1); }
在 DefaultConversionService 組件中已經註冊了 Spring 默認的覺轉換器,能夠分爲如下幾類:ide
Converter
一對一轉換,把 S 類型轉化成 T 類型,最經常使用的轉換器ConverterFactory
一對 N 轉換GenericConverter
N 對 N 轉換(1) 接口學習
@FunctionalInterface public interface Converter<S, T> { T convert(S source); }
Converter接口很簡單,就是把 S 類型轉化成 T 類型。咱們看一下使用方法:測試
(2) 測試ui
@Test public void converterTest() { // ObjectToStringConverter Assert.assertEquals("false", conversionService.convert(false, String.class)); // StringToBooleanConverter Assert.assertTrue(conversionService.convert("true", Boolean.class)); }
(3) ObjectToStringConverter 分析this
ObjectToStringConverter 和 StringToBooleanConverter 都是在 DefaultConversionService 中內置的。code
final class ObjectToStringConverter implements Converter<Object, String> { @Override public String convert(Object source) { return source.toString(); } }
(1) 接口htm
public interface ConverterFactory<S, R> { <T extends R> Converter<S, T> getConverter(Class<T> targetType); }
R 的子類均可以統一由這個 ConverterFactory 進行轉換。
(2) 測試
// 測試 ConverterFactory StringToNumberConverterFactory @Test public void converterFactoryTest() { Assert.assertTrue(conversionService.convert("1.2", double.class) == 1.2d); Assert.assertTrue(conversionService.convert("1", int.class) == 1); Assert.assertTrue(conversionService.convert("0x10", byte.class) == 0x10); }
這裏用到了 StringToNumberConverterFactory 把 String 轉化成了 Number 的各個子類型,代碼其實很簡單:
(3) StringToNumberConverterFactory 分析
final class StringToNumberConverterFactory implements ConverterFactory<String, Number> { @Override public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) { return new StringToNumber<>(targetType); } private static final class StringToNumber<T extends Number> implements Converter<String, T> { private final Class<T> targetType; public StringToNumber(Class<T> targetType) { this.targetType = targetType; } @Override public T convert(String source) { if (source.isEmpty()) { return null; } // String 類型轉換成 Number return NumberUtils.parseNumber(source, this.targetType); } } }
(1) 接口
public interface GenericConverter { // 能夠轉換的類型 Set<ConvertiblePair> getConvertibleTypes(); Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType); final class ConvertiblePair { private final Class<?> sourceType; private final Class<?> targetType; } } // 匹配 GenericConverter public interface ConditionalConverter { boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); } public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter { }
GenericConverter 是 N:N 的轉化,支持轉化的全部類型都寫在了屬性 Set
(2) 測試
// 測試 GenericConverter CollectionToCollectionConverter @Test public void genericConverterTest() { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Set<String> set = (Set<String>) conversionService.convert(list, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class)), TypeDescriptor.collection(Set.class, TypeDescriptor.valueOf(String.class))); // List<Integer> -> Set<String> Assert.assertEquals("1", set.toArray(new String[0])[0]); }
這裏用到了 CollectionToCollectionConverter
(3) CollectionToCollectionConverter 分析
final class CollectionToCollectionConverter implements ConditionalGenericConverter { private final ConversionService conversionService; public CollectionToCollectionConverter(ConversionService conversionService) { this.conversionService = conversionService; } @Override public Set<ConvertiblePair> getConvertibleTypes() { return Collections.singleton(new ConvertiblePair(Collection.class, Collection.class)); } @Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { return ConversionUtils.canConvertElements( sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), this.conversionService); } @Override public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { if (source == null) { return null; } Collection<?> sourceCollection = (Collection<?>) source; // 集合類型 boolean copyRequired = !targetType.getType().isInstance(source); // 1. targetType 集合類型沒變,不用轉換 if (!copyRequired && sourceCollection.isEmpty()) { return source; } // 集合元素類型 TypeDescriptor elementDesc = targetType.getElementTypeDescriptor(); // 2. targetType 集合元素沒有指定類型,即 Object,且集合類型沒變 if (elementDesc == null && !copyRequired) { return source; } // 建立一個空集合 Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), (elementDesc != null ? elementDesc.getType() : null), sourceCollection.size()); // 3. targetType 集合元素沒有指定類型,則元素不用轉換類型 if (elementDesc == null) { target.addAll(sourceCollection); // 4. conversionService 將 sourceElement 轉換爲 targetElement 類型 } else { for (Object sourceElement : sourceCollection) { Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementTypeDescriptor(sourceElement), elementDesc); target.add(targetElement); if (sourceElement != targetElement) { copyRequired = true; } } } return (copyRequired ? target : source); } }
參考:
天天用心記錄一點點。內容也許不重要,但習慣很重要!