Spring custom converter for all Enums

前端 未结 2 1990
孤城傲影
孤城傲影 2020-12-29 06:21

I\'ve built many Enum classes with int getID() and MyEnum withID(int) methods that allow me to dedicate an ID to the enum values for persistence pu

相关标签:
2条回答
  • 2020-12-29 06:37

    I'd say you are trying to solve the wrong problem. I usually persist enums as Strings and thereby avoid this problem in the first place. The drawback is of course a larger DB field, but that's hardly significant.


    That said:

    I'd say it's possible in general, but not in a clean way. What I'd do is let all these enums implement a common interface (either just a marker interface or one that contains the int getId() method). Now register your PropertyEditor for this interface only, then you're not breaking too much standard functionality.

    Then, your next problem is that you are relying on static factory methods, which can not be done in a generic way. Of course your PropertyEditor can do:

    enumClass.getDeclaredMethod("withId", int.class).invoke(id)
    

    but I'd call that very hacky. How about something like this:

    Object target = null;
    for(Object e : EnumSet.allOf(yourEnumClass)){
        if(e instanceof MyInterface && ((MyInterface)e).getId()==thisId){
            target = e;
            break;
        }
    }
    return target;
    

    Now you are not using any static factory methods and you have compile time safety, as long as your enums implement a common interface.


    Update: with the new Converter SPI it gets easier. Use a custom ConverterFactory:

    public class CustomEnumConverterFactory implements
        ConverterFactory<String, Enum<?>>{
    
        @Override
        public <T extends Enum<?>> Converter<String, T> getConverter(
            final Class<T> targetType){
            return WithId.class.isAssignableFrom(targetType)
                ? new EnumWithIdConverter(targetType)
                : new StandardEnumConverter(targetType);
        }
    
    }
    

    Register it like this:

    <bean id="conversionService"
        class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <!-- converters is a set of both converters and converterfactories -->
            <bean class="foo.bar.CustomEnumConverterFactory" />
        </property>
    </bean>
    
    0 讨论(0)
  • 2020-12-29 06:46

    Extended from WebMvcConfigurerAdapter

    @Override
    @SuppressWarnings("unchecked")
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(new ConverterFactory<String, Enum>() {
            @Override
            public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
                return source -> {
                    try {
                        return (T) Enum.valueOf(targetType, source);
                    } catch (Exception e) {
                        return targetType.getEnumConstants()[Integer.parseInt(source)];
                    }
                };
            }
        });
        super.addFormatters(registry);
    }
    
    0 讨论(0)
提交回复
热议问题