我搜索了以下问题,但找不到答案。
我想通过编写实现 org.springframework.core.convert.converter.Converter 的自定义转换器来使用spring的转换服务。
然后我添加我的自定义转换器如下:
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean id="StringToLoggerConverter" class="com.citi.spring.converter.LoggerConverter" />
</list>
</property>
</bean>
执行上述操作时,我的应用程序初始化失败,因为我重写了bean conversionService并仅注册了我的自定义转换器。
我怎样才能覆盖conversionService并仅将自定义转换器添加到转换器列表中,同时保留现有转换器?
提前致谢。
答案 0 :(得分:10)
对于那些现在通过谷歌搜索或类似问题最初发布后2年以上发现此事的人,通过Java Config添加转换器变得更加容易:WebMvcConfigurerAdapter
提供了addFormatters(FormatterRegistry)
方法可用于指定其他自定义转换器。
答案 1 :(得分:4)
在尝试不同的方式,甚至在某些方面遵循弹簧源代码时,我遇到了一件有趣的事情。
我发现使用conversionService而不用现有转换器覆盖现有转换器的唯一方法是扩展或重新实现conversionService,调用超类的afterPropertiesSet()方法来注册默认转换器,然后添加自定义转换器。
但是,即使我使用这种方式,在运行时我得到一个例外,没有找到我的特定类型的转换器(例如从String到Logger)。
这引发了我的兴趣,我按照弹簧源代码找出原因,我意识到spring正试图找到一个用PropertyEditor注册的自定义转换器。我不确定为什么会这样。我必须在这里添加我的应用程序不使用spring mvc和conversionService可能以某种方式需要注册,我没有这样做。
最后,我解决了使用Property编辑器注册自定义转换器的问题。可以将此文档视为参考:
http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html
我很想知道为什么Spring没有在conversionService的注册表中找到我注册的自定义转换器(或者至少为什么Spring没有查看该注册表来查找自定义转换器)。我错过了任何配置吗?
答案 2 :(得分:2)
您也可以在DefaultConversionService-ish类上使用addConverter方法动态添加它:
DefaultConversionService cs = new <YourClassThatInheritsFromDefaultConversionService or DefaultConversionService>();
cs.addConverter(new MyConverter());
答案 3 :(得分:2)
春天&gt; 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;
}
}
答案 4 :(得分:1)
在Stackoverflow中遇到了一种非常有趣的方法 - https://stackoverflow.com/a/12760579/204788
使用名为Collection merging的功能,您基本上可以执行此操作:
<bean id="customConversionService" class="org.springframework.context.support.ConversionServiceFactoryBean" parent="conversionService">
<property name="converters">
<list merge="true">
<bean id="StringToLoggerConverter" class="com.citi.spring.converter.LoggerConverter" />
</list>
</property>
</bean>
答案 5 :(得分:1)
足以覆盖ConversionServiceFactoryBean.afterPropertiesSet()并将ConversionService对象设置为转换器。 让您的转换器实现一些允许设置ConversionService对象的接口,比如ConversionServiceAware。 唯一的问题是访问已注册的转换器,因此您还必须覆盖&#39; setConverters()&#39;方法
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);
}
}
}
}
答案 6 :(得分:0)
编写自定义conversionService
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));
}
}
}
然后更改你的xml
<bean id="conversionService"
class="CustomerConversionServiceFactoryBean" >
<property name="converters" >
<list>
<bean class="CustomConverter" />
</list>
</property>
</bean>
我认为这会对你有帮助......
答案 7 :(得分:0)
此变体对我有效。
如果您使用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 :(得分:0)
要解决任何循环依赖性,请按以下步骤操作(Spring Boot v5.2.1):
注册一个简单的conversionService
@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);
}
}
转换器甚至可以自动连接您的conversionService
@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;
}
}