要知道spring的类型转换,我们首先需要知道两个接口。这两个接口就是类型转换的处理类,一个是spring自己定义的,一个是jdk定义的:
Spring定义的Converter接口:
@FunctionalInterface public interface Converter
{ @Nullable T convert(S source); }
Jdk定义的PropertyEditor接口:
public interface PropertyEditor { void setValue(Object value); Object getValue(); boolean isPaintable(); void paintValue(java.awt.Graphics gfx, java.awt.Rectangle box); String getJavaInitializationString(); String getAsText(); void setAsText(String text) throws java.lang.IllegalArgumentException; String[] getTags(); java.awt.Component getCustomEditor(); boolean supportsCustomEditor(); void addPropertyChangeListener(PropertyChangeListener listener); void removePropertyChangeListener(PropertyChangeListener listener); }
这个PropertyEditor用于类型转换的是setAsText、getAsText、getValue、setValue这些方法。
可以看到Converter这里用了泛型、而PropertyEditor并没有。所以,如果调用getValue方法,获取的是Object对象。获取后还需要再转换为我们的目的对象。
这两个Converter、PropertyEditor接口只是接口,下面我们来看下其的实现类。
Converter接口只有一个convert方法,但我们知道,在进行类型转换前,我们一般会先判断其能不能转换为目的类型。所以其实Converter还会搭配ConditionalConverter接口,判断能不能转换:
public interface ConditionalConverter { boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); }
这两个在组合为一个ConditionalGenericConverter接口:
public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter { }
这里GenericConverter接口,我们先将其看做为Converter接口(但其并有继承Converter接口,只是一个独立接口,在Spring的使用中,实现Converter接口的类最后还是会表叙为GenericConverter接口,这个到后面的代码就明白了),
public interface GenericConverter { @Nullable Set
getConvertibleTypes(); @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType); 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; } ................ }
ConvertiblePair 就是哟本来存源类型,目标类型。
我们先简单看一个Converter接口的实现类:NumberToCharacterConverter ,将Number类型转换为Character类型
final class NumberToCharacterConverter implements Converter
{ @Override public Character convert(Number source) { return (char) source.shortValue(); } }
通过这个我们可以知道Converter在Spring的实现过程。
接下来我们看下其的使用过程,我们看下这个转换器在哪里使用。其是在DefaultConversionService类中被注册:
private static void addScalarConverters(ConverterRegistry converterRegistry) { converterRegistry.addConverterFactory(new NumberToNumberConverterFactory()); .............. converterRegistry.addConverter(new NumberToCharacterConverter()); converterRegistry.addConverterFactory(new CharacterToNumberFactory()); converterRegistry.addConverter(new StringToBooleanConverter()); ................ }
public static void addDefaultConverters(ConverterRegistry converterRegistry) { addScalarConverters(converterRegistry); addCollectionConverters(converterRegistry); converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry)); .......... }
这里我们先了解DefaultConversionService、ConverterRegistry。
ConverterRegister,这个看名字就知道其是用来注册Converter的:
这里有四种类型注册。在这里我们看到可以注册Converter以及GenericConverter,还有ConverterFactory,就是生成Converter 的工厂。
public interface ConversionService { boolean canConvert(@Nullable Class sourceType, Class targetType); boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType); @Nullable
T convert(@Nullable Object source, Class targetType); @Nullable Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType); }
ConversionService 这个接口就是用来判断能不能进行转换,以及进行转换的。
public interface ConfigurableConversionService extends ConversionService, ConverterRegistry { }
其实现类GenericConversionService
GenericConversionService类有两个成员变量:
private final Converters converters = new Converters(); private final Map
converterCache = new ConcurrentReferenceHashMap<>(64);
@Override public void addConverter(Converter converter) { ResolvableType[] typeInfo = getRequiredTypeInfo(converter.getClass(), Converter.class); if (typeInfo == null && converter instanceof DecoratingProxy) { typeInfo = getRequiredTypeInfo(((DecoratingProxy) converter).getDecoratedClass(), Converter.class); } .......... addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1])); }
@Nullable private ResolvableType[] getRequiredTypeInfo(Class converterClass, Class genericIfc) { ResolvableType resolvableType = ResolvableType.forClass(converterClass).as(genericIfc); ResolvableType[] generics = resolvableType.getGenerics(); if (generics.length < 2) { return null; } Class sourceType = generics[0].resolve(); Class targetType = generics[1].resolve(); if (sourceType == null || targetType == null) { return null; } return generics; }
可以看到这个getRequiredTypeInfo就用来获取Converter中的两个表示泛型的类型,例如前面的NumberToCharacterConverter implements Converter
private final class ConverterAdapter implements ConditionalGenericConverter { private final Converter
ConverterAdapter是实现了ConditionalGenericConverter 接口,所以其需要实现GenericConverter的convert方法、以及ConditionalConverter的是否匹配,即是否能用本Converter去转换。同时会将Converter的源类型以及目标类型存到ConvertiblePair。所以这里就将前面的GenericConverter与Converter 的关系理清了。Converter会被转换到ConverterAdapter,ConverterAdapter实现了GenericConverter。
我们再回到 addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));方法:
其调用的是:
@Override public void addConverter(GenericConverter converter) { this.converters.add(converter); invalidateCache(); }
所以这里如果是添加GenericConverter类型,就将其直接添加到converters,如果是添加Converter就将其转换为ConverterAdapter(类型转换适配器)。再调用addConverter(GenericConverter converter)方法,ConverterAdapter实现统一的matchs方法。
private final Converters converters = new Converters();
private static class Converters { private final Set
globalConverters = new LinkedHashSet<>() private final Map converters = new LinkedHashMap<>(36); public void add(GenericConverter converter) { Set convertibleTypes = converter.getConvertibleTypes(); if (convertibleTypes == null) { Assert.state(converter instanceof ConditionalConverter, "Only conditional converters may return null convertible types"); this.globalConverters.add(converter); } else { for (ConvertiblePair convertiblePair : convertibleTypes) { ConvertersForPair convertersForPair = getMatchableConverters(convertiblePair); convertersForPair.add(converter); } } } private ConvertersForPair getMatchableConverters(ConvertiblePair convertiblePair) { ConvertersForPair convertersForPair = this.converters.get(convertiblePair); if (convertersForPair == null) { convertersForPair = new ConvertersForPair(); this.converters.put(convertiblePair, convertersForPair); } return convertersForPair; }
可以看到这里的添加会分情况添加到两个地方:globalConverters、converters。要了解这两种的区别,我们看其find方法,即找到对应的GenericConverter:
首先下ConvertersForPair类
private static class ConvertersForPair { private final LinkedList
converters = new LinkedList<>(); public void add(GenericConverter converter) { this.converters.addFirst(converter); } @Nullable public GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) { for (GenericConverter converter : this.converters) { if (!(converter instanceof ConditionalGenericConverter) || ((ConditionalGenericConverter) converter).matches(sourceType, targetType)) { return converter; } } return null; } }
public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) { ................... 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 = this.converters.get(convertiblePair); if (convertersForPair != null) { GenericConverter converter = convertersForPair.getConverter(sourceType, targetType); if (converter != null) { return converter; } } // Check ConditionalConverters for a dynamic match for (GenericConverter globalConverter : this.globalConverters) { if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) { return globalConverter; } } return null; }
这里是先获取添加到converters中的,如果没有再获取globalConverters中的:
通过前面ConvertersForPair 的getConverter方法,可以知道其在matches是转换为ConditionalGenericConverter,而globalConverters是强转为ConditionalConverter。其中ConditionalGenericConverter继承了ConditionalConverter接口。
所以关于Converer接口,整个使用过程是如果实现Converter接口的类都转换为ConverterAdapter适配器,然后通过这个适配器实现的matches的方法去匹配,及调用converter的convert方法。而如果是添加的GenericConverter类型,通过find方法可以知道,要么同时一起继承ConditionalConverter接口(matches方法),要么直接实现ConditionalGenericConverter,因为
ConditionalGenericConverter继承了ConditionalConverter与GenericConverter接口。
这里Converter、GenericConverter、ConditionalConverter是怎样在GenericConversionService中使用的已经理清楚了。我们再来看其在Spring中使用过程。
我们再回到继承GenericConversionService类的DefaultConversionService:
public DefaultConversionService() { addDefaultConverters(this); }
其在初始化的时候就调用addDefaultConverters将默认的Converter添加到该类中,如果需要自己再添加,就可以调用前面介绍的addConverter方法,
哪里使用到这个DefaultConversionService类呢?这里就要知道TypeConverterSupport类,Spring中类型转换就是通过这个类去统筹调度的。先在这里不展开,因为这个类还会用到类型转换的另一个接口PropertyEditer接口。
这个接口 在Jdk中有个初步实现类:PropertyEditorSupport:
public class PropertyEditorSupport implements PropertyEditor {private Object value; private Object source; private java.util.Vector
listeners; .................. public void setValue(Object value) { this.value = value; firePropertyChange(); } public Object getValue() { return value; } public String getAsText() { return (this.value != null) ? this.value.toString() : null; } public void setAsText(String text) throws java.lang.IllegalArgumentException { if (value instanceof String) { setValue(text); return; } throw new java.lang.IllegalArgumentException(text); } ............. }
可以看到这里在setValue的时候会去通知Listener。我们看一个Spring关于PropertyEditerSupport的实现类:
public class ByteArrayPropertyEditor extends PropertyEditorSupport { @Override public void setAsText(@Nullable String text) { setValue(text != null ? text.getBytes() : null); } @Override public String getAsText() { byte[] value = (byte[]) getValue(); return (value != null ? new String(value) : ""); } }
这里就是将text设置为byte[],所以这个类的成员变量为byte[]。当调用getValue的时候返回的是byte[],调用getAsText的时候是获取转换为byte的String。看下Spring中的测试用例:
@Test public void sunnyDaySetAsText() throws Exception { final String text = "Hideous towns make me throw... up"; byteEditor.setAsText(text); Object value = byteEditor.getValue(); assertNotNull(value); assertTrue(value instanceof byte[]); byte[] bytes = (byte[]) value; for (int i = 0; i < text.length(); ++i) { assertEquals("cyte[] differs at index '" + i + "'", text.charAt(i), bytes[i]); } assertEquals(text, byteEditor.getAsText()); }
这里在getValue的时候要强转换为byte[]。
public interface TypeConverter { @Nullable
T convertIfNecessary(@Nullable Object value, @Nullable Class requiredType) throws TypeMismatchException; @Nullable T convertIfNecessary(@Nullable Object value, @Nullable Class requiredType, @Nullable MethodParameter methodParam) throws TypeMismatchException; @Nullable T convertIfNecessary(@Nullable Object value, @Nullable Class requiredType, @Nullable Field field) throws TypeMismatchException; }
这个TypeConverter就是判断当前的转换器中能不能转换,能转换就调用对应方法进行转换:
public interface PropertyEditorRegistry { void registerCustomEditor(Class requiredType, PropertyEditor propertyEditor); void registerCustomEditor(@Nullable Class requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor); @Nullable PropertyEditor findCustomEditor(@Nullable Class requiredType, @Nullable String propertyPath); }
PropertyEditorRegistry ,通过参数就可以知道其是用来注册PropertyEditor 这种转换器的。
PropertyEditorRegistry 实现类PropertyEditorRegistrySupport:
public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { @Nullable private ConversionService conversionService; private boolean defaultEditorsActive = false; private boolean configValueEditorsActive = false; @Nullable private Map
, PropertyEditor> defaultEditors; @Nullable private Map , PropertyEditor> overriddenDefaultEditors; @Nullable private Map , PropertyEditor> customEditors; @Nullable private Map customEditorsForPath; @Nullable private Map , PropertyEditor> customEditorCache; ................................ public PropertyEditor getDefaultEditor(Class requiredType) { if (!this.defaultEditorsActive) { return null; } if (this.overriddenDefaultEditors != null) { PropertyEditor editor = this.overriddenDefaultEditors.get(requiredType); if (editor != null) { return editor; } } if (this.defaultEditors == null) { createDefaultEditors(); } return this.defaultEditors.get(requiredType); } private void createDefaultEditors() { this.defaultEditors = new HashMap<>(64); // Simple editors, without parameterization capabilities. // The JDK does not contain a default editor for any of these target types. this.defaultEditors.put(Charset.class, new CharsetEditor()); this.defaultEditors.put(Class.class, new ClassEditor()); } .............................. }
这里关注两种类型,defaultEditors这个就是Spring的默认添加的PropertyEditor,customEditors这个就是你自定义的propertyEditor是添加在这里,这里的ConversionService 就是赋值前面讲的用与管理GenericConverter类型转换的GenericConversionService及其子类
再回到TypeConverterSupport:
public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport implements TypeConverter { @Nullable TypeConverterDelegate typeConverterDelegate; @Override @Nullable public
T convertIfNecessary(@Nullable Object value, @Nullable Class requiredType) throws TypeMismatchException { return doConvert(value, requiredType, null, null); } @Override @Nullable public T convertIfNecessary(@Nullable Object value, @Nullable Class requiredType, @Nullable MethodParameter methodParam) throws TypeMismatchException { return doConvert(value, requiredType, methodParam, null); } @Override @Nullable public T convertIfNecessary(@Nullable Object value, @Nullable Class requiredType, @Nullable Field field) throws TypeMismatchException { return doConvert(value, requiredType, null, field); } @Nullable private T doConvert(@Nullable Object value,@Nullable Class requiredType, @Nullable MethodParameter methodParam, @Nullable Field field) throws TypeMismatchException { Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate"); try { if (field != null) { return this.typeConverterDelegate.convertIfNecessary(value, requiredType, field); } else { return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam); } } catch (ConverterNotFoundException | IllegalStateException ex) { throw new ConversionNotSupportedException(value, requiredType, ex); } catch (ConversionException | IllegalArgumentException ex) { throw new TypeMismatchException(value, requiredType, ex); } } }
可以看到这里convertIfNecessary最终是调用doConvert去转换的,而doConvert是调用typeConverterDelegate的convertIfNecessary。
class TypeConverterDelegate { private final PropertyEditorRegistrySupport propertyEditorRegistry; @Nullable private final Object targetObject; public TypeConverterDelegate(PropertyEditorRegistrySupport propertyEditorRegistry) { this(propertyEditorRegistry, null); } ................... }
可以看到TypeConverterDelegate的初始化是需要PropertyEditorRegistrySupport,而TypeConverterSupport实现了该类,并且TypeConverterSupport是抽象类,所以TypeConverterDelegate初始化的时候是TypeConverterSupport的实现类传的this,用代码验证下:
protected AbstractNestablePropertyAccessor(boolean registerDefaultEditors) { if (registerDefaultEditors) { registerDefaultEditors(); } this.typeConverterDelegate = new TypeConverterDelegate(this); } public class SimpleTypeConverter extends TypeConverterSupport { public SimpleTypeConverter() { this.typeConverterDelegate = new TypeConverterDelegate(this); registerDefaultEditors(); } }
AbstractNestablePropertyAccessor实现了TypeConverterSupport。所以这里得到了验证,就是将作为TypeConverterSupport成员的TypeConverterDelegate类的初始化传TypeConverterSupport本身。
我们看TypeConverterDelegate的convertIfNecessary方法:
public
T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue, @Nullable Class requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException { // Custom editor for this type? PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName); ConversionFailedException conversionAttemptEx = null; // No custom editor but custom ConversionService specified? ConversionService conversionService = this.propertyEditorRegistry.getConversionService(); if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) { TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue); if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) { try { return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor); } catch (ConversionFailedException ex) { // fallback to default conversion logic below conversionAttemptEx = ex; } } } Object convertedValue = newValue; .................. if (editor == null) { editor = findDefaultEditor(requiredType); } convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor); } ...............(这后面有一串很长的代码,不过一般用前面这一串就可以完成转换了) return (T) convertedValue; }
1、这里实现是获取自定义PropertyEditor。
2、如果ConversionService不为空,就是指如果存在Converter类型的转获取其,其这里找一下,看有没有符合的Converter转换器:
conversionService.canConvert(sourceTypeDesc, typeDescriptor),该放在在GenericConversionService的实现:
public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) { ........... GenericConverter converter = getConverter(sourceType, targetType); return (converter != 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; }
这里是用了缓存,我们找到在放到缓存前的两个方法:
converter = this.converters.find(sourceType, targetType); if (converter == null) { converter = getDefaultConverter(sourceType, targetType); }
这里的find方法在前面已经讲GenericConversionService的时候就讲了,我们看下如果没有获取到,调用getDefaultConverter:
@Nullable protected GenericConverter getDefaultConverter(TypeDescriptor sourceType, TypeDescriptor targetType) { return (sourceType.isAssignableTo(targetType) ? NO_OP_CONVERTER : null); } private static final GenericConverter NO_OP_CONVERTER = new NoOpConverter("NO_OP"); private static class NoOpConverter implements GenericConverter { private final String name; .......... @Nullable public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { return source; } }
我们再回到前面的convertIfNecessary,如果在这里找到了对应Converter类型的转换器,就去进行对应的转换:
public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) { ............... GenericConverter converter = getConverter(sourceType, targetType); if (converter != null) { Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType); return handleResult(sourceType, targetType, result); } ................ }
获取对应的GenericConverter,然后通过ConversionUtils工具类ConversionUtils去转换:
public static Object invokeConverter(GenericConverter converter, @Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { try { return converter.convert(source, sourceType, targetType); } catch (ConversionFailedException ex) { throw ex; } catch (Throwable ex) { throw new ConversionFailedException(sourceType, targetType, source, ex); } }
再回到convertIfNecessary方法,如果没有对应的GenericConverter类型转换器,就会接着往下:
if (editor == null) { editor = findDefaultEditor(requiredType); } convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
如果没有自定义的PropertyEditor,就会获取默认的PropertyEditor,去转换:
private PropertyEditor findDefaultEditor(@Nullable Class requiredType) { .............. editor = this.propertyEditorRegistry.getDefaultEditor(requiredType); .......... return editor; }
这里就回到前面讲propertyEditorRegistrySupport是时候的getDefaultEditor方法了,将所有的默认Editer,添加到defaultEditors。
自此,这个Spring的类型转换就梳理完毕了。Spring中如果要进行类型转换,就会持有TypeConverterDelegate,或者持有
TypeConverterSupport的子类。同时通过这个流程可以知道。进行类型转换的时候首先是使用Converter类型,如果该类型能完成转换,就不会去使用propertyEditor了。并且,在使用Converter类型的时候,是先使用实现ConditionalGenericConverter接口的类,如果没有才会再去使用实现ConditionalConverter类型的类。