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; } }