внедрение ConversionService в пользовательский конвертер - PullRequest
10 голосов
/ 01 декабря 2011

Использование Spring MVC-3. Я пишу пользовательский конвертер, которому нужен доступ к другим конвертерам, зарегистрированным на ConversionService.

Как мне это сделать? Я попытался написать свой собственный конвертер как:

  class CustomConverter<X, Y>{
     @Autowired ConversionService service;
     //+getter & setters of service

     public Y convert(X input){
          // I need access to service to lookup simple conversions such as
          // String array to Long array etc..

     }

  }

И я зарегистрировал свой собственный конвертер через applicationContext.xml

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

Однако Spring отказывается внедрять сервис в мой CustomConverter (он всегда нулевой). Как мне это сделать?

Спасибо!

Ответы [ 4 ]

8 голосов
/ 15 августа 2013

Я столкнулся с той же проблемой.В Spring JIRA существует проблема SPR-6415 , охватывающая эту проблему.Я привожу здесь свое решение, основанное на обсуждении этого вопроса.Это тот же принцип, что и ответ @nmervaillie, но вам не нужно реализовывать свой собственный ConversionServiceFactoryBean.

/**
 * Base class of @{code Converter} that need to use {@code ConversionService}.
 * Instances of implementing classes must be spring-managed to inject ConversionService.
 * 
 * @author Michal Kreuzman
 */
public abstract class CoversionServiceAwareConverter<S, T> implements Converter<S, T> {

  @Inject
  private ConversionService conversionService;

  protected ConversionService conversionService() {
    return conversionService;
  }

  /**
   * Add this converter to {@code ConverterRegistry}.
   */
  @SuppressWarnings("unused")
  @PostConstruct
  private void register() {
    if (conversionService instanceof ConverterRegistry) {
      ((ConverterRegistry) conversionService).addConverter(this);
    } else {
      throw new IllegalStateException("Can't register Converter to ConverterRegistry");
    }
  }
}

@Component
public class SampleConverter extends CoversionServiceAwareConverter<Object, Object> {

    @Override
    public String convert(Object source) {
        ConversionService conversionService = conversionService();

        // Use conversionService and convert
    }
}
7 голосов
/ 06 января 2012

Я недавно использовал что-то подобное для решения этой проблемы. Использовать фабрику на заказ:

public class MyConversionServiceFactoryBean extends ConversionServiceFactoryBean {

    @Override
    public void afterPropertiesSet() {
        super.afterPropertiesSet();
        ConversionService conversionService = getObject();
        ConverterRegistry registry = (ConverterRegistry) conversionService;
        // register converters that need a nested conversion service
        registry.addConverter(new MyCustomConverter(conversionService));
    }
}

который объявлен так:

<bean id="conversionService"
    class="com.company.MyConversionServiceFactoryBean">
    <property name="converters">
        <list>
            ... declare standard converters here ...
        </list>
    </property>
</bean>
1 голос
/ 09 апреля 2016

Я решил эту проблему в приложении Spring-ws.Основными компонентами этого решения являются:

  • объявление реализаций конвертера как пружинных бинов
  • с использованием @Lazy из spring-context в точках инжекции в конвертерах
  • injectвсе обнаруженные конвертеры в ConversionServiceFactoryBean

SampleConverter

@Component
public class SampleConverter implements Converter<Source, Target> {

private ConversionService conversionService;

    @Inject
    @Lazy
    public SampleConverter(ConversionService conversionService){
        this.conversionService = conversionService; 
    }

    @Override
    public Target convert(Source source){
        Target target = new Target();
        ...
    target.setTargetDetails(conversionService.convert(source.getSourceDetails, TargetDetails.class); 
    ...

и конфигурации:

@Configuration
public class ConversionServiceConfig {

    @Bean
    public ConversionService conversionService(Set<Converter<?,?>> converters){
        ConversionServiceFactoryBean csfb = new ConversionServiceFactoryBean();
        csfb.setConverters(converters); 
        csfb.afterPropertiesSet(); 
        return csfb.getObject(); 
   }

...

The @Lazyаннотации обходят проблему куриного яйца, внедряя прокси-сервер и, таким образом, задерживая разрешение bean-компонента translationservice до его реального использования.

0 голосов
/ 08 октября 2015

Основная проблема (с которой я столкнулся) - это когда вы используете ConversionServiceFactoryBean для сборки conversion service, которая включает в себя также конвертеры, использующие conversion service, что вы получаете ошибку из-за метода ConversionServiceFactoryBean.getObject, который предоставляет экземпляр conversion service вызывается до ConversionServiceFactoryBean.afterPropertiesSet, где этот экземпляр службы преобразования фактически создается.

Итак, , чтобы избежать такого поведения , вам просто нужно , чтобы создать conversion service до того, как ConversionServiceFactoryBean.getObject называется . Я сделал это в конструкторе класса, который расширяет ConversionServiceFactoryBean. Пример:

    try {

        Field serviceField = ConversionServiceFactoryBean.class.getDeclaredField("conversionService");
        conversionServiceField.setAccessible(true);
        conversionServiceField.set(this, createConversionService());

    } catch (NoSuchFieldException | IllegalAccessException fieldAccessError) {

        fieldAccessError.printStackTrace();
        //or do some log output here, it's up to you
    }

Чем вы можете использовать конвертеры, которые также используют conversion service. Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...