java 所有枚举的 Spring 自定义转换器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5178622/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 09:51:04  来源:igfitidea点击:

Spring custom converter for all Enums

javaspring

提问by David Parks

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 purposes (thus avoiding changes due to order/name change with regards to external storage of the enum).

我已经使用int getID()MyEnum withID(int)方法构建了许多 Enum 类,这些方法允许我将 ID 专用于枚举值以用于持久性目的(从而避免由于枚举外部存储的顺序/名称更改而导致的更改)。

I'd like to build a custom converter that does some reflection to look for these methods, and use them or back up to Ordinal/String conversions when they are not found.

我想构建一个自定义转换器,它会进行一些反射以查找这些方法,并在找不到它们时使用它们或备份到序数/字符串转换。

Does a generic Enum converter seem possible to anyone? This is only my second foray into Converters.

任何人都可以使用通用的 Enum 转换器吗?这只是我第二次涉足转换器。

采纳答案by Sean Patrick Floyd

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.

我会说你试图解决错误的问题。我通常将枚举坚持为字符串,从而首先避免这个问题。缺点当然是更大的 DB 字段,但这并不重要。



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.

我会说一般来说这是可能的,但不是以一种干净的方式。我要做的是让所有这些枚举实现一个通用接口(或者只是一个标记接口或一个包含该int getId()方法的接口)。现在只为这个接口注册你的 PropertyEditor,这样你就不会破坏太多的标准功能。

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:

然后,您的下一个问题是您依赖于静态工厂方法,这是无法以通用方式完成的。当然,您的 PropertyEditor 可以:

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

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

但我会称之为非常hacky。这样的事情怎么样:

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:

更新:使用新的转换器 SPI,它变得更容易。使用自定义 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>

回答by BaiJiFeiLong

Extended from WebMvcConfigurerAdapter

从 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);
}