2011-03-03 30 views
15

我已經建立了許多枚舉類與int getID()MyEnum withID(int)方法,允許我專用ID爲枚舉值的持久性目的(從而避免由於命令/名稱更改有關外部存儲的枚舉)。春季自定義轉換器的所有枚舉

我想建立一個自定義轉換器,它會做一些反射來查找這些方法,並在找不到這些方法時使用它們或備份到序數/字符串轉換。

泛型Enum轉換器對任何人都可能嗎?這只是我第二次進入轉換器。

+1

+1擴展。我特別喜歡你「避免因訂單/姓名而發生的變化」_ – 2014-06-18 15:33:02

回答

15

我想說你正試圖解決錯誤的問題。我通常堅持把枚舉作爲Strings,從而避免了這個問題。缺點當然是一個更大的數據庫領域,但這並不重要。


這就是說:

我會說這是可能一般,但不是在一個乾淨的方式。我要做的就是讓所有這些枚舉實現一個通用接口(或者只是一個標記接口或一個包含int getId()方法的接口)。現在只需註冊您的PropertyEditor,然後您就不會破壞太多的標準功能。

然後,你的下一個問題是你依靠靜態工廠方法,這是不能用通用的方式完成的。當然,你的屬性編輯器可以做:

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

但我稱之爲非常哈克。怎麼樣是這樣的:

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

現在你沒有使用任何靜態工廠方法,你有編譯時的安全性,只要你的枚舉實現一個共同的接口。


更新:新轉換器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> 
+0

傑出的迴應。謝謝!一個問題,Converter接口似乎沒有給我任何方式來知道它試圖將字符串轉換爲什麼樣的枚舉類型。你提到Property Editors,我應該看看Property Editors,而不是試圖在春季使用更新的Converter SPI?例如,值[1]可能對10個不同的Enum類有效。 – 2011-03-03 09:49:28

+0

@大衛哦,我的壞,我不太熟悉轉換器SPI,我假設你的意思是一個PropertyEditor。讓我檢查:-) – 2011-03-03 09:51:34

+1

轉換器SPI非常簡單,您只需實現接口:Converter 並註冊它。但是它聲明的唯一轉換方法只傳入FromClass並且期望您派生ToClass。因此沒有傳入Enum 或類似的東西。我想也許財產編輯提供了一種處理事物的不同方式。我從來沒有看過他們。 – 2011-03-03 10:01:48

0

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