Spring的类型转换器Converter

本文介绍了Spring的转换器机制,包括Converter、ConverterFactory、GenericConverter等接口的用途,详细讲解了TypeConverterDelegate如何结合PropertyEditor和ConversionService进行类型转换,以及它们在处理对象转换中的角色和应用场景。
摘要由CSDN通过智能技术生成
前言

一直想开发一个功能比较强大的项目,但是一直没有动手,最近终于有点时间来折腾它了。由于时隔两年没有接触前端了,所以需要一个小项目先练练手感。等这个项目完工之后在着手搞一个大工程。都说好记星不如烂笔头,现在就将这一个过程记录下来,万一有什么踩坑的地方,也可以提示后来人。

背景
由于项目中需要使用到日期和字符串的一个转换,使用到了Converter,所以记录下来。
/**
 * 日期转换
 */
@Component
public class DateConverter implements Converter<String, LocalDate> {

    @Override
    public LocalDate convert(String source) {

        try {
            return LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            //return LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        } catch (Exception e) {
           
        }
        return null;
    }
}
Spring提供了3种converter接口,分别是Converter、ConverterFactory和GenericConverter.一般用于1:1, 1:N, N:N的source->target类型转化

在这里插入图片描述

Converter
public interface Converter<S, T> {
  // 将S转换成T
T convert(S source);
}
GenericConverter

用于在两种或更多种类型之间转换的通用转换器接口

public interface GenericConverter {
    @Nullable
    Set<GenericConverter.ConvertiblePair> getConvertibleTypes();

    @Nullable
    Object convert(@Nullable Object var1, TypeDescriptor var2, TypeDescriptor var3);

    public static 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;
        }

        public boolean equals(@Nullable Object other) {
            if (this == other) {
                return true;
            } else if (other != null && other.getClass() == GenericConverter.ConvertiblePair.class) {
                GenericConverter.ConvertiblePair otherPair = (GenericConverter.ConvertiblePair)other;
                return this.sourceType == otherPair.sourceType && this.targetType == otherPair.targetType;
            } else {
                return false;
            }
        }

        public int hashCode() {
            return this.sourceType.hashCode() * 31 + this.targetType.hashCode();
        }

        public String toString() {
            return this.sourceType.getName() + " -> " + this.targetType.getName();
        }
    }
}
ConverterFactory
public interface ConverterFactory<S, R> {
    <T extends R> Converter<S, T> getConverter(Class<T> var1);
}
TyperConverter
  • 定义类型转换方法的接口。通常(但不一定)与PropertyEditorRegistry接口一起实现,通常接口TypeConverter的实现是基于非线程安全的PropertyEditors类,因此也不是线程安全的
public interface TypeConverter {
	// 将参数中的var1转换成var2类型,从String到任何类型的转换通常使用	   	  		        PropertyEditor类的setAsText方法或ConversionService中的Spring Converter
    @Nullable
    <T> T convertIfNecessary(@Nullable Object var1, @Nullable Class<T> var2) throws TypeMismatchException;

	// 意义同上,增加了作为转换目标的方法参数,主要用于分析泛型类型,可能是null
    @Nullable
    <T> T convertIfNecessary(@Nullable Object var1, @Nullable Class<T> var2, @Nullable MethodParameter var3) throws TypeMismatchException;
	
	// 意义同上,增加了转换目标的反射field
    @Nullable
    <T> T convertIfNecessary(@Nullable Object var1, @Nullable Class<T> var2, @Nullable Field var3) throws TypeMismatchException;

    @Nullable
    default <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {
        throw new UnsupportedOperationException("TypeDescriptor resolution not supported");
    }
}
TypeConverterSupport
  • TypeConverter的基本实现类,同时也是BeanWrapperImpl类的依赖类
