适用于所有Enums的Spring自定义转换器

Dav*_*rks 16 java spring

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

我想构建一个自定义转换器来做一些反射来查找这些方法,并在找不到它们时使用它们或备份到Ordinal/String转换.

一个通用的Enum转换器似乎对任何人都有可能吗?这只是我对转换器的第二次尝试.

Sea*_*oyd 15

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


那说:

我会说这一般是可能的,但不是一个干净的方式.我要做的是让所有这些枚举实现一个公共接口(只是一个标记接口或一个包含该int getId()方法的接口).现在仅为此接口注册PropertyEditor,然后您不会破坏太多标准功能.

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

enumClass.getDeclaredMethod("withId", int.class).invoke(id)
Run Code Online (Sandbox Code Playgroud)

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

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

现在您没有使用任何静态工厂方法,只要您的枚举实现了一个通用接口,您就具有编译时安全性.


更新:使用新的Converter 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);
    }

}
Run Code Online (Sandbox Code Playgroud)

像这样注册:

<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>
Run Code Online (Sandbox Code Playgroud)

  • @David看到我的更新.不要注册转换器,注册converterfactory. (2认同)

Bai*_*ong 5

扩展自 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);
}
Run Code Online (Sandbox Code Playgroud)