2015-10-15 20 views
1

我有一個可序列化的類。當類字段的數據類型改變時處理反序列化

public class Customer implements Externalizable { 

private static final long serialVersionUID = 1L; 

    private String id; 
    private String name; 

    public String getId() { 
     return id; 
    } 

    public void setId(String id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 


    public void setName(String name) { 
     this.name = name; 
    } 


    @Override 
    public String toString() { 
     return "id : "+id+" name : "+name ; 
    } 

    @Override 
    public void readExternal(ObjectInput in) throws IOException, 
      ClassNotFoundException { 
      this.setId((String) in.readObject()); 
      this.setName((String) in.readObject());  
    } 

    @Override 
    public void writeExternal(ObjectOutput out) throws IOException { 
     System.out.println("Reached here"); 
     out.writeObject(id); 
     out.writeObject(name); 
    } 


} 

我已經將該類的對象序列化爲一個文件。現在我已將名稱的數據類型從字符串更改爲列表。所以,雖然反序列化,我得到一個類轉換異常,因爲它無法從字符串轉換爲列表。 我正在考慮在每次對類進行某些更改時更改類的版本,以便在readExternal中可以明確處理它。然而,儘管這個想法可能適用於簡單的類,但如果遇到較大的複雜類,它將會失敗。任何人都可以請提供一個更簡單的解決方案。

謝謝

+0

如果你有一個包含'String'的序列化對象,你如何期望它在反序列化時自動轉換爲'List'? –

+0

我不這樣做,但可以通過更改readExternal方法明確處理它。鏈接在這裏找到http://stackoverflow.com/questions/3678136/managing-several-versions-of-serialized-java-objects。這將適用於小型簡單的類,但我有一個複雜的類與許多內部類。所以需要一個更簡單可行的解決方案。 – Poulami

+0

如果你經常改變你的課程,那就有一種誤解。如果這是一次性遷移,那麼您將不會有比明確處理更好的解決方案。 –

回答

4

你只需要自己管理不同的可能性(並執行適當的轉換)。

@Override 
public void readExternal(ObjectInput in) throws IOException, 
    ClassNotFoundException { 
    this.setId((String) in.readObject()); 
    Object nameField = in.readObject(); 
    if (nameField != null) { 
    boolean resolved = false; 
    if (nameField instanceof String) { 
     ArrayList<String> list = new ArrayList<String>(); // Or whatever you want to for converting the String to list. 
     list.add((String)nameField); 
     this.setName(list); 
     resolved = true; 
    } 
    if (nameField instanceof List) { 
     this.setName((List<String>) nameField); 
     resolved = true; 
    } 
    if (!resolved) { 
     throw new Exception("Could not deserialize " + nameField + " into name attribute"); 
    } 
    } 
} 
0

我建議你看看不同的不同的序列化引擎,例如Protocol BuffersApache AvroApache Thrift

其他可能性:使用策略模式來選擇序列化算法並委託給它/writeExternal。但是你仍然需要一個「選擇器」。類標識符(全名?)和版本通常是頂級候選者,但是序列化佈局(即String + StringString + List)也是替代方案。

0

您最好實現一個遷移工具,用於將序列化對象從一個版本轉換爲另一個版本(將其反序列化爲舊類的實例,然後創建新類的實例並複製字段)。保持簡單,不需要過於聰明的代碼。

我還建議您不要在您的readExternal方法中實施遷移算法,以更好地分離問題,更不用提最有可能改進的性能,因爲您可以並應該省略readExternal,因爲反序列化提供程序通常做得很好並且除非您不反序列化同一個舊對象,否則該分支(它是版本x還是y?)只會產生一次「舊」分支,但是會對每個反序列化進行評估。最後但並非最不重要的一點是:你沒有的代碼是你不需要維護的代碼 - >改進的可維護性。

btw:serialVersionUID字段的思想是爲反序列化實現提供一個提示,即序列化對象不能被反序列化爲同一個類的實例,因爲它已經改變了(因此使它成爲具有相同名稱的不同類)。如果在進行更改時不更改版本字段,則完全沒有用處,您可以將其設置爲0或任何常數,並且永遠不要觸摸它。

相關問題