2016-08-01 69 views
8

Java語言從添加枚舉中受益匪淺;但不幸的是,在具有不同代碼級別的系統之間發送序列化對象時,它們不能很好地工作。在Java中有序列化枚舉的好方法嗎?

示例:假設您有兩個系統A和B.它們都以相同的代碼級別開始,但在某個時間點開始在不同時間點查看代碼更新。現在假設有一些

public enum Whatever { FIRST; } 

還有其他的對象,保持引用該枚舉的常量。這些對象被序列化並從A發送到B,反之亦然。現在考慮B具有無論新版本的

public enum Whatever { FIRST; SECOND } 

然後:

class SomethingElse implements Serializable { ... 
    private final Whatever theWhatever; 
    SomethingElse(Whatever theWhatever) { 
    this.theWhatever = theWhatever; .. 

被實例化......

SomethingElse somethin = new SomethingElse(Whatever.SECOND) 

,然後串行轉換髮送到A(例如,作爲一些RMI呼叫的結果)。這是不好的,因爲現在在A的反序列化過程中會出現一個錯誤:A知道任何枚舉類,但是在沒有SECOND的版本中。

我們認爲這很難;現在我非常渴望使用枚舉來實現「完美枚舉」的情況;只是因爲我知道我以後不能輕易擴展現有的枚舉。

現在我想知道:是否有(良好的)策略避免這種與枚舉的兼容性問題?或者我真的不得不回到「前枚舉」時代;並且不要使用枚舉,但必須依靠一個解決方案,我在整個地方使用普通的字符串?

更新:請注意,使用serialversionuid根本沒有幫助。這件事只會幫助你做出不相容的變化「更明顯」。但重點是:我不關心爲什麼反序列化失敗 - 因爲我必須避免它發生。而且我也無法改變我們序列化對象的方式。我們正在做RMI;我們正在序列化爲二進制;我無法改變這種情況。

+6

這不是任何類的問題嗎?如果您更改較新版本的字段,則舊版本的反序列化將失敗。 – 4castle

+0

不一定。添加字段是完全有效的操作。如果你使用純字符串,你顯然會減少編譯時間檢查;但是如果一個對象字段是String,那麼這個字段可以帶**任何**值而不會引起這樣的問題。 – GhostCat

+1

您可以使用常量 - 這些序列化很好,並且它們具有許多類枚舉屬性 –

回答

0

來回針對不同的解決方案後,我想出一個解決方案基於從@GuiSim的建議:可以建立一個包含枚舉值類。此類可以

  1. 做定製反序列化;因此,我可以防止不會有反序列化過程
  2. 提供像isValid()的getEnumValue(簡單的方法例外):第一個告訴你,如果反序列化的枚舉實際工作;第二個返回反序列化的枚舉(或拋出異常)
6

正如@Jesper在評論中提到的那樣,我會爲您的服務間通信推薦類似JSON的東西。這將允許您更好地控制如何處理未知的Enum值。

例如,使用始終真棒Jackson可以使用Deserialization FeaturesREAD_UNKNOWN_ENUM_VALUES_AS_NULLREAD_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE。兩者都將允許您的應用程序邏輯處理未知的枚舉值,只要您認爲合適。

例(直接從傑克遜DOC)

enum MyEnum { A, B, @JsonEnumDefaultValue UNKNOWN } 
... 
final ObjectMapper mapper = new ObjectMapper(); 
mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE); 

MyEnum value = mapper.readValue("\"foo\"", MyEnum.class); 
assertSame(MyEnum.UNKNOWN, value); 
+0

當然,但至少現在,我們的架構是如此;沒有這種根本性改變的機會。我們必須與序列化的對象生活多年... – GhostCat

+0

@GhostCat我想你可以使用[自定義Java反序列化](http://stackoverflow.com/questions/7290777/java-custom-serialization)來定義枚舉是如何反序列化以及未知值如何處理。 – GuiSim

+2

附錄:我認爲自定義序列化將**不**工作 - 枚舉的處理方式不同(請參閱http://stackoverflow.com/questions/15521309/is-custom-enum-serializable-too)它說*通過它的過程序列化的枚舉常量不能自定義*。 – GhostCat