Spring Core 之 Type Conversion(类型转换)

Spring 3 introduced a core.convert package that provides a general type conversion system. The system defines an SPI to implement type conversion logic and an API to perform type conversions at runtime. Within a Spring container, you can use this system as an alternative to PropertyEditor implementations to convert externalized bean property value strings to the required property types. You can also use the public API anywhere in your application where type conversion is needed.

Spring 3 引入了一个 core.convert 包,它提供了一个通用的类型转换系统。系统定义了一个 SPI 来实现类型转换逻辑和一个 API 来在运行时执行类型转换。在 Spring 容器中,您可以使用此系统作为 PropertyEditor 实现的替代方案,将外部化的 bean 属性值字符串转换为所需的属性类型。你还可以在应用程序中需要类型转换的任何位置使用公共 API。

一、Converter SPI(转换器SPI)

The SPI to implement type conversion logic is simple and strongly typed, as the following interface definition shows:

实现类型转换逻辑的SPI简单且强类型,如下接口定义所示:

package org.springframework.core.convert.converter;

public interface Converter<S, T> {

    T convert(S source);
}

To create your own converter, implement the Converter interface and parameterize S as the type you are converting from and T as the type you are converting to. You can also transparently apply such a converter if a collection or array of S needs to be converted to an array or collection of T, provided that a delegating array or collection converter has been registered as well (which DefaultConversionService does by default).

For each call to convert(S), the source argument is guaranteed to not be null. Your Converter may throw any unchecked exception if conversion fails. Specifically, it should throw an IllegalArgumentException to report an invalid source value. Take care to ensure that your Converter implementation is thread-safe.

Several converter implementations are provided in the core.convert.support package as a convenience. These include converters from strings to numbers and other common types. The following listing shows the StringToInteger class, which is a typical Converter implementation:

要创建你自己的转换器,需实现 Converter 接口并将 S 参数化为你要转换的类型,并将 T 参数化为你要转换到的类型。如果需要将 S 的集合或数组转换为 T 的数组或集合,也可以透明地应用此类转换器,前提是委托数组或集合转换器也已注册(默认情况下 DefaultConversionService 会这样做)。

对于每次调用 convert(S),源参数需保证不为空。如果转换失败,你的转换器可能会抛出任何未经检查的异常。具体来说,它应该抛出一个 IllegalArgumentException 来报告一个无效的源值。请注意确保你的 Converter 实现是线程安全的。

为方便起见,core.convert.support 包中提供了几个转换器实现。这些包括从字符串到数字和其他常见类型的转换器。下面的清单显示了 StringToInteger 类,它是一个典型的 Converter 实现:

package org.springframework.core.convert.support;

final class StringToInteger implements Converter<String, Integer> {

    public Integer convert(String source) {
        return Integer.valueOf(source);
    }
}

二、Using ConverterFactory(使用ConverterFactory)

When you need to centralize the conversion logic for an entire class hierarchy (for example, when converting from String to Enum objects), you can implement ConverterFactory, as the following example shows:

当你需要集中整个类层次结构的转换逻辑时(例如,从 String 对象转换为 Enum 对象时),您可以实现 ConverterFactory,如下例所示:

package org.springframework.core.convert.converter;

public interface ConverterFactory<S, R> {

    <T extends R> Converter<S, T> getConverter(Class<T> targetType);
}

Parameterize S to be the type you are converting from and R to be the base type defining the range of classes you can convert to. Then implement getConverter(Class), where T is a subclass of R.Consider the StringToEnumConverterFactory as an example:

参数S是你要转换的类型,并将 R 参数化为定义您可以转换为的类范围的基类型。然后实现 getConverter(Class),其中 T 是 R 的子类。以 StringToEnumConverterFactory 为例:

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

三、Using GenericConverter(使用 GenericConverter)

When you require a sophisticated Converter implementation, consider using the GenericConverter interface. With a more flexible but less strongly typed signature than Converter, a GenericConverter supports converting between multiple source and target types. In addition, a GenericConverter makes available source and target field context that you can use when you implement your conversion logic. Such context lets a type conversion be driven by a field annotation or by generic information declared on a field signature. The following listing shows the interface definition of GenericConverter:

当你需要复杂的 Converter 实现时,请考虑使用 GenericConverter 接口。其具有比 Converter 更灵活但类型更弱的签名,一个 GenericConverter 支持在多个源和目标类型之间进行转换。此外,GenericConverter 使你可以在实现转换逻辑时使用的源和目标字段上下文可用。这样的上下文允许类型转换由字段注释或在字段签名上声明的通用信息驱动。以下代码显示了 GenericConverter 的接口定义:

package org.springframework.core.convert.converter;

public interface GenericConverter {

