usar - serialversionuid java




¿Qué es un serialVersionUID y por qué debería usarlo? (14)

Eclipse emite advertencias cuando falta un serialVersionUID .

La clase serializable Foo no declara un campo estático final serialVersionUID de tipo long

¿Qué es serialVersionUID y por qué es importante? Por favor, muestre un ejemplo donde faltar serialVersionUID causará un problema.


¿Qué es un serialVersionUID y por qué debería usarlo?

SerialVersionUID es un identificador único para cada clase, JVM usa para comparar las versiones de la clase, lo que garantiza que la misma clase se usó durante la serialización durante la Deserialización.

Especificar uno da más control, aunque JVM genera uno si no lo especificas. El valor generado puede diferir entre diferentes compiladores. Además, a veces, por alguna razón, solo desea prohibir la deserialización de objetos serializados antiguos [ backward incompatibility ], y en este caso solo tiene que cambiar el serialVersionUID.

Los javadocs para Serializable dicen :

el cálculo de serialVersionUID predeterminado es altamente sensible a los detalles de clase que pueden variar dependiendo de las implementaciones del compilador, y por lo tanto puede dar como resultado InvalidClassException inesperadas durante la deserialización.

Por lo tanto, debe declarar serialVersionUID porque nos da más control .

Este artículo tiene algunos buenos puntos sobre el tema.


En cuanto a un ejemplo en el que el serialVersionUID faltante podría causar un problema:

Estoy trabajando en esta aplicación Java EE que se compone de un módulo web que utiliza un módulo EJB . El módulo web llama al módulo EJB forma remota y pasa un POJO que implementa Serializable como un argumento.

Esta clase POJO's se empaquetó dentro del jar de EJB y dentro de su propio jar en el WEB-INF / lib del módulo web. En realidad, son la misma clase, pero cuando empaco el módulo EJB desempaqueto el frasco de este POJO para empaquetarlo junto con el módulo EJB.

La llamada al EJB estaba fallando con la excepción a continuación porque no había declarado su serialVersionUID :

Caused by: java.io.IOException: Mismatched serialization UIDs : Source
 (Rep.
 IDRMI:com.hordine.pedra.softbudget.domain.Budget:5CF7CE11E6810A36:04A3FEBED5DA4588)
 = 04A3FEBED5DA4588 whereas Target (Rep. ID RMI:com.hordine.pedra.softbudget.domain.Budget:7AF5ED7A7CFDFF31:6227F23FA74A9A52)
 = 6227F23FA74A9A52

La pregunta original ha pedido "por qué es importante" y "ejemplo" donde esta Serial Version ID sería útil. Bueno, he encontrado uno.

Supongamos que creas una clase de Car , la creas y la escribes en una secuencia de objetos. El objeto de coche aplanado permanece en el sistema de archivos durante algún tiempo. Mientras tanto, si la clase Car se modifica agregando un nuevo campo. Más adelante, cuando intenta leer (es decir, deserializar) el objeto Car aplanado, obtiene la java.io.InvalidClassException , ya que todas las clases serializables reciben automáticamente un identificador único. Esta excepción se produce cuando el identificador de la clase no es igual al identificador del objeto aplanado. Si realmente lo piensas, la excepción se produce debido a la adición del nuevo campo. Puede evitar que se produzca esta excepción controlando el control de versiones usted mismo declarando un serialVersionUID explícito. También hay un pequeño beneficio en el rendimiento al declarar explícitamente su serialVersionUID (porque no tiene que ser calculado). Por lo tanto, es una práctica recomendada agregar su propio serialVersionUID a sus clases de Serializable tan pronto como las cree como se muestra a continuación:

public class Car {
static final long serialVersionUID = 1L; //assign a long value
}

Los datos de campo representan alguna información almacenada en la clase. La clase implementa la interfaz Serializable , por lo que eclipse automáticamente ofrece declarar el campo serialVersionUID . Vamos a empezar con el valor 1 establecido allí.

Si no quieres que llegue esa advertencia, usa esto:

@SuppressWarnings("serial")

No puedo dejar pasar esta oportunidad de conectar el libro Effective Java (2da edición) de Josh Bloch. El Capítulo 11 es un recurso indispensable en la serialización de Java.

Para Josh, el UID generado automáticamente se genera en base a un nombre de clase, interfaces implementadas y todos los miembros públicos y protegidos. Cambiar cualquiera de estos de cualquier manera cambiará el serialVersionUID . Por lo tanto, no necesita meterse con ellos solo si está seguro de que no más de una versión de la clase será serializada (ya sea a través de procesos o recuperada del almacenamiento en un momento posterior).