public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport implements TypeConverter {
   
    // 委托给TypeConverterDelegate来转换
    @Nullable
    TypeConverterDelegate typeConverterDelegate;

    public TypeConverterSupport() {
    }

    @Nullable
    public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException {
        return this.convertIfNecessary(value, requiredType, TypeDescriptor.valueOf(requiredType));
    }

    @Nullable
    public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable MethodParameter methodParam) throws TypeMismatchException {
        return this.convertIfNecessary(value, requiredType, methodParam != null ? new TypeDescriptor(methodParam) : TypeDescriptor.valueOf(requiredType));
    }

    @Nullable
    public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field) throws TypeMismatchException {
        return this.convertIfNecessary(value, requiredType, field != null ? new TypeDescriptor(field) : TypeDescriptor.valueOf(requiredType));
    }

    @Nullable
    public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {
        Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate");

        try {
            return this.typeConverterDelegate.convertIfNecessary((String)null, (Object)null, value, requiredType, typeDescriptor);
        } catch (IllegalStateException | ConverterNotFoundException var5) {
            throw new ConversionNotSupportedException(value, requiredType, var5);
        } catch (IllegalArgumentException | ConversionException var6) {
            throw new TypeMismatchException(value, requiredType, var6);
        }
    }
}
TypeConverterDelegate
  • 类型转换的委托类,所有类型转换的工作都由该类完成,即将属性转换为其他类型的Spring内部使用方法(内部实现: 先使用PropertyEditor转换器器转换,如果没找到对应的转换器器,会⽤ConversionService来进⾏行行对象转换
class TypeConverterDelegate {
    private static final Log logger = LogFactory.getLog(TypeConverterDelegate.class);
    private final PropertyEditorRegistrySupport propertyEditorRegistry;
    @Nullable
    private final Object targetObject;

    public TypeConverterDelegate(PropertyEditorRegistrySupport propertyEditorRegistry) {
        this(propertyEditorRegistry, (Object)null);
    }

    public TypeConverterDelegate(PropertyEditorRegistrySupport propertyEditorRegistry, @Nullable Object targetObject) {
        this.propertyEditorRegistry = propertyEditorRegistry;
        this.targetObject = targetObject;
    }

    @Nullable
    public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, Object newValue, @Nullable Class<T> requiredType) throws IllegalArgumentException {
        return this.convertIfNecessary(propertyName, oldValue, newValue, requiredType, TypeDescriptor.valueOf(requiredType));
    }

    @Nullable
    public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue, @Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException {
        PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
        ConversionFailedException conversionAttemptEx = null;
        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 conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
                } catch (ConversionFailedException var14) {
                    conversionAttemptEx = var14;
                }
            }
        }

        Object convertedValue = newValue;
        if (editor != null || requiredType != null && !ClassUtils.isAssignableValue(requiredType, newValue)) {
            if (typeDescriptor != null && requiredType != null && Collection.class.isAssignableFrom(requiredType) && newValue instanceof String) {
                TypeDescriptor elementTypeDesc = typeDescriptor.getElementTypeDescriptor();
                if (elementTypeDesc != null) {
                    Class<?> elementType = elementTypeDesc.getType();
                    if (Class.class == elementType || Enum.class.isAssignableFrom(elementType)) {
                        convertedValue = StringUtils.commaDelimitedListToStringArray((String)newValue);
                    }
                }
            }

            if (editor == null) {
                editor = this.findDefaultEditor(requiredType);
            }

            convertedValue = this.doConvertValue(oldValue, convertedValue, requiredType, editor);
        }

        boolean standardConversion = false;
        if (requiredType != null) {
            if (convertedValue != null) {
                if (Object.class == requiredType) {
                    return convertedValue;
                }

                if (requiredType.isArray()) {
                    if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
                        convertedValue = StringUtils.commaDelimitedListToStringArray((String)convertedValue);
                    }

                    return this.convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
                }

                if (convertedValue instanceof Collection) {
                    convertedValue = this.convertToTypedCollection((Collection)convertedValue, propertyName, requiredType, typeDescriptor);
                    standardConversion = true;
                } else if (convertedValue instanceof Map) {
                    convertedValue = this.convertToTypedMap((Map)convertedValue, propertyName, requiredType, typeDescriptor);
                    standardConversion = true;
                }

                if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
                    convertedValue = Array.get(convertedValue, 0);
                    standardConversion = true;
                }

                if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
                    return convertedValue.toString();
                }

                if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
                    if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
                        try {
                            Constructor<T> strCtor = requiredType.getConstructor(String.class);
                            return BeanUtils.instantiateClass(strCtor, new Object[]{convertedValue});
                        } catch (NoSuchMethodException var12) {
                            if (logger.isTraceEnabled()) {
                                logger.trace("No String constructor found on type [" + requiredType.getName() + "]", var12);
                            }
                        } catch (Exception var13) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Construction via String failed for type [" + requiredType.getName() + "]", var13);
                            }
                        }
                    }

                    String trimmedValue = ((String)convertedValue).trim();
                    if (requiredType.isEnum() && trim
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值