Je souhaite enregistrer un convertisseur Spring dans un projet Spring Boot par programme. Dans les projets de printemps précédents, je l'ai fait en XML comme ceci ...
<!-- 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>
J'essaie de comprendre comment faire dans SpringBootServletInitializer de Spring Boot
Mise à jour: J'ai un peu progressé en passant le StringToAssessmentConverter comme argument à getConversionService
, mais je reçois maintenant une erreur "No default constructor found"
pour la classe StringToAssessmentConverter. Je ne sais pas pourquoi Spring ne voit pas le constructeur @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;
}
}
Voici le code pour le convertisseur ...
@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;
}
}
}
Erreur complète
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>()
La réponse est qu'il vous suffit d'annoter votre convertisseur en tant que @Component
:
Ceci est mon exemple de convertisseur
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());
}
}
Ensuite, lorsque Spring doit convertir, le convertisseur est appelé.
Ma version de démarrage du printemps: 1.4.1
Voici ma solution:
Une annotation TypeConverter:
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface TypeConverter {
}
Un registraire de convertisseur:
@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);
}
}
}
}
Et annotez ensuite vos convertisseurs:
@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());
}
}
}
essaye ça:
@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;
}
}
}
}
ou si votre StringToAssessmentConverter est déjà un haricot de printemps:
@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();
}