[英]If i changed the package of a java class. Will the deserialization from the old serialized version still work?
我在我的 java 項目中使用 aerospike 作為緩存。 我更改了我的緩存對象之一的包。 我在一台機器上部署了新代碼。 獲取序列化異常,因為緩存中存在舊的緩存對象。
我希望舊代碼在某些機器上運行,而在某些機器上運行新代碼,並且兩者都應該能夠在 aerospike 緩存中獲取/放置對象。
有沒有辦法實現這一目標? 為什么我會收到此異常。
類所屬的包是該類標識的基本部分,正如包名稱是類的完全限定名稱的一部分所反映的那樣。 出於所有實際意圖和目的,更改為類分配的包會刪除原始類並將其替換為完全不同的類。
特別是,如果您通過 Java 序列化序列化名為“my.package.MyClass”的類的實例,那么成功反序列化結果總是會產生名為“my.package.MyClass”的類的實例。 如果不能加載這樣的類,或者如果加載的類的序列化版本與已序列化的類的版本不匹配,則反序列化將失敗。
如果您保留舊類和新類,那么您也許可以在新版本的應用程序中修補反序列化問題。 只需為舊類的對象做好准備,並在反序列化后立即將它們轉換為新類的實例。 但是如果你想讓新版本的應用程序和舊版本的應用程序一起玩,那么你也必須在新版本序列化受影響類的對象時進行相反的操作,否則只會導致舊應用程序出現反序列化錯誤。 在這一點上,您應該考慮更改包名稱是否真的那么重要。
總的來說,Java 序列化不太適合對象存儲。 它主要針對對象通信。 您可能會考慮切換到基於 XML、JSON 或 YAML 的序列化格式,至少您可以在緩存和使用者之間切換。 這樣的更改當然會與您的應用程序的舊版本不兼容,但顯然,您已經執行的包更改也是如此。
通常,序列化算法執行以下操作:
java.lang.object
。在反序列化期間,它將嘗試重新實例化該類,但由於包名稱已更改,因此無法找到元數據中指定的類並失敗。
查看以下工具可能是值得的: jDeserialize 。 它不會實例化流中描述的任何類; 相反,它構建了類型、實例和值的中間表示。 因此,它可以分析流而無需訪問生成它們的類代碼。
您可以將 ObjectInputStream 子類化並使用它來攔截 readClassDescriptor,如果被反序列化的類的包與您的不同,您可以更改它。 但是,如果被反序列化的類然后包含需要反序列化的其他類,則情況會變得更加復雜。
public class MyObjectInputStream extends ObjectInputStream {
public MyObjectInputStream(InputStream in) throws IOException {
super(in);
}
@Override
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
ObjectStreamClass resultClassDescriptor = super.readClassDescriptor();
String className = resultClassDescriptor.getName();
if (className.equals("my.old.pacakgename.MyClass")) {
return ObjectStreamClass.lookup(MyClass.class);
}
return resultClassDescriptor;
}
}
要使用這個
ObjectInputStream ois = new MyObjectInputStream(stream);
MyClass myObject = (MyClass) ois.readObject();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.