Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Como configurar Enum Converter com Spring usando classes sem XML

Bom dia,

Gostaria de saber se existe uma forma de configurar o enum converter do spring, pois não estou conseguindo salvar enums no banco com a minha configuração atual.

Toda minha configuração está em classes java e eu não consegui configurar o enum converter.

Classe de configuração do spring

@ComponentScan(basePackageClasses={HomeController.class,ClienteDAO.class})
public class AppWebConfiguration{

    @Bean
    public InternalResourceViewResolver internalResourceViewResolver(){
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

}

Classe de configurção do enum

@SuppressWarnings({"rawtypes", "unchecked"})
final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {

    public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToEnumConverter(targetType);
    }

    private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> {

        private Class<T> enumType;

        public StringToEnumConverter(Class<T> enumType) {
            this.enumType = enumType;
        }

        public T convert(String source) {
            return (T) Enum.valueOf(this.enumType, source.trim());
        }
    }
}

No meu caso falta implementar o conversion service

<bean id="conversionService"
          class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="br.com.caelum.contas.StringToEnumConverterFactory"/>
            </list>
        </property>
    </bean>

Queria saber se há uma maneira de implementar esse conversion service sem usar XML direto na classe AppWebConfiguration

2 respostas
solução!

Boa tarde Lucas,

Eu não cheguei a testar aqui ainda, mas, pelo que vi, dá pra fazer a configuração através de uma classe anotada com @Configuration com um método chamado getConversionService.

Por exemplo, se a configuração do XML for

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="converters.AddressToStringConverter" />
                <bean class="converters.StringToAddressConverter" />
            </list>
        </property>
    </bean>

A configuração por classe será:

@Configuration
public class ConversionConfiguration {

    @Bean(name="conversionService")
    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(new AddressToStringConverter());
        converters.add(new StringToAddressConverter());

        return converters;
    }
}

Veja se funciona e me avisa! E, se não funcionar, procuramos outra possível solução. :)

Obrigado pela atenção,

Eu resolvi o problema e agora funcionou normalmente, eu só utilizei a expressão do Spring no formulário e corrigi alguns detalhes na model, pois estava com o nome diferente na view e acho que estava dando conflito na hora de fazer o binding. Eu não precisei de nenhuma classe de configuração.

Segue o código de exemplo:

Model:

@Entity
public class Cliente {

//Outros atributos omitidos

    //Enum UF Definido para salvar como texto
    @Enumerated(EnumType.STRING) 
    private Uf uf;

public Uf getUf() {
        return uf;
    }

    public void setUf(Uf uf) {
        this.uf = uf;
    }

Na view dentro do form, lembrando de importar a tag do spring para formulários:

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

<div>
                    <label>UF</label>      
                         <form:select path="uf">
                            <form:option value="#" label="Selecione uma UF"/>
                            <form:options items="${uf}" />
                        </form:select>
                </div>

Assim ele recuperou e enviou corretamente os dados, salvando como string no banco todas as ufs do meu enum

Segue o código do enum:

public enum Uf {
    AC, AL, AM, AP, BA, CE, DF, ES, GO, 
    MA, MG, MS, MT, PA, PB, PE, PI, PR, 
    RJ, RN, RO, RR, RS, SC, SE, SP, TO
}

Controller

@RequestMapping(method=RequestMethod.POST)
    public ModelAndView gravar(MultipartFile arquivo, @Valid Cliente cliente,BindingResult res, RedirectAttributes redirectAttributes){


        if (res.hasErrors()){
            return form(cliente);
        }

        fileSaver.write("arquivosCliente", arquivo);
        clientesDao.gravar(cliente);    
        redirectAttributes.addFlashAttribute("sucesso","Cliente cadastrado com sucesso!");
        return new ModelAndView("redirect:form");
    }