Spring ConversionService, добавляющий преобразователи
Автор вопроса: nikkatsaОтветов: 9
Я искал проблему ниже, но не смог найти ответ.
Я хочу использовать службу преобразования Spring, написав свой собственный преобразователь, реализующий org.springframework.core.convert.converter.Converter.
Затем я добавляю свой собственный конвертер, как показано ниже:
При выполнении вышеизложенного инициализация моего приложения завершается ошибкой, потому что я переопределяю службу преобразования компонентов и регистрирую только свой собственный преобразователь.
Как я могу не переопределить convertService и добавить только свой собственный конвертер в список конвертеров, в то же время сохранив существующие?
Для тех, кто наткнулся на это сейчас с помощью поиска Google или аналогичного более чем через 2 года после первоначальной публикации вопроса, добавление конвертеров стало намного проще с помощью Java Config: WebMvcConfigurerAdapter предоставляет метод addFormatters(FormatterRegistry), который можно использовать для указания дополнительных пользовательских конвертеров.
Ответ 2 · рейтинг 4 · nikkatsa
Экспериментируя с разными способами и даже в некоторых случаях следуя исходному коду Spring, я наткнулся на интересную вещь.
Единственный способ, которым я нашел использование convertService без переопределения существующих преобразователей моими пользовательскими, заключался в том, чтобы либо расширить, либо повторно реализовать convertService, вызывая метод afterPropertiesSet() суперкласса, чтобы зарегистрировать преобразователи по умолчанию, а затем добавить пользовательские.
Но даже если бы я использовал этот способ, во время выполнения я получал исключение, что для моих конкретных типов не был найден конвертер (например, из String в Logger).
Это вызвало мой интерес, и я проследил за исходным кодом Spring, чтобы узнать, почему, и я понял, что Spring пытается найти собственный конвертер, зарегистрированный в PropertyEditor. Я не уверен, почему это происходит. Я должен добавить, что мое приложение не использует Spring MVC, и, возможно, нужно как-то зарегистрировать convertService, а я этого не делал.
Наконец, я решил проблему с регистрацией пользовательского конвертера с помощью редактора свойств. Эту документацию можно рассматривать как справочную:
Мне было бы очень интересно узнать, почему Spring не находит мои зарегистрированные пользовательские конвертеры в реестре convertService (или, по крайней мере, почему Spring не просматривает этот реестр, чтобы найти пользовательские конвертеры). Я пропустил какую-либо конфигурацию?
Ответ 3 · рейтинг 2 · Christian Vielma
Вы также можете добавить его динамически, используя метод addConverter в вашем классе DefaultConversionService:
DefaultConversionService cs = new <YourClassThatInheritsFromDefaultConversionService or DefaultConversionService>();
cs.addConverter(new MyConverter());
Ответ 4 · рейтинг 2 · Heri
С Spring> 4 больше нет необходимости реализовывать собственный производный от ConversionService. Инициализируйте его в аннотированном классе @Configuration следующим образом:
@Configuration
public class ConversionServiceProvider
{
@Autowired
private MyConverterImpl myConverter;
@Bean
public ConversionService getConversionService()
{
ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
bean.setConverters( getConverters() );
bean.afterPropertiesSet();
ConversionService object = bean.getObject();
return object;
}
private Set<Converter<?, ?>> getConverters()
{
Set<Converter<?, ?>> converters = new HashSet<Converter<?, ?>>();
converters.add( myConverter );
// add here more custom converters, either as spring bean references or directly instantiated
return converters;
}
}
Достаточно переопределить ConversionServiceFactoryBean.afterPropertiesSet() и установить там объект ConversionService для ваших конвертеров. Пусть ваши преобразователи реализуют некоторый интерфейс, который позволяет установить объект ConversionService, скажем, ConversionServiceAware. Единственная проблема заключается в том, чтобы получить доступ к зарегистрированным преобразователям, поэтому вам также придется переопределить метод setConverters().
public class MyFormattingConversionServiceFactoryBean extends FormattingConversionServiceFactoryBean {
private Set<?> cachedConverters = new LinkedHashSet<>();
@Override
public void setConverters(Set<?> converters) {
super.setConverters(converters);
this.cachedConverters = new LinkedHashSet<>(converters);
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
FormattingConversionService conversionService = getObject();
for (Object converter : cachedConverters) {
if (converter instanceof ConversionServiceAware) {
((ConversionServiceAware) converter).setConversionService(conversionService);
}
}
}
}
Ответ 7 · рейтинг 1 · limon4ick
Этот вариант у меня работает. Если вы используете конфигурацию Java, вы можете добавить свои преобразователи в существующие GenericConversionService
Config methods may have an arbitrary name and any number of arguments; each of those arguments will be autowired with a matching bean in the Spring container. Bean property setter methods are effectively just a special case of such a general config method. Such config methods do not have to be public.
@Configuration
class MyConfig {
@Autowired
void conversionService(GenericConversionService genericConversionService) {
genericConversionService.addConverter(String.class, UUID.class, UUID::fromString);
genericConversionService.addConverter(String.class, DateTime.class, DateTime::parse);
genericConversionService.addConverter(String.class, EnumState.class, EnumState::valueOf);
}
}
Ответ 8 · рейтинг 1 · LionH
Чтобы устранить любые циклические зависимости, выполните следующие шаги (Spring Boot v5.2.1):
Зарегистрируйте простой сервис преобразования
@Configuration
public class ConverterProvider {
@Bean
public ConversionService conversionService() {
ConversionService conversionService = new GenericConversionService();
return conversionService;
}
}
Внедряйте свои пользовательские конвертеры
@Component
public class ConvertersInjection {
@Autowired
private GenericConversionService conversionService;
@Autowired
private void converters(Set<Converter> converters) {
converters.forEach(conversionService::addConverter);
}
}
Конвертер может даже автоматически подключить ваш сервис преобразования.
@Component
public class PushNotificationConverter implements Converter<PushNotificationMessages.PushNotification, GCM> {
@Lazy
@Autowired
private ConversionService conversionService;
@Override
public GCM convert(PushNotificationMessages.PushNotification source) {
GCM gcm = new GCM();
if (source.hasContent()) {
PushNotificationMessages.PushNotification.Content content = source.getContent();
if (content.hasData()) {
conversionService.convert(content.getData(), gcm.getData().getClass());
} else if (content.hasNotification()) {
conversionService.convert(content.getNotification(), gcm.getNotification().getClass());
}
}
return gcm;
}
}
Ответ 9 · sgpalit
написать пользовательский сервис преобразования
public class CustomerConversionServiceFactoryBean extends ConversionServiceFactoryBean {
List<Converter<Object, Object>> converters = new ArrayList<>();
public CustomerConversionServiceFactoryBean() {
super();
DefaultConversionService conversionservice = (DefaultConversionService) super.getObject();
for(int i=0;i<converters.size();i++){
conversionservice.addConverter(converters.get(i));
}
}
}