Si los ignora por ahora, y luego descubre que necesita cambiar la clase de alguna manera pero mantiene la compatibilidad con la versión anterior de la clase, puede usar la herramienta serialver JDK para generar el serialVersionUID en la clase anterior y establecer explícitamente que en la nueva clase. (Dependiendo de sus cambios, es posible que también necesite implementar una serialización personalizada agregando métodos writeObject y readObject ; consulte javadoc Serializable o el capítulo 11 mencionado anteriormente).


No se moleste, el cálculo predeterminado es realmente bueno y suficiente para el 99,9999% de los casos. Y si tiene problemas, puede, como ya se ha dicho, introducir los UID según sea necesario (lo que es altamente improbable)


Primero necesito explicar la serialización.
La serialización permite convertir el objeto a transmisión, para enviar ese objeto a través de la red O Guardar en un archivo O guardar en DB para el uso de la letra.

Hay algunas reglas para la serialización .

  • Un objeto es serializable solo si su clase o su superclase implementa la interfaz Serializable

  • Un objeto es serializable (implementa la interfaz Serializable) incluso si su superclase no lo es. Sin embargo, la primera superclase en la jerarquía de la clase serializable, que no implementa la interfaz Serializable, DEBE tener un constructor sin argumentos. Si esto se viola, readObject () producirá una excepción java.io.InvalidClassException en tiempo de ejecución

  • Todos los tipos primitivos son serializables.

  • Los campos transitorios (con modificador transitorio) NO se serializan (es decir, no se guardan ni se restauran). Una clase que implementa Serializable debe marcar los campos transitorios de las clases que no admiten la serialización (por ejemplo, una secuencia de archivos).

  • Los campos estáticos (con modificador estático) no se serializan.

Cuando Object se serializa, JAVA Runtime Asocia el número de versión de serie que se llama serialVersionID.

Donde necesitemos serialVersionID: durante la deserialización para verificar que el remitente y el receptor son compatibles con respecto a la serialización. Si el receptor cargó la clase con un serialVersionID diferente, la deserialización terminará con la excepción InvalidClassCastException .
Una clase serializable puede declarar su propio serialVersionUID declarando explícitamente un campo llamado "serialVersionUID" que debe ser estático, final y de tipo long :.

Probemos esto con un ejemplo.

import java.io.Serializable;    
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String empname;
private byte empage;

public String getEmpName() {
    return name;
}
public void setEmpName(String empname) {
    this.empname = empname;
}
public byte getEmpAge() {
    return empage;
}
public void setEmpAge(byte empage) {
    this.empage = empage;
}

public String whoIsThis() {
    StringBuffer employee = new StringBuffer();
    employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old  "));
    return employee.toString();
}
}

Crear objeto Serialize

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Writer {
public static void main(String[] args) throws IOException {
    Employee employee = new Employee();
    employee.setEmpName("Jagdish");
    employee.setEmpAge((byte) 30);

    FileOutputStream fout = new 
FileOutputStream("/users/Jagdish.vala/employee.obj");
    ObjectOutputStream oos = new ObjectOutputStream(fout);
    oos.writeObject(employee);
    oos.close();
    System.out.println("Process complete");
}
}

Deserializ el objeto

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Reader {
public static void main(String[] args) throws ClassNotFoundException, 
IOException {
    Employee employee = new Employee();
    FileInputStream fin = new 
    FileInputStream("/users/Jagdish.vala/employee.obj");
    ObjectInputStream ois = new ObjectInputStream(fin);
    employee = (Employee) ois.readObject();
    ois.close();
    System.out.println(employee.whoIsThis());
 }
}    

NOTA: Ahora cambie el serialVersionUID de la clase Employee y guarde:

private static final long serialVersionUID = **4L**;

Y ejecutar la clase Reader. No ejecutar la clase Writer y obtendrá la excepción.

Exception in thread "main" java.io.InvalidClassException: 
com.jagdish.vala.java.serialVersion.Employee; local class incompatible: 
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)

Puede decirle a Eclipse que ignore estas advertencias de serialVersionUID:

Ventana> Preferencias> Java> Compilador> Errores / Advertencias> Problemas potenciales de programación

En caso de que no lo sepas, hay muchas otras advertencias que puedes habilitar en esta sección (o incluso que algunas se han reportado como errores), muchas son muy útiles:

  • Posibles problemas de programación: posible asignación booleana accidental
  • Posibles problemas de programación: acceso a puntero nulo
  • Código innecesario: la variable local nunca se lee
  • Código innecesario: cheque nulo redundante
  • Código innecesario: conversión innecesaria o 'instanceof'

y muchos más.


Si nunca necesitará serializar sus objetos a la matriz de bytes y enviarlos / almacenarlos, entonces no necesita preocuparse por eso. Si lo hace, entonces debe considerar su serialVersionUID ya que el deserializador del objeto lo comparará con la versión del objeto que tiene su cargador de clases. Lea más sobre esto en la especificación del lenguaje Java.


