web-dev-qa-db-fra.com

Enregistrer le convertisseur de printemps par programme dans Spring Boot

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>()
8
jpolete

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

18
deFreitas

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());
        }
    }
}
1
narduk

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();
}
0
MangEngkus