クライアントにOracleデータベースがあり、オブジェクトがobjOutStream.writeObjectを介してblobフィールドとして永続化された場合、オブジェクトの現在の値はserialVersionUID
オブジェクトには何の変化、多分別のJVMのバージョン)を持っていないと、彼らは例外をデシリアライズしようとするとスローされます。オブジェクトが異なるserialVersionUIDを持つ場合にdb内で永続化されたオブジェクトのデコード方法
java.io.InvalidClassException: CommissionResult; local class incompatible:
stream classdesc serialVersionUID = 8452040881660460728,
local class serialVersionUID = -5239021592691549158
彼らは初めからserialVersionUID
ために固定値を割り当てていない今、いくつかのものは変更されるようにその例外がスローされます。現在、彼らはデータを失うことは望まないので、オブジェクトを読み込んでデシリアライズし、XMLEncoderで再び永続化して、現在の「クラス互換性のない」エラーのような将来のエラーを避けることをお勧めします。
明らかにそのオブジェクトのために保持されているserialVersionUID
の2つの異なる値がありますので、データを読み込み、1つの値で試してみて、失敗したら他の値で試してみてください。クラスのserialVersionUID
は the ASM apiを使用しています。私は値を変更することができましたが、問題はクラスの変更をアクティブにする方法です。逆シリアル化されている場合は、serializedVersionUID
のクラスの修正版をobjInpStr.readObject()
に取ります。
public class Reservation implements java.io.Serializable {
private CommissionResult commissionResult = null;
}
public class CommissionResult implements java.io.Serializable{
}
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.commons.SerialVersionUIDAdder;
public class SerialVersionUIDRedefiner extends ClassLoader {
public void workWithFiles() {
try {
Reservation res = new Reservation();
FileOutputStream f = new FileOutputStream("/home/xabstract/tempo/res.ser");
ObjectOutputStream out = new ObjectOutputStream(f);
out.writeObject(res);
out.flush();
out.close();
ClassWriter cw = new ClassWriter(0);
ClassVisitor sv = new SerialVersionUIDAdder(cw); //assigns a real serialVersionUID
ClassVisitor ca = new MyOwnClassAdapter(sv); //asigns my specific serialVerionUID value
ClassReader cr=new ClassReader("Reservation");
cr.accept(ca, 0);
SerialVersionUIDRedefiner loader= new SerialVersionUIDRedefiner();
byte[] code = cw.toByteArray();
Class exampleClass = loader.defineClass("Reservation", code, 0, code.length); //at this point the class Reservation has an especific serialVersionUID value that I put with MyOwnClassAdapter
loader.resolveClass(exampleClass);
loader.loadClass("Reservation");
DeserializerThread dt=new DeserializerThread();
dt.setContextClassLoader(loader);
dt.run();
} catch (Exception e) {
e.printStackTrace();
}}
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class DeserializerThread extends Thread {
public void run() {
try {
FileInputStream f2;
f2 = new FileInputStream("/home/xabstract/tempo/res.ser");
ObjectInputStream in = new ObjectInputStream(f2);
Reservation c1 = (Reservation)in.readObject();
System.out.println(c1);
} catch (Exception e) {
e.printStackTrace();
}
stop();
}
}
MyOwnClassAdapter Relevant code:
public void visitEnd() {
// asign SVUID and add it to the class
try {
cv.visitField(Opcodes.ACC_FINAL + Opcodes.ACC_STATIC,
"serialVersionUID",
"J",
null,
new Long(-11001));//computeSVUID()));
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException("Error while computing SVUID for x"
, e);
}
super.visitEnd();
}
テストをして失敗する必要があります私はオブジェクト名がプロパティが CommissionResult
あるReservation
です(プロパティとして異なるserialVersionUID
問題を持つオブジェクトを持つ)オブジェクトを取り、実環境をシミュレートするテストクラスを作りましたjava.io.InvalidClassException
「ローカルクラス互換性のない」 私は、ファイルを保存し、 ・デ・ファイルを読み取るための、新しいものを使用した後、私はserialVersionUID
を変えたが、それは失敗していないので、ObjectInputStream.readObject
がReservation
の私の修正版を使用して でないことを意味するので、クラス。
すべてのアイデア?前もって感謝します。
!!!!!!!!!!!!! UPDATE:私はその前に言ったように
[OK]を、奇妙ないくつかのことが起こる、ストリームのserialVersionUIDを上書きするresultClassDescriptorを再定義することは可能であるが、 があるようです。この最後の値が 私はローカルクラスに値を指定しない場合に生成1である2クラスのバージョン持続し、オブジェクトのserialVersionUID = -5239021592691549158Lとし、値8452040881660460728Lと他の人です。
- serialVersionUIDの値を指定しないと、デフォルト値(8452040881660460728L)が使用されますが、 に他の値があるオブジェクトを非表示にすることはできません。プロパティは他の型のものです。
- 値を-5239021592691549158Lに指定すると、その値が のクラスは正常にデシリアライズされますが、他のタイプではエラーは発生しません。同じタイプのエラーです。
潜在的に致命的なデシリアライズ操作:
これはエラートレースです。 java.io.InvalidClassException:直列化されたクラスバージョンの不一致を無効にする:local serialVersionUID = -5239021592691549158 stream serialVersionUID = 8452040881660460728 java.lang.ClassCastException:java.util.HashMapのインスタンスをcom.posadas.ic.rules.common.commisionRulesフィールドに代入できません。comのインスタンス内のjava.lang.String型の.CommissionResult.statusCode。posadas.ic.rules.common.commisionRules.CommissionResult
このエラーがスローされたとき8452040881660460728に変更 値はクラスが正常にデシリアライズされている、だから、何が起こる?場合、クラスは、-5239021592691549158の値を持っていたが間違ったクラスのキャストしようとするエラーはなぜですか?
おかげ
HEX形式で新しいシリアルUIDと古いUIDを編集し、置き換えることができ、HEX形式でシリアルUIDを見つけることができ、同様の質問ですhttp: //stackoverflow.com/questions/444909/java-modifying-serialversionuid-of-binary-serialized-object –
はい前にその質問を読んでいましたが、答えが見つからなかった、ダニエルは解決方法を見つけたが、詳細な方法と必要なもののようですが、私は彼に尋ねる方法が見つけられませんでした:S –