简体   繁体   English

弹簧双向转换器

[英]Two-way converter in spring

Spring 3 has such a nice feature as type conversion. Spring 3具有类型转换这样一个很好的功能。 It provides a converter SPI( Converter<S, T> ) to be used to implement differenet conversion logic. 它提供了一个转换器SPI( Converter<S, T> ),用于实现差分转换逻辑。 The subclass of Converter type allow to define one-way conversion(only from S to T), so if I want a conversion also to be performed from T to SI need to define another converter class that implement Converter<T, S> . Converter类型的子类允许定义单向转换(仅从S到T),因此如果我还希望从T到SI执行Converter<T, S>需要定义另一个实现Converter<T, S>转换器类。 If I have many classes which are subject to conversion, i need to define many converters. 如果我有许多可以转换的类,我需要定义许多转换器。 Is there any posibility to define two-way conversion logic(from S to T and from T to S) in one converter? 是否有可能在一个转换器中定义双向转换逻辑(从S到T和从T到S)? and how it will be used? 以及它将如何使用?

PS. PS。 now I'm using my converters via ConversionServiceFactoryBean defining/injecting them in configuration file 现在我通过ConversionServiceFactoryBean使用我的转换器,在配置文件中定义/注入它们

You are correct, if you want to use the org.springframework.core.convert.converter.Converter interface directly, you'll need to implement two converters, one for each direction. 你是对的,如果你想直接使用org.springframework.core.convert.converter.Converter接口,你需要实现两个转换器,每个方向一个。

But spring 3 has a couple of other options: 但是春天3还有其他两个选择:

  1. If your conversion is not object-to-object but rather object-to-string (and back), then you can implement a org.springframework.format.Formatter instead. 如果您的转换不是对象到对象,而是对象到字符串(和返回),那么您可以实现org.springframework.format.Formatter Formatters get registered as GenericConverters (see http://static.springsource.org/spring-webflow/docs/2.3.x/reference/html/ch05s07.html#converter-upgrade-to-spring-3 ) 格式化程序注册为GenericConverters(请参阅http://static.springsource.org/spring-webflow/docs/2.3.x/reference/html/ch05s07.html#converter-upgrade-to-spring-3

  2. Otherwise you could implement your own org.springframework.core.convert.converter.GenericConverter , which makes it easy to create TwoWayConverter implementations using reflection. 否则,您可以实现自己的org.springframework.core.convert.converter.GenericConverter ,这样可以使用反射轻松创建TwoWayConverter实现。

     public abstract class AbstractTwoWayConverter<S, T> implements GenericConverter { private Class<S> classOfS; private Class<T> classOfT; protected AbstractTwoWayConverter() { Type typeA = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; Type typeB = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]; this.classOfS = (Class) typeA; this.classOfT = (Class) typeB; } public Set<ConvertiblePair> getConvertibleTypes() { Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>(); convertiblePairs.add(new ConvertiblePair(classOfS, classOfT)); convertiblePairs.add(new ConvertiblePair(classOfT, classOfS)); return convertiblePairs; } public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { if (classOfS.equals(sourceType.getType())) { return this.convert((S) source); } else { return this.convertBack((T) source); } } protected abstract T convert(S source); protected abstract S convertBack(T target); } /** * converter to convert between a userId and user. * this class can be registered like so: * conversionService.addConverter(new UserIdConverter (userDao)); */ public class UserIdConverter extends AbstractTwoWayConverter<String, User> { private final UserDao userDao; @Autowired public UserIdConverter(UserDao userDao) { this.userDao = userDao; } @Override protected User convert(String userId) { return userDao.load(userId); } @Override protected String convertBack(User target) { return target.getUserId(); } } 

You can use Spring Formatter to format object of type T to String and vice versa. 您可以使用Spring Formatter将类型为T的对象格式化为String,反之亦然。

package org.springframework.format;

public interface Formatter<T> extends Printer<T>, Parser<T> {
}

Using this interface you can achieve the same as the Barry Pitman says but with less code and this is the preferable way by the Spring documentation if you waht to format to String and vice versa. 使用这个接口你可以实现与Barry Pitman所说的相同,但代码更少,如果你要格式化为String,这是Spring文档的首选方法,反之亦然。 So the Barry's UserIdConverter class is going to look like this: 所以Barry的UserIdConverter类看起来像这样:

public class UserIdConverter implements Formatter<User> {

    private final UserDao userDao;

    @Autowired
    public UserIdConverter(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public User parse(String userId, Locale locale) {
        return userDao.load(userId);
    }

    @Override
    public String print(User target, Locale locale) {
        return target.getUserId();
    }
}

To register this Formatter you should include this in your XML config: 要注册此Formatter,您应该在XML配置中包含它:

...
<mvc:annotation-driven conversion-service="conversionService"/>

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" >
    <property name="formatters">
        <set>
            <bean class="com.x.UserIdConverter"/>
        </set>
    </property>
</bean>
...

! NOTE that this class can be used only for formatting from some type T to String and vice versa. 请注意,此类只能用于从某种类型T到String的格式化,反之亦然。 You can not format from type T to some other type T1 for example. 例如,您无法将类型T格式化为其他类型T1。 If you have this case you should go with the Spring GenericConverter and use the Barry Pitman answer: 如果您有这种情况,您应该使用Spring GenericConverter并使用Barry Pitman答案:

public abstract class AbstractTwoWayConverter<S, T> implements GenericConverter {

    private Class<S> classOfS;
    private Class<T> classOfT;

    protected AbstractTwoWayConverter() {
        Type typeA = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        Type typeB = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        this.classOfS = (Class) typeA;
        this.classOfT = (Class) typeB;
    }

    public Set<ConvertiblePair> getConvertibleTypes() {
        Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
        convertiblePairs.add(new ConvertiblePair(classOfS, classOfT));
        convertiblePairs.add(new ConvertiblePair(classOfT, classOfS));
        return convertiblePairs;
    }

    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        if (classOfS.equals(sourceType.getType())) {
            return this.convert((S) source);
        } else {
            return this.convertBack((T) source);
        }
    }

    protected abstract T convert(S source);

    protected abstract S convertBack(T target);

}

/** 
 * converter to convert between a userId and user.
 * this class can be registered like so: 
 * conversionService.addConverter(new UserIdConverter (userDao));
 */ 
public class UserIdConverter extends AbstractTwoWayConverter<String, User> {

    private final UserDao userDao;

    @Autowired
    public UserIdConverter(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    protected User convert(String userId) {
        return userDao.load(userId);
    }

    @Override
    protected String convertBack(User target) {
        return target.getUserId();
    }
}

And add to your XML config: 并添加到您的XML配置:

...
<mvc:annotation-driven conversion-service="conversionService"/>

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean" >
    <property name="converters">
        <set>
            <bean class="com.x.y.UserIdConverter"/>
        </set>
    </property>
</bean>
...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM