Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two-way converter in spring

Tags:

java

spring-3

Spring 3 has such a nice feature as type conversion. It provides a converter SPI(Converter<S, T>) to be used to implement differenet conversion logic. 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 S I need to define another converter class that implement 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? and how it will be used?

PS. now I'm using my converters via ConversionServiceFactoryBean defining/injecting them in configuration file

like image 296
maks Avatar asked Jun 12 '12 12:06

maks


People also ask

How does a Spring converter work?

Spring provides out-of-the-box various converters for built-in types; this means converting to/from basic types like String, Integer, Boolean and a number of other types. Apart from this, Spring also provides a solid type conversion SPI for developing our custom converters.

What is the use of MappingJackson2HttpMessageConverter?

Class MappingJackson2HttpMessageConverter. Implementation of HttpMessageConverter that can read and write JSON using Jackson 2. x's ObjectMapper . This converter can be used to bind to typed beans, or untyped HashMap instances.

What is an HttpMessageConverter in Spring rest?

HttpMessageConverter is a strategy interface that specifies a converter that can convert from and to HTTP requests and responses in Spring REST Restful web services. Internally Spring MVC uses it to convert the Http request to an object representation and back.

How do I use Conversionservice?

Method SummaryReturn true if objects of sourceType can be converted to the targetType . Return true if objects of sourceType can be converted to the targetType . Convert the given source to the specified targetType . Convert the given source to the specified targetType .


1 Answers

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.

But spring 3 has a couple of other options:

  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. 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)

  2. Otherwise you could implement your own org.springframework.core.convert.converter.GenericConverter, which makes it easy to create TwoWayConverter implementations using reflection.

    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();
        }
    }
    
like image 175
Barry Pitman Avatar answered Sep 29 '22 20:09

Barry Pitman