2010-05-17 66 views
0

當我繼承下面的代碼(和使用它存儲的數據,即A的序列化實例):跳過新瞬態字段反序列化

class A implements Serializable { 
    private static final long serialVersionUID = 1L; 
    int someField; 
    B b; 
} 

class B implements Serializable { 
    private static final long serialVersionUID = 1L; 
    int someField; 
} 

在某些時候我意識到,在Ab字段不應該實際上堅持(和B不應該是可序列化的話),所以我改變的東西:

class A implements Serializable { 
    private static final long serialVersionUID = 1L; 
    int someField; 
    transient B b; 
} 

class B { 
    int someField; 
} 

如果我做的A一個新的實例,並對其進行序列化,我沒有問題反序列化它。但是,如果我嘗試反序列化的已存儲的老代碼A情況下,我得到以下形式的除外:

java.io.InvalidClassException: B; B; class invalid for deserialization 
    at java.io.ObjectStreamClass.checkDeserialize(Unknown Source) 
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
    at java.io.ObjectInputStream.readObject0(Unknown Source) 
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source) 
    at java.io.ObjectInputStream.readSerialData(Unknown Source) 
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
    at java.io.ObjectInputStream.readObject0(Unknown Source) 
    at java.io.ObjectInputStream.readObject(Unknown Source) 

我相信這是因爲持續的數據也有A的和B的類的描述存儲,並且那些仍然認爲b是持久的,即使在當前版本中它們不再是(參見ObjectStreamClass中的行600到606)

是否有強制A的反序列化跳過字段的方法現在暫時?例如,是否有一種方法可以覆蓋反序列化代碼在ObjectInputStream中讀取的類描述,並更新其定義b,以便知道其瞬態?

回答

2

在反序列化過程中跳過某些字段沒有任何竅門。實際上,對類的源代碼所做的任何更改(幾乎)都會使舊的序列化數據無法反序列化。序列化將您的源代碼與串行化數據緊密耦合。

這就是序列化不適合長期數據存儲的原因。序列化僅適用於RMI(通過網絡傳輸對象)或磁盤上的臨時存儲器之類的內容。使用記錄完好的(標準)文件格式而不是Java序列化來進行長期數據存儲。

你可以做的是使用舊代碼反序列化數據,然後將其寫入另一種格式,然後只使用該格式。

+0

我最終編寫了一個「修復」任務,讀取和寫回A/B類的類定義,它們是向後/向前兼容的(b字段是暫時的,但B仍被標記爲實現Serializable) ,然後我能夠從B中移除Serializable實現,現在沒有一個A的持久實例有B的實例。 – 2010-05-18 13:39:57

0

這就是爲什麼使用序列化進行長期對象存儲是一個壞主意。就你而言,我認爲把B作爲可序列化(即使A中的引用是暫態的)足以解決你的問題。

此外,您可能會想要實現您自己的readObject方法,以便在舊數據出現的情況下將B清零。

我不知道是否有可能實現一個自定義的readObject方法,在面對這樣的錯誤時實際上會恢復類。它肯定會非常混亂。