Mi cliente tiene una base de datos de Oracle y un objeto se conservó como un campo de blob a través de objOutStream.writeObject, el objeto ahora tiene un serialVersionUID
diferente (aunque el objeto no tiene ningún cambio, puede ser diferente versión de la JVM) y cuando tratan de des-serializar se produce una excepción:Cómo deserializar un objeto persistido en un db ahora cuando el objeto tiene un serialVersionUID diferente
java.io.InvalidClassException: CommissionResult; local class incompatible:
stream classdesc serialVersionUID = 8452040881660460728,
local class serialVersionUID = -5239021592691549158
ellos no asignó un valor fijo para serialVersionUID
desde el principio por lo que ahora que algo ha cambiado esa excepción se arroja. Ahora no quieren perder ningún dato, para hacerlo creo que lo mejor es leer los objetos, deserializarlos y persistirlos de nuevo a través de XMLEncoder para evitar futuros errores como el actual "clase incompatible".
Aparentemente hay 2 valores diferentes para el serialVersionUID
persistente para ese objeto, así que quiero leer los datos, pruebe con un valor y si falla intente con el otro valor, para hacerlo intenté cambiar el serialVersionUID
de la clase usando the ASM api. Pude cambiar el valor, pero el problema es cómo activar el cambio en la clase, por lo que cuando se deserializa, el objInpStr.readObject()
toma mi versión modificada de la clase con mi serializedVersionUID
específico. Hice una clase de prueba para simular el entorno real, tomo un objeto (que tiene como propiedad del objeto con diferentes serialVersionUID
problema) el nombre del objeto es Reservation
la propiedad es 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, 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();
}
La prueba debe fallar con java.io.InvalidClassException
la "clase local incompatibles" porque he cambiado el serialVersionUID
después de que salvé el archivo y se utiliza una nueva para leer de archivo pero no falla lo que significa que el ObjectInputStream.readObject
no es usando mi versión modificada del Reservation
clase.
alguna idea? Gracias por adelantado.
!!!!!!!!!!!!! ACTUALIZACIÓN:
Ok, es posible redefinir el resultClassDescriptor para anular el serialVersionUID corriente, pero, algo extraño sucede, como he dicho antes parece que son 2 versiones de la clase persistente, objetos con serialVersionUID = -5239021592691549158L y otros con valor 8452040881660460728L este último valor es el generado si no especifico un valor para la clase local.
-Si no especifica un valor para el serialVersionUID entonces el valor por defecto (8452040881660460728L) se utiliza, pero no es posible des-serealize los objetos que tiene otro valor, se emite un error decir que una la propiedad es de otro tipo.
-Si especifico el valor -5239021592691549158L, las clases persisten con ese valor se deserializaron con éxito, pero no los otros, el mismo error de tipos.
esta es la traza de error:
Operación Deserialización potencialmente fatal. java.io.InvalidClassException: sobrescribir la versión de clase serializada no coincidente: local serialVersionUID = -5239021592691549158 stream serialVersionUID = 8452040881660460728 java.lang.ClassCastException: no se puede asignar la instancia de java.util.HashMap al campo com.posadas.ic.rules.common.commisionRules .CommissionResult.statusCode de tipo java.lang.String en instancia de com.posadas.ic.rules.common.commisionRules.CommissionResult
Cuando este error fue arrojado a la clase tenido el valor de -5239021592691549158, si el cambio el valor de 8452040881660460728 la clase es de-serializado con éxito, así que, ¿qué ocurre? ¿Por qué ese error intenta arrojar la clase equivocada?
Gracias
Aquí es una pregunta similar http: //stackoverflow.com/questions/444909/java-modifying-serialversionuid-of-binary-serialized-object –
Sí, leí esa pregunta antes, pero no encontré respuesta, Daniel dijo que había encontrado la manera de resolverla, pero no lo hizo. t detalla cómo, y parece ser lo que necesito, pero no encontré la manera de preguntarle: S –