6.5 Spring3 类型转换

6.5 Spring3 类型转换

Spring3引入了core.convert包,提供了一个通用的类型转换系统。这个系统定义了一个SPI来实现类型转换逻辑。SPI就像API一样,用来在运行时执行类型转换。在Spring容器中,这个系统可以用来替代PropertyEditors,因为它也可以将bean的string属性值转换成所需的属性类型。在你的应用程序中,任何需要类型转换的地方都可以使用这些公共API。(下文中的Converter将被翻译成转换器)

Converter SPI

实现类型转换逻辑的SPI简单且是强类型的:

	package org.springframework.core.convert.converter;
	public interface Converter<S, T> {
		T convert(S source);
	}

想要创建你自己的Converter,只需要实现上面的接口。参数S是转换前的类型,而T则是转换后的类型。每次调用convert(S)时,参数(原值)不能为null。你的转换器可能会在转换失败时抛出异常。若是一个无效的原值,那么应该抛出一个IllegalArgumentException。并且确保你的转换器实现是线程安全的。

为了方便起见,在core.convert.support包中提供了一些converter的实现类。其中包括了String和Number以及其他常见类型之间的转换。可以将下面这个Converter的实现类——StringToInteger当成一个小例子来学习:

	package org.springframework.core.convert.support;

	final class StringToInteger implements Converter<String, Integer> {
		public Integer convert(String source) {
			return Integer.valueOf(source);
		}
	}

转换器工厂

当你需要集中一个完整的类结构的转换逻辑时,比如,从String到java.lang.Enum的转换,那么,实现ConverterFactory。

	package org.springframework.core.convert.converter;

	public interface ConverterFactory<S, R> {
		<T extends R> Converter<S, T> getConverter(Class<T> targetType);
	}

参数S是转换前的参数类型,而参数R是你要转换成的类的基类型,它定义了你能够转换的类的范围。然后需要实现getConverter(Class<T>),其中T是R的子类。

考虑下面的ConverterFactory ——StringToEnum:

	package org.springframework.core.convert.support;

	final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {

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

			public T convert(String source) {
				return(T) Enum.valueOf(this.enumType, source.trim());
			}
		}
	}

GenericConverter(泛型转换器)

当你需要一个复杂的转换器实现时,可以考虑GenericConverter接口。它拥有一个相对弱类型但却更加灵活的方法头,GenericConverter支持多个原类型和目标类型的转换。另外,当你在实现你的转换逻辑时,GenericConverter还能够让你使用原字段和目标字段的上下文。这个上下文允许被属性(field)注解驱动的类型转换,或者是被泛型信息定义的类型转换:

	package org.springframework.core.convert.converter;

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

		Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
	}

实现一个GenericConverter接口时,getConvertibleTypes()需要返回所支持的源类型和目标类型的配对(译者注:这个方法在ConversionServiceFactory的registerConverters调用,之后会被缓存),convert(Object,TypeDescriptor, TypeDescriptor)方法用来定义你的转换逻辑。源TypeDescriptor提供了对源字段的访问且包含了需要转换的原值。而目标TypeDescriptor则提供了对目标字段的访问且用于放置转换后的值。

关于GenericConverter一个比较典型的例子就是Java数组类型和集合类型之间的转换。这个ArrayToCollectionConverter通过内省目标集合类型的字段来决定集合的元素类型。这允许源数组中的每一个元素在集合被设置到目标字段之前被转换成集合元素类型。

注意:由于GenericConverter是一个更为复杂的SPI接口,只有当你需要的时候再去使用它。对于基本的类型转换,优先使用Converter或者是ConverterFactory。

带条件的GenericConverter

有时你只想在满足某个特定条件的时候才执行一个Converter。比如,只有当目标属性上有一个特定的注解时才去执行一个Converter,或者当目标类中定义了一个特定的方法,比如一个静态的valueOf方法时,才去执行一个Converter。那么你可以使用ConditionalGenericConverter,它是GenericConverter的子接口,允许你定义刚才提到的那些匹配条件:

	public interface ConditionalGenericConverter extends GenericConverter {
		boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
	}

