Java 在 Spring Boot 中以编程方式注册 Spring Converter
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35025550/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Register Spring Converter Programmatically in Spring Boot
提问by jpolete
I want to register a Spring Converter in a Spring Boot project programmatically. In past Spring projects I've done it in XML like this...
我想以编程方式在 Spring Boot 项目中注册一个 Spring Converter。在过去的 Spring 项目中,我像这样用 XML 完成了...
<!-- Custom converters to allow automatic binding from Http requests parameters to objects -->
<!-- All converters are annotated w/@Component -->
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<ref bean="stringToAssessmentConverter" />
</list>
</property>
</bean>
I'm trying to figure out how to do in Spring Boot's SpringBootServletInitializer
我试图弄清楚如何在 Spring Boot 的 SpringBootServletInitializer 中做
Update:I've made a little progress by passing the StringToAssessmentConverter as an argument to getConversionService
, but now I'm getting a "No default constructor found"
error for the StringToAssessmentConverter class. I'm not sure why Spring is not seeing the @Autowired constructor.
更新:通过将 StringToAssessmentConverter 作为参数传递给getConversionService
,我取得了一些进展,但现在我收到了"No default constructor found"
StringToAssessmentConverter 类的错误。我不确定为什么 Spring 没有看到 @Autowired 构造函数。
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
...
@Bean(name="conversionService")
public ConversionServiceFactoryBean getConversionService(StringToAssessmentConverter stringToAssessmentConverter) {
ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
Set<Converter> converters = new HashSet<>();
converters.add(stringToAssessmentConverter);
bean.setConverters(converters);
return bean;
}
}
Here's the code for the Converter...
这是转换器的代码...
@Component
public class StringToAssessmentConverter implements Converter<String, Assessment> {
private AssessmentService assessmentService;
@Autowired
public StringToAssessmentConverter(AssessmentService assessmentService) {
this.assessmentService = assessmentService;
}
public Assessment convert(String source) {
Long id = Long.valueOf(source);
try {
return assessmentService.find(id);
} catch (SecurityException ex) {
return null;
}
}
}
Full Error
完全错误
Failed to execute goal org.springframework.boot:spring-boot-maven-
plugin:1.3.2.RELEASE:run (default-cli) on project yrdstick: An exception
occurred while running. null: InvocationTargetException: Error creating
bean with name
'org.springframework.boot.context.properties.ConfigurationPropertiesBindingPo
stProcessor': Invocation of init method failed; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException: Error
creating bean with name 'conversionService' defined in
me.jpolete.yrdstick.Application: Unsatisfied dependency expressed through
constructor argument with index 0 of type
[me.jpolete.yrdstick.websupport.StringToAssessmentConverter]: : Error
creating bean with name 'stringToAssessmentConverter' defined in file
[/yrdstick/target/classes/me/jpolete/yrdstick/websupport
/StringToAssessmentConverter.class]: Instantiation of bean failed; nested
exception is org.springframework.beans.BeanInstantiationException: Failed
to instantiate
[me.jpolete.yrdstick.websupport.StringToAssessmentConverter]: No default
constructor found; nested exception is java.lang.NoSuchMethodException:
me.jpolete.yrdstick.websupport.StringToAssessmentConverter.<init>();
nested exception is
org.springframework.beans.factory.BeanCreationException: Error creating
bean with name 'stringToAssessmentConverter' defined in file [/yrdstick
/dev/yrdstick/target/classes/me/jpolete/yrdstick/websupport
/StringToAssessmentConverter.class]: Instantiation of bean failed; nested
exception is org.springframework.beans.BeanInstantiationException: Failed
to instantiate
[me.jpolete.yrdstick.websupport.StringToAssessmentConverter]: No default
constructor found; nested exception is java.lang.NoSuchMethodException:
me.jpolete.yrdstick.websupport.StringToAssessmentConverter.<init>()
采纳答案by deFreitas
The answer is, you only need to anotate your converter as @Component
:
答案是,您只需要将转换器注释为@Component
:
This is my converter example
这是我的转换器示例
import org.springframework.core.convert.converter.Converter;
@Component
public class DateUtilToDateSQLConverter implements Converter<java.util.Date, Date> {
@Override
public Date convert(java.util.Date source) {
return new Date(source.getTime());
}
}
Then when Spring needs to make convert, the converter is called.
然后当 Spring 需要进行转换时,就会调用转换器。
My Spring Boot Version: 1.4.1
我的 Spring Boot 版本: 1.4.1
回答by MangEngkus
try this:
尝试这个:
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
@Bean
public AssessmentService assessmentService(){
return new AssessmentService();
}
@Bean
public StringToAssessmentConverter stringToAssessmentConverter(){
return new StringToAssessmentConverter(assessmentService());
}
@Bean(name="conversionService")
public ConversionService getConversionService() {
ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
Set<Converter> converters = new HashSet<Converter>();
//add the converter
converters.add(stringToAssessmentConverter());
bean.setConverters(converters);
return bean.getObject();
}
// separate these class into its own java file if necessary
// Assesment service
class AssessmentService {}
//converter
class StringToAssessmentConverter implements Converter<String, Assessment> {
private AssessmentService assessmentService;
@Autowired
public StringToAssessmentConverter(AssessmentService assessmentService) {
this.assessmentService = assessmentService;
}
public Assessment convert(String source) {
Long id = Long.valueOf(source);
try {
return assessmentService.find(id);
} catch (SecurityException ex) {
return null;
}
}
}
}
or if your StringToAssessmentConverter is already a spring bean:
或者如果您的 StringToAssessmentConverter 已经是一个 spring bean:
@Autowired
@Bean(name="conversionService")
public ConversionService getConversionService(StringToAssessmentConverter stringToAssessmentConverter) {
ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
Set<Converter> converters = new HashSet<Converter>();
//add the converter
converters.add(stringToAssessmentConverter);
bean.setConverters(converters);
return bean.getObject();
}
回答by narduk
Here is my solution:
这是我的解决方案:
A TypeConverter Annotation:
TypeConverter 注解:
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface TypeConverter {
}
A Converter Registrar:
转换器注册商:
@Configuration
public class ConverterConfiguration {
@Autowired(required = false)
@TypeConverter
private Set<Converter<?, ?>> autoRegisteredConverters;
@Autowired(required = false)
@TypeConverter
private Set<ConverterFactory<?, ?>> autoRegisteredConverterFactories;
@Autowired
private ConverterRegistry converterRegistry;
@PostConstruct
public void conversionService() {
if (autoRegisteredConverters != null) {
for (Converter<?, ?> converter : autoRegisteredConverters) {
converterRegistry.addConverter(converter);
}
}
if (autoRegisteredConverterFactories != null) {
for (ConverterFactory<?, ?> converterFactory : autoRegisteredConverterFactories) {
converterRegistry.addConverterFactory(converterFactory);
}
}
}
}
And then annotate your converters:
然后注释您的转换器:
@SuppressWarnings("rawtypes")
@TypeConverter
public class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
@SuppressWarnings("unchecked")
public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToEnum(targetType);
}
private final class StringToEnum<T extends Enum> implements Converter<String, T> {
private Class<T> enumType;
public StringToEnum(Class<T> enumType) {
this.enumType = enumType;
}
@SuppressWarnings("unchecked")
public T convert(String source) {
return (T) Enum.valueOf(this.enumType, source.trim().toUpperCase());
}
}
}
回答by Grigory Kislin
For Spring Boot it looks like:
对于 Spring Boot,它看起来像:
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// do not replace with lambda as spring cannot determine source type <S> and target type <T>
registry.addConverter(new Converter<String, Integer>() {
@Override
public Integer convert(String text) {
if (text == null) {
return null;
}
String trimmed = StringUtils.trimWhitespace(text);
return trimmed.equals("null") ? null : Integer.valueOf(trimmed);
}
});
}
回答by fg78nc
If you are not on Spring Boot, where automatic registration of converters annotated with @Component (and similar stereotype annotations) is performed and you are **not in Web Mvc environment:
如果您不在 Spring Boot 上,在其中执行用 @Component(和类似的构造型注释)注释的转换器的自动注册,并且您 **不在 Web Mvc 环境中:
@Bean
ConversionService conversionService(ConversionServiceFactoryBean factory){
ConversionServiceFactoryBean factory = new ConversionServiceFactoryBean();
Set<Converter<?, ?>> convSet = new HashSet<Converter<?, ?>>();
convSet.add(new MyConverter()); // or reference bean convSet.add(myConverter());
factory.setConverters(convSet);
factory.afterPropertiesSet();
return factory.getObject();
}
回答by Anton
Also had problem with registration custom converter in xml config. Should to add converter id to annotation-driver
在 xml 配置中注册自定义转换器也有问题。应该将转换器 id 添加到 annotation-driver
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="ru.javawebinar.topjava.util.StringToLocalDateConverter"/>
</set>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService"/>
Reference links: Spring MVC. Type Conversion,Spring Core. Type Conversion