Si recibe esta advertencia en una clase en la que nunca piensa acerca de la serialización, y que no se declaró a sí mismo implements Serializable , a menudo se debe a que heredó de una superclase, que implementa Serializable. A menudo, entonces sería mejor delegar en un objeto de este tipo en lugar de utilizar la herencia.

Entonces, en lugar de

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

hacer

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

y en los métodos relevantes, llame a myList.foo() lugar de this.foo() (o super.foo() ). (Esto no cabe en todos los casos, pero aún así con bastante frecuencia.)

A menudo veo personas que extienden JFrame o algo así, cuando realmente solo necesitan delegar en esto. (Esto también ayuda para completar automáticamente un IDE, ya que JFrame tiene cientos de métodos, que no necesita cuando desea llamar a los personalizados en su clase).

Un caso en el que la advertencia (o el serialVersionUID) es inevitable es cuando se extiende desde AbstractAction, normalmente en una clase anónima, solo agregando el método actionPerformed. Creo que no debería haber una advertencia en este caso (ya que normalmente no se puede serializar y deserializar de manera confiable dichas clases anónimas en diferentes versiones de su clase), pero no estoy seguro de cómo el compilador podría reconocer esto.


¿Por qué usar SerialVersionUIDdentro de Serializableclase en Java?

Durante serialization, el tiempo de ejecución de Java crea un número de versión para una clase, de modo que pueda dessializarlo más tarde. Este número de versión se conoce como SerialVersionUIDen Java.

SerialVersionUIDSe utiliza para la versión de datos serializados. Solo puede des-serializar una clase si SerialVersionUIDcoincide con la instancia serializada. Cuando no declaramos SerialVersionUIDen nuestra clase, el tiempo de ejecución de Java lo genera para nosotros, pero no es recomendable. Se recomienda declarar SerialVersionUIDcomo private static final longvariable para evitar el mecanismo por defecto.

Cuando declara una clase Serializableimplementando una interfaz de marcador java.io.Serializable, el tiempo de ejecución de Java conserva la instancia de esa clase en el disco utilizando el mecanismo de serialización predeterminado, siempre que no haya personalizado el proceso utilizando la Externalizableinterfaz.

vea también Por qué usar SerialVersionUID dentro de la clase Serializable en Java

Código: javassist.SerialVersionUID


Cada vez que un objeto se serializa, el objeto se estampa con un número de ID de versión para la clase del objeto. Este ID se llama serialVersionUID y se calcula basándose en la información sobre la estructura de la clase. Supongamos que creó una clase de empleado y tiene la id. De versión # 333 (asignada por JVM). Ahora, cuando serialice el objeto de esa clase (Supongamos que el objeto de empleado), JVM le asignará UID como # 333.

Considere una situación: en el futuro necesitará editar o cambiar su clase y, en ese caso, cuando la modifique, JVM le asignará un nuevo UID (Supongamos que # 444). Ahora, cuando intenta deserializar el objeto de empleado, JVM comparará el ID de versión del objeto serializado (Objeto de empleado) (# 333) con el de la clase, es decir, # 444 (desde que se modificó). En comparación, JVM encontrará que ambas versiones de UID son diferentes y, por lo tanto, la deserialización fallará. Por lo tanto, si el programador define el serialVersionID para cada clase. Será igual incluso si la clase evoluciona en el futuro y, por lo tanto, JVM siempre encontrará que la clase es compatible con el objeto serializado aunque se cambie la clase. Para más información puede consultar el capítulo 14 de HEAD FIRST JAVA.


Sería bueno si CheckStyle pudiera verificar que el serialVersionUID en una clase que implementa Serializable tiene un buen valor, es decir, que coincida con lo que produciría el generador de id de la versión de serie. Si tiene un proyecto con muchos DTO serializables, por ejemplo, recordar eliminar el serialVersionUID existente y regenerarlo es una molestia, y actualmente la única manera (que conozco) de verificar esto es regenerar para cada clase y comparar con el viejo. Esto es muy muy doloroso.


SerialVersionUID se utiliza para el control de versiones de objeto. También puede especificar serialVersionUID en su archivo de clase. La consecuencia de no especificar serialVersionUID es que cuando agrega o modifica cualquier campo de la clase, la clase ya serializada no podrá recuperarse porque serialVersionUID generado para la nueva clase y para el viejo objeto serializado será diferente. El proceso de serialización de Java se basa en serialVersionUID correcto para recuperar el estado del objeto serializado y lanza la excepción java.io.InvalidClassException en caso de discrepancia de serialVersionUID

Lea más: http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ







serialversionuid