    public Set<ConvertiblePair> getConvertibleTypes();

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

To implement a GenericConverter, have getConvertibleTypes() return the supported source→target type pairs. Then implement convert(Object, TypeDescriptor, TypeDescriptor) to contain your conversion logic. The source TypeDescriptor provides access to the source field that holds the value being converted. The target TypeDescriptor provides access to the target field where the converted value is to be set.

A good example of a GenericConverter is a converter that converts between a Java array and a collection. Such an ArrayToCollectionConverter introspects the field that declares the target collection type to resolve the collection’s element type. This lets each element in the source array be converted to the collection element type before the collection is set on the target field.

要实现 GenericConverter,让 getConvertibleTypes() 返回支持的源→目标类型对。然后实现 convert(Object, TypeDescriptor, TypeDescriptor) 以包含你的转换逻辑。源 TypeDescriptor 提供对包含要转换的值的源字段的访问。目标 TypeDescriptor 提供对要设置转换值的目标字段的访问。

GenericConverter 的一个很好的例子是在 Java 数组和集合之间进行转换的转换器。这样的 ArrayToCollectionConverter 内省声明目标集合类型的字段以解析集合的元素类型。这使得在目标字段上设置集合之前,源数组中的每个元素都可以转换为集合元素类型。

Using ConditionalGenericConverter

Sometimes, you want a Converter to run only if a specific condition holds true. For example, you might want to run a Converter only if a specific annotation is present on the target field, or you might want to run a Converter only if a specific method (such as a static valueOf method) is defined on the target class. ConditionalGenericConverter is the union of the GenericConverter and ConditionalConverter interfaces that lets you define such custom matching criteria:

有时,你希望转换器仅在特定条件成立时运行。例如,你可能只想在目标字段上存在特定注释时才运行 Converter,或者你可能只想在目标类上定义了特定方法(例如静态 valueOf 方法)时才运行 Converter。ConditionalGenericConverter 是 GenericConverter 和 ConditionalConverter 接口的联合,它允许你定义这样的自定义匹配条件:

public interface ConditionalConverter {

    boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}

public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
}

四、The ConversionService API

ConversionService defines a unified API for executing type conversion logic at runtime. Converters are often run behind the following facade interface:

ConversionService 定义了一个统一的 API,用于在运行时执行类型转换逻辑。转换器通常在以下外观接口后面运行:

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

Most ConversionService implementations also implement ConverterRegistry, which provides an SPI for registering converters. Internally, a ConversionService implementation delegates to its registered converters to carry out type conversion logic.A robust ConversionService implementation is provided in the core.convert.support package. GenericConversionService is the general-purpose implementation suitable for use in most environments. ConversionServiceFactory provides a convenient factory for creating common ConversionService configurations.

大多数 ConversionService 实现还实现了 ConverterRegistry,它提供了一个用于注册转换器的 SPI。在内部,ConversionService 实现委托其注册的转换器执行类型转换逻辑。core.convert.support 包中提供了一个健壮的 ConversionService 实现。 GenericConversionService 是适用于大多数环境的通用实现。ConversionServiceFactory 提供了一个方便的工厂来创建通用的 ConversionService 配置。

五、Configuring a ConversionService(配置一个ConversionService)

A ConversionService is a stateless object designed to be instantiated at application startup and then shared between multiple threads. In a Spring application, you typically configure a ConversionService instance for each Spring container (or ApplicationContext). Spring picks up that ConversionService and uses it whenever a type conversion needs to be performed by the framework. You can also inject this ConversionService into any of your beans and invoke it directly. If no ConversionService is registered with Spring, the original PropertyEditor-based system is used.To register a default ConversionService with Spring, add the following bean definition with an id of conversionService:

ConversionService 是一个无状态对象,旨在在应用程序启动时实例化,然后在多个线程之间共享。在 Spring 应用程序中,通常为每个 Spring 容器(或 ApplicationContext)配置一个 ConversionService 实例。Spring 获取该 ConversionService 并在框架需要执行类型转换时使用它。你也可以将此 ConversionService 注入到您的任何 bean 中并直接调用它。如果没有向 Spring 注册 ConversionService,则使用原始的基于 PropertyEditor 的系统。要向 Spring 注册默认的 ConversionService,需添加以下 bean 定义,其 id 为 ConversionService:

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

六、Using a ConversionService Programmatically(以编程方式使用 ConversionService)

To work with a ConversionService instance programmatically, you can inject a reference to it like you would for any other bean. The following example shows how to do so:

要以编程方式使用 ConversionService 实例,可以像注入任何其他 bean 一样注入对它的引用。以下示例显示了如何执行此操作:

@Service
public class MyService {

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

    public void doIt() {
        this.conversionService.convert(...)
    }
}

For most use cases, you can use the convert method that specifies the targetType, but it does not work with more complex types, such as a collection of a parameterized element. For example, if you want to convert a List of Integer to a List of String programmatically, you need to provide a formal definition of the source and target types.Fortunately, TypeDescriptor provides various options to make doing so straightforward, as the following example shows:

对于大多数情况,可以使用指定 targetType 的 convert 方法,但它不适用于更复杂的类型,例如集合。例如,如果要以编程方式将整数列表转换为字符串列表,则需要提供源类型和目标类型的正式定义。幸运的是,TypeDescriptor 提供了各种选项来使操作变得简单,如以下示例所示:

DefaultConversionService cs = new DefaultConversionService();

List<Integer> input = ...
cs.convert(input,
    TypeDescriptor.forObject(input), // List<Integer> type descriptor
    TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)));

Note that DefaultConversionService automatically registers converters that are appropriate for most environments. This includes collection converters, scalar converters, and basic Object-to-String converters. You can register the same converters with any ConverterRegistry by using the static addDefaultConverters method on the DefaultConversionService class.Converters for value types are reused for arrays and collections, so there is no need to create a specific converter to convert from a Collection of S to a Collection of T, assuming that standard collection handling is appropriate.

需要注意的是, DefaultConversionService 会自动注册适用于大多数环境的转换器。包括集合转换器、标量转换器和基本的对象到字符串转换器。可以使用 DefaultConversionService 类上的静态 addDefaultConverters 方法向任何 ConverterRegistry 注册相同的转换器。值类型的转换器可重用于数组和集合,因此无需创建特定转换器即可将 S 的集合转换为 T 的集合,假设标准集合处理是合适的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值