8 Jun 2023

Spring源码解析之类型转换

Java 提供的转换器 PropertyEditor(接口)、PropertyEditorSupport(可以继承的类)

  • #setAsText传入需要转换的string,重写PropertyEditorSupport方法改变类型转换
  • #getValue获取转换后的数据
  • 局限性:只支持从string向其他类型做转换。

具体demo如下:


public class StringToIntPropertiesEditor extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        this.setValue(Integer.valueOf(text));
    }

	 public static void main(String[] args) {
        StringToIntPropertiesEditor stringToIntPropertiesEditor = new StringToIntPropertiesEditor();
        stringToIntPropertiesEditor.setAsText("123");
        Object value = stringToIntPropertiesEditor.getValue();
        System.out.println(value.getClass().getTypeName());
    }

}

Spring提供的Convert

  • Converter<S, T>最基本的接口,这个接口的实现是线程安全的,可以共享。实现了所有的基本类型转换,常见的比如date/string/int/long …
  • 额外的接口ConditionalConverter,允许Converter、GenericConverter或ConverterFactory基于源和目标类型描述符的属性有条件地执行。
  • GenericConverterGenericConverter,用于在两个或多个类型之间进行转换的通用转换器接口。这是转换器中最灵活的SPI接口,但也是最复杂的。它是灵活的,因为GenericConverter可以支持多个源/目标类型对之间的转换(参见getConvertibleTypes())。此外,GenericConverter实现可以在类型转换过程中访问源/目标字段上下文。这允许解析源和目标字段元数据,如注释和泛型信息,这些元数据可用于影响转换逻辑。

写一个demo如下:把properties转换为string

@Component("conversionService")
public class PropertiesToStringConvert implements ConditionalGenericConverter {
    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        return Properties.class.equals(sourceType.getType()) && String.class.equals(targetType.getType());
    }

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(Properties.class, String.class));
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        Properties properties = (Properties)source;
        return properties.toString();
    }
}

 <util:properties id="context">
        <prop key="id">1</prop>
        <prop key="name">mercyblitz</prop>
 </util:properties>
 <bean id="user" class="xxx.UserInfo">
        <property name="id" value="1"/>
        <property name="name" value="test"/>
        <property name="context" ref="context"/>
    </bean>

    <bean id="convert" class="com.ynhuang.thinking.databinder.convert.PropertiesToStringConvert">

    </bean>

    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters" ref="convert" />
    </bean>

当然在spring中配置convertService除了ConversionServiceFactoryBean,还可以使用ConversionService,ConversionService在beanfactory refresh阶段就已经开始加载了,如果不指定,spring只会初始化默认的转换器,则新加的无效。

最后,只有转换器处理完成之后,才会完成整个的数据绑定,也就是在spring bean实例化完成阶段。


Tags:
0 comments