Java – how to deserialize an object’s database when an object has different serialversionuids

My client has an Oracle database and an object through objutstream Writeobject is persisted as a BLOB field. The object now has a different serialVersionUID (even if the object does not change, it may be a different JVM version). When they try to serialize, they throw an exception:

java.io.InvalidClassException: CommissionResult; local class incompatible: 
 stream classdesc serialVersionUID = 8452040881660460728,local class serialVersionUID = -5239021592691549158

They did not assign a fixed value to the serialVersionUID, because from now on, something has changed, and this exception is thrown Now they don't want to release any data. To do this, I think the best thing is to read objects, serialize them, and keep them again through the xmlencoder to avoid future errors like the current "class incompatibility" error

Obviously, there are two different values of serialVersionUID for this object, so I want to read the data and try to use one value. If it fails, I try to use other values To do this, I try to change the serialVersionUID of this class and use the ASM API I have been able to change the value, but the problem is how to make the class activate the change, so when it is deserialized, obyinpstr ReadObject () changes the modified version of my specific serializedversion uid I made a test class to simulate the real environment. I took an object (which has a serialVersionUID problem different from the object) with the object name reservation and the attribute 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();
    }

The test should fail and Java io. Invalidclassexception "local class incompatibility" because I changed the serialVersionUID after saving the file and used a new file de file, but it will not fail, so this means objectinputstream ReadObject is not a reservation class that uses my modified version

Any ideas? Thank you in advance

!!!!!!!!!!!!! to update:

OK, you can redefine the resultclassdescriptor to override the stream serialVersionUID, but some strange things happen. As I said earlier, the two versions of the class are persistent. The object and serialVersionUID = - 5239021592691549158l and other values are 8452040881660460728l. The last value is generated if I do not specify a value for the local class

– if I do not specify a value for serialVersionUID, the default value (8452040881660460728l) will be used, but it is impossible to undelete the object. If there is another value, an error will be thrown saying that the attribute is of another type

– if I specify a value of - 5239021592691549158l, the class persists that the value has been successfully deserialized, but it is not the same error type as other types

This is error tracking:

Potentially fatal deserialization operation java. io. Invalidclassexception: overwrite serialization class version mismatch: local serialVersionUID = - 5239021592691549158 stream serialVersionUID = 8452040881660460728 Java Lang.classcastexception: java.net cannot be util. An instance of HashMap is assigned to com posadas. ic. rules. common. commisionRules. CommissionResult. Statuscode, type Java Lang.string, for example, com posadas. ic. rules. common. commisionRules. CommissionResult

When this error is thrown, the value of the class is - 5239021592691549158. What happens if the value is changed to 8452040881660460728 and the class is successfully deserialized? Why does this error attempt to cast for the wrong class?

thank you

Solution

Jorge, I'm here http://forums.sun.com/thread.jspa?threadID=518416 A solution was found

Create the following classes in your project When creating an objectinputstream object, use decompressible InputStream instead of it. It uses the new version of ID class to deserialize the old object

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;
    }
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>