Spring 3介绍的core.convert包提供了对通用类型的转换,它定义了SPI来实现类型转换逻辑,以及在运行时执行类型转换的API,在Spring系统中,此系统可用用作PropertyEditors的替代方法,他将外部bean属性字符串转换为所需的属性类型,公共API可以在任何需要类型转换的应用程序中使用。
a.converter的使用 例子:https://blog.csdn.net/fang_qiming/article/details/79237766
b.转化工厂:
当需要集中整个类层次结构的转换逻辑时,例如需要将字符串转化为枚举类型,可以实现ConverterFactory来批量转换
例子:
1.定义ConverterFactory实现类
@Component
public class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
@Override
public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToEnumConverter(targetType);
}
private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> {
private Class<T> enumType;
public StringToEnumConverter(Class<T> enumType) {
this.enumType = enumType;
}
@Override
public T convert(String source) {
return (T)Enum.valueOf(this.enumType, source.trim());
}
}
}
2.定义相应的枚举类型
public enum TestEnum {
WAITING((byte) 1, "等待确认"),
CANCELED((byte) 2, "取消"),
COMPLETED((byte) 3, "已完成");
@Getter
private Byte code;
@Getter
private String desc;
TestEnum(Byte code, String desc) {
this.code = code;
this.desc = desc;
}
}
public enum HelloEnum {
WAITING1((byte) 1, "等待确认111111"),
CANCELED2((byte) 2, "取消1111111"),
COMPLETED3((byte) 3, "已完成1111111");
@Getter
private Byte code;
@Getter
private String desc;
HelloEnum(Byte code, String desc) {
this.code = code;
this.desc = desc;
}
}
3.将转换对象注入容器
@Bean
public Converter<String, TestEnum> converterTestEnum() {
return stringToEnumConverterFactory.getConverter(TestEnum.class);
}
@Bean
public Converter<String, HelloEnum> converterHelloEnum() {
return stringToEnumConverterFactory.getConverter(HelloEnum.class);
}
4.编写测试类
/**
* 127.0.0.1:8886/get5?text=WAITING
* @param text
* @return
*/
@GetMapping(value = "/get4")
public Object get(TestEnum text) {
System.out.println(text.getDesc());
return "hello";
}
/**
* 127.0.0.1:8886/get5?text=WAITING1
* @param text
* @return
*/
@GetMapping(value = "/get5")
public Object get(HelloEnum text) {
System.out.println(text.getDesc());
return "hello";
}
c.通用转换器 GenericConverter
当需要复杂的转换器实现时,请使用GenericConverter接口,使用更灵活但不太强类型的签名让GenericConverter在多个源和目标类型之间进行转换,另外GenericConverter可以在实现转换逻辑时使用可用的源和目标字段上下文,此上下文类允许通过字段注解或在字段签名上声明的一般信息来驱动类型转换。
例子:
1.编写通用转换实现类
@Component
public class MyConverter implements GenericConverter {
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
//编写转化的支持的类型对
ConvertiblePair convertiblePair = new ConvertiblePair(String.class, TestEnum.class);
Set<ConvertiblePair> set = new HashSet();
set.add(convertiblePair);
return set;
}
/**
* 此处实现转换逻辑
*
* @param o sourceType的值
* @param sourceType String的类型抽象
* @param targetType TestEnum类型抽象
* @return
*/
@Override
public Object convert(Object o, TypeDescriptor sourceType, TypeDescriptor targetType) {
return TestEnum.valueOf((String) o);
}
}
2.编写测试代码
/**
* 127.0.0.1:8886/get4?text=WAITING
* @param text
* @return
*/
@GetMapping(value = "/get4")
public Object get(TestEnum text) {
System.out.println(text.getDesc());
return "hello";
}
Java数组和集合之间转换的转换器是GenericConverter应用的例子,其中ArrayToCollectionConver内部申明目标集合类型用于解析集合类型的字段,他允许在目标字段上设置集合之前,将源数组中的每个元素转换为集合元素类型。因为通用转换器适宜复杂的SPI接口,直接使用Converter和ConverterFactory基本能满足类型转换的需要。
d.ConditionalGenericConverter 通用条件转换器
有时可能只想在特定条件为真时才执行转换器,例如在特定注解的目标上使用转换器,或者在一个特定目标类方法中执行转换器。
ConditionalGenericConverter 是GenericConverter和ConditionalConverter接口的组合,允许自定义匹配条件。
public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
}
用于持久实体标识符和实体引用之间转换的EntityConverter是ConditionalGenericConverter引用的例子。如果目标实体类型申明静态查找器方法,那么EntityConverter只对匹配的生效,开发者可以实现matches方法以自信finder方法来检查是否匹配。
e.ConversionService API
ConversionService 定义了统一的API,用于在运行时执行类型转换逻辑,转换器通常在此接口后面执行。
大多数Conversion实现也实现了ConverterRegistry,它提供了一个用于注册转换器的SPI,在内部,ConversionService 实现委托其注册的转换器来执行类型转换逻辑。
配置ConversionService
ConversionService 是一个无状态对象,在应用程序启动时就会实例化,可以被多个线程共享,在Spring应用程序中,通常每个Spring容器配置一个ConversionService 实例,该ConversionService 将被Spring获取,然后在框架需要执行类型转换时使用,也可以将ConversionService 插入任意bean并直接调用他。
注意 如果Spring没有注册ConversionService ,就会使用原始的PropertyEditor系统
要使用Spring默认注册ConversionService ,可以采用如下配置
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"></bean>
默认的ConversionService 可以在字符串,数字,枚举,集合,映射和其它常见类型之间进行转换,如果要使用自定义的转换器来补充或者覆盖默认转换器,请设置“converters”属性,Property值可以实现任意的转换器,ConverterFactory 或 GenericConverter接口
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="example.MyCustomConverter"></bean>
</set>
</property>
</bean>
如果想用编程的方式使用ConversionService实例,只需向他注入一个引用,就像对任何其他bean一样
@Autowired
private ConversionService conversionService;
对于多数用例,可以使用指定targetType的转换方法,但他不能处理复杂类型,例如参数化元素的集合,如果想使用编程的方式将整数列表转换为字符串列表,则需要提供源和目标类型的正规定义。
幸运的是TypeDescriptor提供了一些选项用于实现这样的功能
DefaultConversionService cs=new DefaultConversionService();
List<Integer> input=...
cs.convert(input,TypeDescriptor.forObject(input),TypeDescriptor.collection(List.class,TypeDescriptor.valueOf(String.class)));
注意:DefaultConversionService自动注册了适合大多数环境的转换器,包括集合转换器,标量转换器以及字符串转换器的基本对象。使用DefaultConversionService类上的静态addDefaultConverters方法可以向任意ConverterRegistry注册相同的转换器。
值类型的转换器将被数组和集合重用,因此不需要创建特定从S集合转换为T的集合的转换器,前提是标准集合处理是合适的。