【问题标题】:Spring custom converter for all Enums所有枚举的 Spring 自定义转换器
【发布时间】:2011-07-07 21:49:40
【问题描述】:

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

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

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

【问题讨论】:

  • +1。我特别喜欢您“避免因订单/名称而更改”

标签: java spring


【解决方案1】:

我想说您正在尝试解决错误的问题。我通常将枚举保留为字符串,从而首先避免这个问题。缺点当然是更大的 DB 字段,但这并不重要。


也就是说:

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

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

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

但我认为这很 hacky。像这样的东西怎么样:

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

现在你没有使用任何静态工厂方法,并且你有编译时安全,只要你的枚举实现一个公共接口。


更新:使用新的 Converter SPI 变得更容易。使用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);
    }

}

这样注册:

<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>

【讨论】:

  • 出色的反应。谢谢!一个问题,Converter 接口似乎没有让我知道它试图将 String 转换为什么 Enum 类型。您提到了 Property Editors,我应该研究 Property Editors 而不是在春季尝试使用较新的 Converter SPI 吗?例如,值 [1] 可能对 10 个不同的 Enum 类有效。
  • @David 哦,我的错,我对转换器 SPI 还不太熟悉,我以为您的意思是 PropertyEditor。让我检查一下:-)
  • Converter SPI 非常简单,你只需实现接口:Converter 并注册它。但是它声明的唯一转换方法只传递 FromClass 并期望您派生一个 ToClass。因此没有传入 Enum> 或类似的东西。我想也许属性编辑器提供了一种不同的处理方式。我以前从未看过它们。
  • @David 看到我的更新。不要注册转换器,注册转换器工厂。
  • 哦天才,你是我的新神! :) 感谢您指出这一点并努力帮助解决这个问题!我认为这是我在 SO 上遇到的最好的回应!
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-30
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 2022-07-06
    相关资源
    最近更新 更多