- java.io.InvalidClassException: CommissionResult; local class incompatible:
- stream classdesc serialVersionUID = 8452040881660460728,local class serialVersionUID = -5239021592691549158
他们没有为serialVersionUID分配一个固定的值,因为从现在开始,有些事情改变了这个异常被抛出.现在他们不想松开任何数据,要做到这一点,我认为最好的是读取对象,对它们进行序列化,并通过XMLEncoder再次保持它们,以避免像当前的“类不兼容”错误那样的未来错误.
显然,对于该对象,serialVersionUID持续存在2个不同的值,因此我想要读取数据,尝试使用一个值,如果失败,则尝试使用其他值.为此,我尝试更改该类的serialVersionUID运用
the ASM api.我已经能够更改值,但是问题是如何使类激活更改,所以当它被反序列化时,objInpStr.readObject()将我的特定serializedVersionUID的修改版本.我做了一个测试类来模拟真正的环境,我拿一个对象(其具有与对象具有不同的serialVersionUID问题的对象)对象名称是Reservation的属性是
CommissionResult:
- 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,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();
- }
测试应该失败,并且java.io.InvalidClassException“本地类不兼容”
因为我在保存文件之后更改了serialVersionUID,并使用了一个新的文件
de文件,但它不会失败,所以这意味着ObjectInputStream.readObject不是
使用我的修改版本的Reservation类.
有任何想法吗?提前致谢.
!!!!!!!!!!!!!更新:
好的,可以重新定义resultClassDescriptor来覆盖流serialVersionUID,但是有些奇怪的事情发生,正如我之前所说的那样
是类的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.CommissionResult.statusCode,类型为java.lang.String,例如com.posadas.ic.rules. common.commisionRules.CommissionResult
抛出此错误时,类的值为-5239021592691549158,如果更改
该值是8452040881660460728该类成功解除序列化,那么会发生什么?为什么这个错误试图为错误的类投射?
谢谢
解决方法
在你的项目中创建下面的类.在创建ObjectInputStream对象的时候,使用DecompressibleInputStream代替它,它使用新版本的Id类反序列化旧对象.
- public class DecompressibleInputStream extends ObjectInputStream {
- public DecompressibleInputStream(InputStream in) throws IOException {
- super(in);
- }
- protected ObjectStreamClass readClassDescriptor() throws IOException,ClassNotFoundException {
- ObjectStreamClass resultClassDescriptor = super.readClassDescriptor(); // initially streams descriptor
- Class localClass = Class.forName(resultClassDescriptor.getName()); // the class in the local JVM that this descriptor represents.
- if (localClass == null) {
- System.out.println("No local class for " + resultClassDescriptor.getName());
- return resultClassDescriptor;
- }
- ObjectStreamClass localClassDescriptor = ObjectStreamClass.lookup(localClass);
- if (localClassDescriptor != null) { // only if class implements serializable
- final long localSUID = localClassDescriptor.getSerialVersionUID();
- final long streamSUID = resultClassDescriptor.getSerialVersionUID();
- if (streamSUID != localSUID) { // check for serialVersionUID mismatch.
- final StringBuffer s = new StringBuffer("Overriding serialized class version mismatch: ");
- s.append("local serialVersionUID = ").append(localSUID);
- s.append(" stream serialVersionUID = ").append(streamSUID);
- Exception e = new InvalidClassException(s.toString());
- System.out.println("Potentially Fatal Deserialization Operation. " + e);
- resultClassDescriptor = localClassDescriptor; // Use local class descriptor for deserialization
- }
- }
- return resultClassDescriptor;
- }
- }