2012-06-12 2 views
2

Весна 3 имеет такую ​​приятную функцию, как преобразование типа. Он предоставляет преобразователь SPI (Converter<S, T>), который будет использоваться для реализации логики преобразования дифференциалов. Подкласс типа конвертера позволяет определять одностороннее преобразование (только от S до T), поэтому, если я хочу, чтобы преобразование также выполнялось с T на S, мне нужно определить другой класс преобразователя, который реализует Converter<T, S>. Если у меня есть много классов, которые подлежат преобразованию, мне нужно определить многие преобразователи. Есть ли возможность определить двустороннюю логику преобразования (от S до T и от T до S) в одном преобразователе? и как он будет использоваться?Двухсторонний преобразователь весной

PS. теперь я использую свои преобразователи через ConversionServiceFactoryBean, определяющие/вводя их в конфигурационный файл

ответ

7

Вы правильно, если вы хотите использовать интерфейс org.springframework.core.convert.converter.Converter напрямую, вам необходимо реализовать два преобразователя, по одному для каждого направления.

Но весной 3 имеет несколько других вариантов:

  1. Если преобразование не приемлю к объекту, а объект в строку (и обратно), то вы можете реализовать org.springframework.format.Formatter вместо , Форматтеры зарегистрироваться в качестве GenericConverters (см http://static.springsource.org/spring-webflow/docs/2.3.x/reference/html/ch05s07.html#converter-upgrade-to-spring-3)

  2. В противном случае вы можете реализовать свой собственный 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(); 
        } 
    } 
    
0

Вы можете использовать Spring Formatter форматировать объект типа T в строку и наоборот.

package org.springframework.format; 

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

Используя этот интерфейс, вы можете достичь того же, как говорит Барри Питмэн, но с меньшим количеством кода, и это является предпочтительным способом в документации Spring, если вы WAHT отформатировать в строку и наоборот. Так класс 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 Вы должны включить это в 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> 
... 

! Обратите внимание, что этот класс может использоваться только для форматирования от некоторого типа T до String и наоборот. Вы не можете форматировать из типа T в другой тип T1, например. Если у вас есть этот случай вы должны пойти с Spring GenericConverter и использовать Барри Питманом ответ:

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

И добавить к вашему 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> 
...