关于ConditionalGenericConverter的一个典型的例子是EntityConverter。它提供了一个持久的实体标识符和一个实体引用之间的转换。这样的EntityConverter可能只会匹配那些定义了一个静态finder方法(比如findAccount(Long))的目标实体。你需要在实现matches(TypeDescriptor,TypeDescriptor)方法时来检查是否存在这样的finder方法。

(译者注:关于matches方法,是在第一次需要类型转换的时候会被调用,之后就会被缓存下来)

ConversionService API

ConversionService为运行时执行类型转换逻辑定义了一个统一的API。Converters通常在这层门面接口之后运行:

	package org.springframework.core.convert;

	public interface ConversionService {
		boolean canConvert(Class<?> sourceType, Class<?> targetType);

		<T> T convert(Object source, Class<T> targetType);

		boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);

		Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
	}

大多数ConversionService实现类也实现了ConverterRegistry接口。ConverterRegistry为注册converters提供了一个SPI。实际上,在ConversionService实现里会将类型转换的逻辑委托给注册了的converters。

core.convert.support包里提供了一个健壮的ConversionService实现。GenericConversionService作为一个通用的实现类,可以满足大多数情况。ConversionServiceFactory提供了一个方便的创建常用的ConversionService配置的工厂。

配置一个ConversionService

ConversionService是一个无状态的对象,且被设计成在应用启动时就被实例化,并在多个线程间共享。在Spring应用中一个典型的情况,为每个Spring容器(或是ApplicationContext)配置一个ConversionService实例。这个ConversionService将会生存在Spring中,并且在需要类型转换的时候被使用。你也可以将它注入到你的beans中并直接地调用它。

注意:如果Spring中没有注册ConversionService,那么它将会使用原始的基于PropertyEditor的系统。

为了在Spring中注册一个默认的ConversionService,添加下面的bean定义并且将它的id设置为conversionService:

	<bean id="conversionService"
		class="org.springframework.context.support.ConversionServiceFactoryBean"/>

默认的ConversionServcice能够转换strings、number、enums、collections、maps和其他常见类型。通过设置converters属性,可以用你自定义的converters来补充或覆盖默认的converters。这个converters属性的值必须要实现Converter、ConverterFactory或是GenericConverter接口。

	<bean id="conversionService"
		class="org.springframework.context.support.ConversionServiceFactoryBean">
		<property name="converters">
			<list>
				<bean class="example.MyCustomConverter" />
			</list>
		</property>
	</bean>

在Spring MVC应用中使用ConversionService也是很常见的。阅读“ConfiguringFormatting in Spring MVC”这一节获得更多关于如何使用<mvc:annotation-driven/>的详细信息。

在某些场景下你可能希望在类型转换中应用格式化。阅读“FormatterRegistry SPI”这一节可以获得使用FormattingConversionServiceFactoryBean.的详细信息。

使用编程式的ConversionService

使用编程式的ConversionService实例,只需要注入一个ConversionService的引用即可,就像你注入其他bean一样:

	@Service
	public class MyService {

		@Autowired
		public MyService(ConversionService conversionService) {
			this.conversionService = conversionService;
		}

		public void doIt() {
			this.conversionService.convert(...)
		}
	}
时间: 2024-08-08 01:07:43

6.5 Spring3 类型转换的相关文章

spring(7)--注解式控制器的数据验证、类型转换及格式化

7.1.简介 在编写可视化界面项目时,我们通常需要对数据进行类型转换.验证及格式化. 一.在Spring3之前,我们使用如下架构进行类型转换.验证及格式化: 流程: ①:类型转换:首先调用PropertyEditor的setAsText(String),内部根据需要调用setValue(Object)方法进行设置转换后的值: ②:数据验证:需要显示调用Spring的Validator接口实现进行数据验证: ③:格式化显示:需要调用PropertyEditor的getText进行格式化显示. 使用

SpringMVC数据格式化,介绍了解一下

