型別轉換類ConversionService
阿新 • • 發佈:2018-12-11
spring可以對不同Class型別進行相應的轉換。比如String轉成Boolean. Boolean轉成string類.以下是個簡單的例子
- @Test
- public void testConverter() {
- DefaultConversionService serivce = new DefaultConversionService();
- boolean actual = serivce.canConvert(String.class, Boolean.class);
- Assert.assertEquals(true, actual);
- Object acc = serivce.convert("true", Boolean.class);
- Assert.assertEquals(true, ((Boolean)acc).booleanValue());
- }
spring型別轉換涉及到的類圖如下
1、spring是通過ConversionService進行型別轉換,通過ConverterRegistry進行轉換器註冊
其中ConversionService中的方法canConverter判斷是否可以轉失,convert呼叫相應的轉換器進行型別轉換操作
ConverterRegistry中的方法add(Converter)是註冊一個轉換器
2、對於ConversionService和ConverterRegistry的主要實現類是GenericConversionService。GenericConversionService維護了一個內部類的物件Converters.
當註冊一個converter時。會生成一個GenericeConverter的適配類ConverterAdapter,並註冊到內部類Converters中
- public void addConverter(Converter<?, ?> converter) {
- GenericConverter.ConvertiblePair typeInfo = getRequiredTypeInfo(converter, Converter.class);
- Assert.notNull(typeInfo, "Unable to the determine sourceType <S
> and targetType " + - "<T> which your Converter<S, T> converts between; declare these generic types.");
- 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));
- }
- public void addConverter(GenericConverter converter) {
- this.converters.add(converter);
- invalidateCache();
- }
內部類Converters中維護了一個Map用於存放先前註冊的所有Converter
- private static class Converters {
- private final Set<GenericConverter> globalConverters =
- new LinkedHashSet<GenericConverter>();
- private final Map<ConvertiblePair, ConvertersForPair> converters =
- new LinkedHashMap<ConvertiblePair, ConvertersForPair>(36);
- public void add(GenericConverter converter) {
- Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();
- if (convertibleTypes == null) {
- Assert.state(converter instanceof ConditionalConverter,
- "Only conditional converters may return null convertible types");
- globalConverters.add(converter);
- }
- else {
- for (ConvertiblePair convertiblePair : convertibleTypes) {
- ConvertersForPair convertersForPair = getMatchableConverters(convertiblePair);
- convertersForPair.add(converter);
- }
- }
- }
3、當呼叫canConvert時,會呼叫內部類的方法find方法查詢轉換的型別sourceType和targetType是否進行了註冊
其中內部類Converters的find方法根據sourceType和targetType去查詢Converters中維護的Map中是否包括支援的註冊型別,如果存在返回GenericConverter的適配類ConverterAdapter,如果沒有存在返回null
- 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);
- }
- converter = this.converters.find(sourceType, targetType);
- if (converter == null) {
- converter = getDefaultConverter(sourceType, targetType);
- }
- if (converter != null) {
- this.converterCache.put(key, converter);
- return converter;
- }
- this.converterCache.put(key, NO_MATCH);
- return null;
- }
- public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {
- // Search the full type hierarchy
- List<Class<?>> sourceCandidates = getClassHierarchy(sourceType.getType());
- List<Class<?>> targetCandidates = getClassHierarchy(targetType.getType());
- for (Class<?> sourceCandidate : sourceCandidates) {
- for (Class<?> targetCandidate : targetCandidates) {
- ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);
- GenericConverter converter = getRegisteredConverter(
- sourceType, targetType, convertiblePair);
- if(converter != null) {
- return converter;
- }
- }
- }
- return null;
- }
- private GenericConverter getRegisteredConverter(TypeDescriptor sourceType,
- TypeDescriptor targetType, ConvertiblePair convertiblePair) {
- // Check specifically registered converters
- ConvertersForPair convertersForPair = converters.get(convertiblePair);
- GenericConverter converter = convertersForPair == null ? null
- : convertersForPair.getConverter(sourceType, targetType);
- if (converter != null) {
- return converter;
- }
- // Check ConditionalGenericConverter that match all types
- for (GenericConverter globalConverter : this.globalConverters) {
- if (((ConditionalConverter)globalConverter).matches(
- sourceType, targetType)) {
- return globalConverter;
- }
- }
- return null;
- }
4、當查詢到註冊的型別轉換器時GenericConverter時。會呼叫ConverterAdapter中的convert方法。ConverterAdapter中的convert方法會呼叫相當維護的converter並轉換
5、spring的註冊型別轉換器時,是通過GenericConversionService的子類DefaultConversionService實現的
- public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
- if (source == null) {
- return convertNullSource(sourceType, targetType);
- }
- return this.converter.convert(source);
- }
- private static void addScalarConverters(ConverterRegistry converterRegistry) {
- ConversionService conversionService = (ConversionService) converterRegistry;
- converterRegistry.addConverter(new StringToBooleanConverter());
- converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());
- converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
- converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());
- converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());
- converterRegistry.addConverter(new StringToCharacterConverter());
- converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());
- converterRegistry.addConverter(new NumberToCharacterConverter());
- converterRegistry.addConverterFactory(new CharacterToNumberFactory());
- converterRegistry.addConverterFactory(new StringToEnumConverterFactory());
- converterRegistry.addConverter(Enum.class, String.class, new EnumToStringConverter(conversionService));
- converterRegistry.addConverter(new StringToLocaleConverter());
- converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());
- converterRegistry.addConverter(new PropertiesToStringConverter());
- converterRegistry.addConverter(new StringToPropertiesConverter());
- converterRegistry.addConverter(new StringToUUIDConverter());
- converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());
- }