java.io.InvalidClassException: clase local incompatible:

6 minutos de lectura

avatar de usuario de lonesome
solitario

Creé el cliente y el servidor y luego agregué una clase en el lado del cliente para fines de serialización, luego simplemente fui a la carpeta del cliente en mi disco duro y copié y pegué en la ubicación correspondiente del servidor, ambos classname.class y classname.java respectivamente.

Funcionó bien en mi propia computadora portátil, pero cuando quise continuar mi trabajo en otro sistema, cuando abrí las carpetas de proyectos y después de que el cliente intenta conectarse al servidor, aparece el siguiente error:

Exception in thread "main" java.io.InvalidClassException: projectname.clasname; local class incompatible: stream classdesc serialVersionUID = -6009442170907349114, local class serialVersionUID = 6529685098267757690
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)

¿Qué está pasando? ¿Es porque ejecuté el programa con una versión anterior del IDE?

EDITAR

import java.io.Serializable;
import java.net.URL;

public class KeyAdr implements Serializable {
  private static final long serialVersionUID = 6529685098267757690L;

  public URL adr;
  public String key;
}

avatar de usuario de Trutheality
verdadrealidad

Si una clase no define explícitamente un private static final long serialVersionUID en el código se generará automáticamente, y no hay garantía de que diferentes máquinas generen la misma identificación; parece que eso es exactamente lo que sucedió. Además, si las clases son diferentes de alguna manera (usando diferentes versiones de la clase), el autogenerado serialVersionUIDs también será diferente.

Desde el Serializable interfaz documentos:

Si una clase serializable no declara explícitamente un serialVersionUIDentonces el tiempo de ejecución de serialización calculará un valor predeterminado serialVersionUID valor para esa clase en función de varios aspectos de la clase, como se describe en la Especificación de serialización de objetos Java(TM). Sin embargo lo és muy recomendado que todas las clases serializables declaran explícitamente serialVersionUID valores, ya que el valor predeterminado serialVersionUID el cálculo es muy sensible a los detalles de la clase que pueden variar según las implementaciones del compilador y, por lo tanto, pueden generar resultados inesperados. InvalidClassExceptions durante la deserialización. Por lo tanto, para garantizar una consistencia serialVersionUID valor a través de diferentes implementaciones del compilador Java, una clase serializable debe declarar un explícito serialVersionUID valor. También se recomienda encarecidamente que sea explícito serialVersionUID Las declaraciones utilizan el private modificador cuando sea posible, ya que tales declaraciones se aplican solo a la clase que declara inmediatamente:serialVersionUID los campos no son útiles como miembros heredados. Las clases de matriz no pueden declarar un explícito serialVersionUIDpor lo que siempre tienen el valor calculado predeterminado, pero el requisito de coincidencia serialVersionUID los valores se renuncia para las clases de matriz.

Debes definir un serialVersionUID en la definición de clase, por ejemplo:

class MyClass implements Serializable {
    private static final long serialVersionUID = 6529685098267757690L;
    ...

  • ¿Cómo ajustar serialVersionUID en la definición?

    – solitario

    30 de abril de 2012 a las 5:36


  • Eso es extraño. Verificaría dos veces que ambos lados estén usando la versión más nueva de la clase.

    – veracidad

    30 de abril de 2012 a las 6:19

  • Incluso hice dos nuevos proyectos con el mismo nombre y creé las clases desde el principio, pero aún así sucede.

    – solitario

    30 de abril de 2012 a las 6:39

  • intente limpiar los resultados del proyecto (.class archivos generados en el momento de la compilación) y reconstruir (recompilar) los proyectos.

    – yair

    30 de abril de 2012 a las 6:47

  • @EJP no es recomendable tratar de hacer coincidir el SUID con una versión diferente de la clase. Actualizar la clase en ambos extremos fue lo correcto aquí.

    – veracidad

    30 de abril de 2012 a las 18:48

Una cosa que pudo haber pasado:

  • 1: crea sus datos serializados con una biblioteca A dada (versión X)
  • 2: luego intenta leer estos datos con la misma biblioteca A (pero la versión Y)

Por tanto, en tiempo de compilación para la versión X, la JVM generará un primer Serial ID (para la versión X) y hará lo mismo con la otra versión Y (otro Serial ID).

Cuando su programa intenta deserializar los datos, no puede porque las dos clases no tienen el mismo ID de serie y su programa no tiene garantía de que los dos objetos serializados correspondan al mismo formato de clase.

Suponiendo que haya cambiado su constructor mientras tanto y esto debería tener sentido para usted.

Si está utilizando el IDE de Eclipse, verifique su configuración de depuración/ejecución. En la pestaña Classpath, seleccione el proyecto ejecutor y haga clic en el botón Editar.
Incluir solo entradas exportadas debe ser revisado.

Intente eliminar/cambiar el nombre del archivo de salida y vuelva a crear uno nuevo si almacenó un objeto durante la prueba. Tuve este error porque había serializado datos en el mismo archivo en dos clases de jFrame diferentes.

Creo que esto sucede porque usa las diferentes versiones de la misma clase en el cliente y el servidor. Pueden ser diferentes campos de datos o métodos.

avatar de usuario de nawazish-stackoverflow
nawazish-stackoverflow

El mensaje de excepción habla claramente de que las versiones de la clase, que también incluirían los metadatos de la clase, han cambiado con el tiempo. En otras palabras, la estructura de clases durante la serialización no es la misma durante la deserialización. Esto es lo que probablemente “está pasando”.

avatar de usuario de jpaugh
jpaugh

La serialización en Java no está pensada como formato de transporte o persistencia a largo plazo; es demasiado frágil para esto. Con la más mínima diferencia en el código de bytes de clase y JVM, sus datos ya no se pueden leer. Utilice el enlace de datos XML o JSON para su tarea (XStream es rápido y fácil de usar, y hay un montón de alternativas)

  • Puedo estar de acuerdo hasta cierto punto con la persistencia, pero no hay nada de malo en usar la serialización de Java como formato de transporte. Es demasiado frágil si uno no conoce los conceptos de serialización de Java como serialVersionUID‘s.

    – Sanjay T. Sharma

    30 de abril de 2012 a las 6:43


  • No lo es, de verdad. Tal vez solo veamos el mundo de la ‘serialización de Java’ con lentes de diferentes colores. Además, es prácticamente la única opción cuando se usa RMI. Además, veo que hiciste un comentario sobre ‘jefe de proyecto desollando algo’ que se eliminó más tarde…

    – Sanjay T. Sharma

    30 de abril de 2012 a las 8:47

  • “La más mínima diferencia en el código de bytes de clase y JVM y sus datos ya no se pueden leer”. Esto es simplemente falso. Consulte la sección Control de versiones de objetos de la Especificación de serialización de objetos.

    – usuario207421

    30 de abril de 2012 a las 10:06

  • @EJP Aquí hay un enlace: Versionado de objetos serializables

    – jpaugh

    20 de septiembre de 2016 a las 14:12


¿Ha sido útil esta solución?