7.3.数据格式化在如Web /客户端项目中,通常需要将数据转换为具有某种格式的字符串进行展示,因此上节我们学习的数据类型转换系统核心作用不是完成这个需求,因此Spring3引入了格式化转换器(Formatter SPI) 和格式化服务API(FormattingConversionService)从而支持这种需求.在Spring中它和PropertyEditor功能类似,可以替代PropertyEditor来进行对象的解析和格式化,而且支持细粒度的字段级别的格式化/解析. Formatter

More Effective C++

条款一:指针与引用的区别 指针与引用看上去完全不同(指针用操作符'*'和'->',引用使用操作符'.'),但是它们似乎有相同的功能.指针与引用都是让你间接引用其他对象.你如何决定在什么时候使用指针,在什么时候使用引用呢? 首先,要认识到在任何情况下都不能用指向空值的引用.一个引用必须总是指向某些对象.因此如果你使用一个变量并让它指向一个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量.相反,如果变量肯定指向一个对象,例如你的设计不允许变量为

Spring3 MVC 类型转换

1. Spring在进行类型转化都是基于java.beans.PropertyEditor接口. 2. 可以使用@InitBinder来进行对单个controller的类型进行操作,比如添加Date类型的转换器: @InitBinder public void initBinder(WebDataBinder binder) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.se

Spring MVC 之类型转换(五)

虽然SpringMVC可以自动绑定多种数据类型,但是有时候有些特殊的数据类型还是会在绑定时发生错误,需要我们自己书写类型转换完成绑定. SpringMVC中提供两种绑定方式:以时间转换为例. 1.属性编辑器(传统方式) 控制器: 1 @RequestMapping(value="/login.do") 2 public String login(UserBean user){ 3 log.info(user.getUsername()); 4 log.info(user.getBirt

【第一章】 Spring概述 ——跟我学Spring3

1.1.1  Spring是什么 Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发.应用程序是由一组相互协作的对象组成.而在传统应用程序开发中,一个完整的应用是由一组相互协作的对象组成.所以开发一个应用除了要开发业务逻辑之外,最多的是关注如何使这些对象协作来完成所需功能,而且要低耦合.高内聚.业务逻辑开发是不可避免的,那如果有个框架出来帮我们来创建对象及管理这些对象之间的依赖关系.可能有人说了

开涛spring3(3.1) - DI的配置使用

3.1.1  依赖和依赖注入 传统应用程序设计中所说的依赖一般指“类之间的关系”,那先让我们复习一下类之间的关系: 泛化:表示类与类之间的继承关系.接口与接口之间的继承关系: 实现:表示类对接口的实现: 依赖:当类与类之间有使用关系时就属于依赖关系,不同于关联关系,依赖不具有“拥有关系”,而是一种“相识关系”,只在某个特定地方(比如某个方法体内)才有关系. 关联:表示类与类或类与接口之间的依赖关系,表现为“拥有关系”:具体到代码可以用实例变量来表示: 聚合:属于是关联的特殊情况,体现部分-整体关

SpringMVC之类型转换Converter

SpringMVC之类型转换Converter 1.1     目录 1.1      目录 1.2      前言 1.3      Converter接口 1.4      ConversionService接口 1.5      ConverterFactory接口 1.6      GenericConverter接口 1.6.1     概述 1.6.2     ConditionalGenericConverter 接口 1.2     前言 在以往我们需要SpringMVC为我们自

6.校验,数据绑定和类型转换(6.1 - 6.3)

6.校验,数据绑定和类型转换 6.1 介绍 关于是否把数据校验看做业务逻辑,有支持也有反对.Spring设计了一套校验规则(包括数据绑定)并没有否定任何一种观点.特定地校验不应该依赖于web层,而是应该易于局部化而且可以嵌入到任何可用的校验器(validator)中.考虑到以上几点,Spring提出了一个校验器(Validator)接口,它是校验的基础并且非常出众,而最关键的是它在每一层中都可以使用. 数据绑定对于将用户的输入动态绑定到实体上非常有用.Spring提供数据绑定器(DataBind