概述
Spring Type Conversion(Spring类型转换)
1:概述:
Spring3引入了core.convert包,提供了通用类型转换系统,定义了实现类型转换和运行时执行类型的SPI。
在Spring3.0之前,提供的PropertyEditor来将外部化bean属性值字符串转换成必需的实现类型。
2:Converter SPI
/*** A converter converts a source object of type {@codeS} to a target of type {@codeT}.
*
*
Implementations of this interface are thread-safe and can be shared.
*
*
Implementations may additionally implement {@linkConditionalConverter}.
*
*@authorKeith Donald
*@since3.0
*@param the source type
*@param the target type*/@FunctionalInterfacepublic interface Converter{
/*** Convert the source object of type {@codeS} to target type {@codeT}.
*@paramsource the source object to convert, which must be an instance of {@codeS} (never {@codenull})
*@returnthe converted object, which must be an instance of {@codeT} (potentially {@codenull})
*@throwsIllegalArgumentException if the source cannot be converted to the desired target type*/@Nullable
T convert(S source);
}
实现自定义的类型转换可以实现Converter接口。但是如果S是集合或者数组转换为T的集合或者数组,
建议参考诸如ArrayToCollectionConverter实现。前提是已经注册了委托数组或集合转换器。例如,
DefaultConversionService实现。
Converter.convert(S source)中source确保不能为null,否则转换器可能抛出异常如果转换失败。具体
说,应该会抛出IllegalArgumentException报告不合理的转换源。确保Converter实现是线程安全。
在core.convert.support包下,注册了常见了类型转换器。例如:
/*** Converts from a String any JDK-standard Number implementation.
*
*
Support Number classes including Byte, Short, Integer, Float, Double, Long, BigInteger, BigDecimal. This class
* delegates to {@linkNumberUtils#parseNumber(String, Class)} to perform the conversion.
*
*@authorKeith Donald
*@since3.0
*@seejava.lang.Byte
*@seejava.lang.Short
*@seejava.lang.Integer
*@seejava.lang.Long
*@seejava.math.BigInteger
*@seejava.lang.Float
*@seejava.lang.Double
*@seejava.math.BigDecimal
*@seeNumberUtils*/
final class StringToNumberConverterFactory implements ConverterFactory{
@Overridepublic Converter getConverter(ClasstargetType) {return new StringToNumber<>(targetType);
}
private static final class StringToNumber implements Converter{
private final ClasstargetType;
public StringToNumber(ClasstargetType) {this.targetType =targetType;
}
@OverridepublicT convert(String source) {if(source.isEmpty()) {return null;
}return NumberUtils.parseNumber(source, this.targetType);
}
}
}
3:ConverterFactory
当你需要集中整理类层次结构的类型转换器,可以使用ConverterFactory。例如StringToNumberConverterFactory,
该接口定义如下,当你需要范围转换器,可以转换这些对象从S类型转换成R的子类型。使用该接口。
/*** A factory for "ranged" converters that can convert objects from S to subtypes of R.
*
*
Implementations may additionally implement {@linkConditionalConverter}.
*
*@authorKeith Donald
*@since3.0
*@seeConditionalConverter
*@param the source type converters created by this factory can convert from
*@param the target range (or base) type converters created by this factory can convert to;
* for example {@linkNumber} for a set of number subtypes.*/
public interface ConverterFactory{
/*** Get the converter to convert from S to target type T, where T is also an instance of R.
*@param the target type
*@paramtargetType the target type to convert to
*@returna converter from S to T*/
Converter getConverter(ClasstargetType);
}/*** Converts from a String any JDK-standard Number implementation.
*
*
Support Number classes including Byte, Short, Integer, Float, Double, Long, BigInteger, BigDecimal. This class
* delegates to {@linkNumberUtils#parseNumber(String, Class)} to perform the conversion.
*
*@authorKeith Donald
*@since3.0
*@seejava.lang.Byte
*@seejava.lang.Short
*@seejava.lang.Integer
*@seejava.lang.Long
*@seejava.math.BigInteger
*@seejava.lang.Float
*@seejava.lang.Double
*@seejava.math.BigDecimal
*@seeNumberUtils*/
final class StringToNumberConverterFactory implements ConverterFactory{
@Overridepublic Converter getConverter(ClasstargetType) {return new StringToNumber<>(targetType);
}
private static final class StringToNumber implements Converter{
private final ClasstargetType;
public StringToNumber(ClasstargetType) {this.targetType =targetType;
}
@OverridepublicT convert(String source) {if(source.isEmpty()) {return null;
}return NumberUtils.parseNumber(source, this.targetType);
}
}
}
4:GenericConverter
GenericConverter提供多种源和目标类型之间转换,比Converter更灵活但是对类型要求不高。它提供了实现
转换逻辑的源和目标上下文。 这样的上下文允许类型转换由字段注释或在字段签名上声明的通用信息驱动。接口
如下:
packageorg.springframework.core.convert.converter;
public interfaceGenericConverter {
public SetgetConvertibleTypes();
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
ConvertiblePair持有转换源和目标类型对。convert(Object, TypeDescriptor, TypeDescriptor)。
源TypeDescriptor提供对保存正在转换的值的源字段的访问。 目标TypeDescriptor提供对要设置转换值的目标字段的访问。TypeDescriptor类是关于要转换类型的上下文。
一个好的实例是GenericConverter在Java数组和集合之间转换。例如ArrayToCollectionConverter。
注意
因为GenericConverter是一个更复杂的SPI接口,所以只有在需要时才应该使用它.喜欢Converter或ConverterFactory以满足基本的类型转换需求。
5:ConditionalGenericConverter
该接口是一个带有判断条件的类型转换器。该接口是GenericConverter和ConditionalConverter的组合。
/*** A {@linkGenericConverter} that may conditionally execute based on attributes
* of the {@codesource} and {@codetarget} {@linkTypeDescriptor}.
*
*
See {@linkConditionalConverter} for details.
*
*@authorKeith Donald
*@authorPhillip Webb
*@since3.0
*@seeGenericConverter
*@seeConditionalConverter*/
public interface ConditionalGenericConverter extendsGenericConverter, ConditionalConverter {
}/*** A {@linkGenericConverter} that may conditionally execute based on attributes
* of the {@codesource} and {@codetarget} {@linkTypeDescriptor}.
*
*
See {@linkConditionalConverter} for details.
*
*@authorKeith Donald
*@authorPhillip Webb
*@since3.0
*@seeGenericConverter
*@seeConditionalConverter*/
public interface ConditionalGenericConverter extendsGenericConverter, ConditionalConverter {
}
ConditionalGenericConverter的一个好示例是StringToCollectionConverter
/*** Converts a comma-delimited String to a Collection.
* If the target collection element type is declared, only matches if
* {@codeString.class} can be converted to it.
*
*@authorKeith Donald
*@authorJuergen Hoeller
*@since3.0*/
final class StringToCollectionConverter implementsConditionalGenericConverter {
private finalConversionService conversionService;
publicStringToCollectionConverter(ConversionService conversionService) {this.conversionService =conversionService;
}
@Overridepublic SetgetConvertibleTypes() {return Collections.singleton(new ConvertiblePair(String.class, Collection.class));
}
@Overridepublic booleanmatches(TypeDescriptor sourceType, TypeDescriptor targetType) {return (targetType.getElementTypeDescriptor() == null ||
this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor()));
}
@Override
@NullablepublicObject convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {if (source == null) {return null;
}
String string=(String) source;
String[] fields=StringUtils.commaDelimitedListToStringArray(string);
TypeDescriptor elementDesc=targetType.getElementTypeDescriptor();
Collection target =CollectionFactory.createCollection(targetType.getType(),
(elementDesc!= null ? elementDesc.getType() : null), fields.length);
if (elementDesc == null) {for(String field : fields) {
target.add(field.trim());
}
}else{for(String field : fields) {
Object targetElement= this.conversionService.convert(field.trim(), sourceType, elementDesc);
target.add(targetElement);
}
}returntarget;
}
}
6:ConversionService API
ConversionService定义了一个统一的API,用于在运行时执行类型转换逻辑. 转换器通常在以下Facade接口后面执行。
packageorg.springframework.core.convert;
public interfaceConversionService {
boolean canConvert(Class> sourceType, Class>targetType);
T convert(Object source, ClasstargetType);
booleancanConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
大多数ConversionService实现,同样也实现了ConverterRegistry,该接口提供了SPI来注册Converters.
在内部,ConversionService的实现,容器委托它来注册转换器来执行转换逻辑。
core.convert.support提供一个强大的ConversionService实现,该实现是GenericConversionSer
,它适用于大多数转换器环境实现。ConversionServiceFactory来创建普通的ConversionService
配置。
7:配置ConversionService
ConversionService被设计成无状态对象,在容器启动时被实例化,在多线程间进行共享(线程安全)。
在Spring应用中,可以自定义类型转换器。当需要框架进行类型转换时,Spring会选择合适的类型转换器
使用。你也可以注入ConversionService到beans或者直接调用。
注意
如果没有ConversionService注册到Spring容器,基于的PropertyEditor实现的类型转换会被使用。
使用如下的方式,注册默认ConversionService进Spring容器中:
public classConvertersConfiguration {
@Bean(name= "conversionService")publicConversionServiceFactoryBean conversionServiceFactory() {
ConversionServiceFactoryBean conversionServiceFactoryBean= newConversionServiceFactoryBean();returnconversionServiceFactoryBean;
}
}
默认的ConversionService可以在字符串,数字,枚举,集合,映射和其他常见类型之间进行转换。要使用您自己的自定义转换器补充或覆盖默认转换器,请设置converter属性.属性值可以实现任何Converter,ConverterFactory或GenericConverter接口。默认ConversionService实现是DefaultConversionService。
public classConvertersConfiguration {
@Bean(name= "conversionService")publicConversionServiceFactoryBean conversionServiceFactory() {
ConversionServiceFactoryBean conversionServiceFactoryBean= newConversionServiceFactoryBean();//实现自定义的类型转换器
conversionServiceFactoryBean.setConverters(Collections.singleton(newStringToDateConverter()));returnconversionServiceFactoryBean;
}
}
也可以使用ConversionService在Spring MVC应用中,参考WebMvcConfigurationSupport类,该类方法
addFormatters(FormatterRegistry registry)可以注册自定义的converters。
在某些情况,希望在类型转换期间需要格式化,参考FormatterRegistry。
在程序中使用ConversionService
@Servicepublic classMyService {
@AutowiredpublicMyService(ConversionService conversionService) {this.conversionService =conversionService;
}
public voiddoIt() {this.conversionService.convert(...)
}
}
8:Spring域属性格式化
core.convert是一个通用的类型转换系统.它提供了统一的ConversionService API以及强类型转换器SPI,用于实现从一种类型到另一种类型的转换逻辑.Spring容器使用这个系统来绑定bean属性值。额外的,还要SpEL和
DataBinder。Spring3引入了Formatter SPI来实现格式化属性值。ConversionService为两个SPI提供统一的类型转换API。
(1):Formatter SPI
/*** Formats objects of type T.
* A Formatter is both a Printer and a Parser for an object type.
*
*@authorKeith Donald
*@since3.0
*@param the type of object this Formatter formats*/
public interface Formatter extends Printer, Parser{
}
/*** Parses text strings to produce instances of T.
*
*@authorKeith Donald
*@since3.0
*@param the type of object this Parser produces*/@FunctionalInterfacepublic interface Parser{
/*** Parse a text String to produce a T.
*@paramtext the text string
*@paramlocale the current user locale
*@returnan instance of T
*@throwsParseException when a parse exception occurs in a java.text parsing library
*@throwsIllegalArgumentException when a parse exception occurs*/T parse(String text, Locale locale)throwsParseException;
}
/*** Prints objects of type T for display.
*
*@authorKeith Donald
*@since3.0
*@param the type of object this Printer prints*/@FunctionalInterfacepublic interface Printer{
/*** Print the object of type T for display.
*@paramobject the instance to print
*@paramlocale the current user locale
*@returnthe printed text string*/String print(T object, Locale locale);
}
(2):Annotation-Driven Formatting
域格式化可以通过域类型或者注解配置.为了绑定注解在一个Formatter,实现AnnotationFormatterFactory.
packageorg.springframework.format;
/*** A factory that creates formatters to format values of fields annotated with a particular
* {@linkAnnotation}.
*
*
For example, a {@codeDateTimeFormatAnnotationFormatterFactory} might create a formatter
* that formats {@codeDate} values set on fields annotated with {@code@DateTimeFormat}.
*
*@authorKeith Donald
*@since3.0
*@param the annotation type that should trigger formatting*/
public interface AnnotationFormatterFactory{
Set>getFieldTypes();
Printer> getPrinter(A annotation, Class>fieldType);
Parser> getParser(A annotation, Class>fieldType);
}
例如实现NumberFormatAnnotationFormatterFactory,绑定@NumberFormat注解到Formatter。public class NumberFormatAnnotationFormatterFactory extendsEmbeddedValueResolutionSupportimplements AnnotationFormatterFactory{
@Overridepublic Set>getFieldTypes() {returnNumberUtils.STANDARD_NUMBER_TYPES;
}
@Overridepublic Printer getPrinter(NumberFormat annotation, Class>fieldType) {returnconfigureFormatterFrom(annotation);
}
@Overridepublic Parser getParser(NumberFormat annotation, Class>fieldType) {returnconfigureFormatterFrom(annotation);
}
private FormatterconfigureFormatterFrom(NumberFormat annotation) {
String pattern=resolveEmbeddedValue(annotation.pattern());if(StringUtils.hasLength(pattern)) {return newNumberStyleFormatter(pattern);
}else{
Style style=annotation.style();if (style ==Style.CURRENCY) {return newCurrencyStyleFormatter();
}else if (style ==Style.PERCENT) {return newPercentStyleFormatter();
}else{return newNumberStyleFormatter();
}
}
}
}
(3):格式化注解API
DateTimeFormat和NumberFormat。
(4):FormatterRegistry SPI
FormatterRegistry是用来注册formatters 和 converters的SPI。FormattingConversionService
是FormatterRegistry一个实现,可以支持大多数环境。可以通过FormattingConversionServiceFactoryBean
来配置。也可以通过Spring's DataBinder和SpEL。
packageorg.springframework.format;
public interface FormatterRegistry extendsConverterRegistry {
void addFormatterForFieldType(Class> fieldType, Printer> printer, Parser>parser);
void addFormatterForFieldType(Class> fieldType, Formatter>formatter);
void addFormatterForFieldType(Formatter>formatter);
void addFormatterForAnnotation(AnnotationFormatterFactory, ?>factory);
}
(5):FormatterRegistrar SPI
FormatterRegistrar是通过FormatterRegistry注册formatters和converters的SPI。
packageorg.springframework.format;
public interfaceFormatterRegistrar {
voidregisterFormatters(FormatterRegistry registry);
}
9:在Spring MVC配置Formatting
Configuration
@Slf4jpublic class WebConfiguration extendsWebMvcConfigurationSupport {
@Overrideprotected voidaddFormatters(FormatterRegistry registry) {
registry.addConverter(newStringToDateConverter());
}
}
10:配置全局的Date和时间Format
JodaTimeFormatterRegistrar和DateFormatterRegistrar,使用Joda需要引入joda库
配置如下:
@Configurationpublic classAppConfig {
@BeanpublicFormattingConversionService conversionService() {
//Use the DefaultFormattingConversionService but do not register defaults
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false);
//Ensure @NumberFormat is still supported
conversionService.addFormatterForFieldAnnotation(newNumberFormatAnnotationFormatterFactory());
//Register date conversion with a specific global format
DateFormatterRegistrar registrar = newDateFormatterRegistrar();
registrar.setFormatter(new DateFormatter("yyyyMMdd"));
registrar.registerFormatters(conversionService);
returnconversionService;
}
}
注意
Joda-Time提供不同类型表示日期date,time,datetime,需要通过JodaTimeFormatterRegistrar进行
注册。或者使用DateTimeFormatterFactoryBean来进行创建formatters。
如果您使用Spring MVC,请记住明确配置使用的转换服务.对于基于Java的@Configuration,这意味着扩展WebMvcConfigurationSupport类并覆盖mvcConversionService()方法.对于XML,您应该使用mvc:annotation-driven元素的conversion-service属性。 有关详细信息,请参阅转换和格式。
最后
以上就是端庄萝莉为你收集整理的java建一个conversion_Spring Type Conversion(Spring类型转换)的全部内容,希望文章能够帮你解决java建一个conversion_Spring Type Conversion(Spring类型转换)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复