¿Qué causa java.lang.IncompatibleClassChangeError?


Estoy empaquetando una biblioteca Java como un JAR, y está lanzando muchos java.lang.IncompatibleClassChangeError s cuando intento invocar métodos desde ella. Estos errores parecen aparecer al azar. ¿Qué tipo de problemas podrían estar causando este error?

Author: Pops, 2009-12-30

17 answers

Esto significa que ha realizado algunos cambios binarios incompatibles en la biblioteca sin recompilar el código del cliente. La especificación del lenguaje Java §13 detalla todos estos cambios, más prominentemente, cambiando los campos/métodos no-static no-privados para que sean static o viceversa.

Recompile el código del cliente con la nueva biblioteca, y debería estar listo.

ACTUALIZACIÓN: Si publica una biblioteca pública, debe evitar hacer cambios binarios incompatibles tanto como sea posible para preservar lo que se conoce como "compatibilidad binaria hacia atrás". La actualización de jars de dependencias por sí sola idealmente no debería romper la aplicación o la compilación. Si usted tiene que romper la compatibilidad binaria hacia atrás, esrecomendado para aumentar el número de versión principal (por ejemplo, de 1.x. y a 2.0.0) antes de lanzar el cambio.

 149
Author: notnoop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-23 09:21:50

Su biblioteca recién empaquetada no es compatible con binarios anteriores (BC) con la versión anterior. Por esta razón, algunos de los clientes de la biblioteca que no se recompilan pueden lanzar la excepción.

Esta es una lista completa de cambios en la API de bibliotecas Java que pueden hacer que los clientes creados con una versión antigua de la biblioteca arrojen java.lang. IncompatibleClassChangeError si se ejecutan en uno nuevo (es decir, rompiendo BC):

  1. El campo no final se convierte en estática,
  2. El campo no constante se vuelve no estático,
  3. Clase convertirse en interfaz,
  4. Interfaz convertirse en clase,
  5. si agrega un nuevo campo a la clase/interfaz (o agrega una nueva super-clase/super-interfaz), entonces un campo estático de una super-interfaz de una clase cliente C puede ocultar un campo agregado (con el mismo nombre) heredado de la super-clase de C (caso muy raro).

Nota: Hay muchas otras excepciones causados por otros incompatible cambios: NoSuchFieldError, NoSuchMethodError, IllegalAccessError, InstantiationError, excepción verifyerror, NoClassDefFoundError y AbstractMethodError.

El mejor artículo sobre BC es "Evolving Java-based APIs 2: Achieving API Binary Compatibility" escrito por Jim des Rivières.

También hay algunas herramientas automáticas para detectar tales cambios:

Uso de japi-compliance-checker para su biblioteca:

japi-compliance-checker OLD.jar NEW.jar

Uso de la herramienta clirr:

java -jar clirr-core-0.6-uber.jar -o OLD.jar -n NEW.jar

¡Buena suerte!

 92
Author: linuxbuild,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-20 08:57:38

Si bien todas estas respuestas son correctas, resolver el problema a menudo es más difícil. Generalmente es el resultado de dos versiones ligeramente diferentes de la misma dependencia en el classpath, y casi siempre es causado por una superclase diferente de la que se compiló originalmente en contra de estar en el classpath o alguna importación de que el cierre transitivo sea diferente, pero generalmente en la instanciación de clase y la invocación del constructor. (Después de la carga de clase exitosa y ctor invocación, obtendrá NoSuchMethodException o lo que sea.)

Si el comportamiento aparece al azar, es probable que sea el resultado de un programa multihilo que carga diferentes dependencias transitivas basadas en el código que se golpeó primero.

Para resolverlos, intente lanzar la VM con -verbose como argumento, luego mire las clases que se estaban cargando cuando se produce la excepción. Deberías ver información sorprendente. Por ejemplo, tener varias copias de la misma dependencia y versiones que nunca esperado o habría aceptado si supieras que estaban siendo incluidos.

Resolver jars duplicados con Maven se hace mejor con una combinación de maven-dependency-plugin y maven-enforcer-plugin bajo Maven (o el Plugin de Gráfico de dependencias de SBT , luego agregando esos jars a una sección de su POM de nivel superior o como elementos de dependencia importados en SBT (para eliminar esas dependencias).

¡Buena suerte!

 51
Author: Brian Topping,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-30 21:52:45

También he descubierto que, al usar JNI, invocando un método Java desde C++, si pasa parámetros al método Java invocado en el orden incorrecto, obtendrá este error cuando intente usar los parámetros dentro del método llamado (porque no serán el tipo correcto). Inicialmente me sorprendió que JNI no hiciera esta comprobación por usted como parte de la comprobación de firma de clase cuando invoca el método, pero asumo que no hacen este tipo de comprobación porque puede estar pasando parámetros polimórficos y tienen que asumir que sabes lo que estás haciendo.

Ejemplo de Código JNI en C++:

void invokeFooDoSomething() {
    jobject javaFred = FredFactory::getFred(); // Get a Fred jobject
    jobject javaFoo = FooFactory::getFoo(); // Get a Foo jobject
    jobject javaBar = FooFactory::getBar(); // Get a Bar jobject
    jmethodID methodID = getDoSomethingMethodId() // Get the JNI Method ID


    jniEnv->CallVoidMethod(javaFoo,
                           methodID,
                           javaFred, // Woops!  I switched the Fred and Bar parameters!
                           javaBar);

    // << Insert error handling code here to discover the JNI Exception >>
    //  ... This is where the IncompatibleClassChangeError will show up.
}

Ejemplo de código Java:

class Bar { ... }

class Fred {
    public int size() { ... }
} 

class Foo {
    public void doSomething(Fred aFred, Bar anotherObject) {
        if (name.size() > 0) { // Will throw a cryptic java.lang.IncompatibleClassChangeError
            // Do some stuff...
        }
    }
}
 4
Author: Ogre Psalm33,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-16 16:44:27

Tuve el mismo problema, y más tarde me di cuenta de que estoy ejecutando la aplicación en Java versión 1.4, mientras que la aplicación se compila en la versión 6.

En realidad, la razón era tener una biblioteca duplicada, una se encuentra dentro de la ruta de clase y la otra se incluye dentro de un archivo jar que se encuentra dentro de la ruta de clase.

 4
Author: Eng.Fouad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-16 11:04:42

Otra situación en la que puede aparecer este error es con la cobertura de Código Emma.

Esto sucede cuando se asigna un objeto a una interfaz. Supongo que esto tiene algo que ver con el Objeto que está siendo instrumentado y ya no es compatible con binarios.

Http://sourceforge.net/tracker/?func=detail&aid=3178921&group_id=177969&atid=883351

Afortunadamente este problema no sucede con Cobertura, así que he añadido cobertura-maven-plugin en mis plugins de informes de mi pom.xml

 1
Author: stivlo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-08 12:33:32

Me he enfrentado a este problema al deshacer y redesplegar una guerra con glassfish. Mi estructura de clases era así,

public interface A{
}

public class AImpl implements A{
}

Y se cambió a

public abstract class A{
}

public class AImpl extends A{
}

Después de detener y reiniciar el dominio, funcionó bien. Estaba usando glassfish 3.1.43

 1
Author: Nerrve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-06 07:20:55

Tengo una aplicación web que se despliega perfectamente bien en el tomcat de mi máquina local(8.0.20). Sin embargo, cuando lo puse en el entorno qa (tomcat - 8.0.20), siguió dándome el IncompatibleClassChangeError y se quejaba de que estaba extendiendo en una interfaz. Esta interfaz fue cambiada a una clase abstracta. Y compilé las clases de padres e hijos y aún así seguí recibiendo el mismo tema. Finalmente, quería depurar, así que cambié la versión del padre a x. 0.1-INSTANTÁNEA y luego compilado todo y ahora está funcionando. Si alguien sigue golpeando el problema después de seguir las respuestas dadas aquí, asegúrese de que las versiones en su pom.xml también son correctos. Cambia las versiones para ver si funciona. Si es así, solucione el problema de la versión.

 1
Author: Jobin Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-25 19:04:57

Mi respuesta, creo, será Intellij específica.

Había reconstruido clean, incluso yendo tan lejos como para eliminar manualmente los dirs "out" y "target". Intellij tiene un "invalidar cachés y reiniciar", que a veces borra errores extraños. Esta vez no funcionó. Todas las versiones de dependencias se veían correctamente en el menú configuración del proyecto->módulos.

La respuesta final fue eliminar manualmente mi dependencia problemática de mi repositorio maven local. Una versión antigua de bouncycastle era el culpable (sabía que acababa de cambiar las versiones y que sería el problema) y aunque la versión anterior no apareció en ninguna parte de lo que se estaba construyendo, resolvió mi problema. Estaba usando intellij versión 14 y luego actualizado a 15 durante este proceso.

 1
Author: David Nickerson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-16 20:28:12

En mi caso, me encontré con este error de esta manera. pom.xml de mi proyecto definió dos dependencias A y B. Y tanto A como B definieron la dependencia del mismo artefacto (llámelo C) pero diferentes versiones del mismo (C.1 y C.2). Cuando esto sucede, para cada clase en C maven solo puede seleccionar una versión de la clase de las dos versiones (mientras construye un uber-jar). Seleccionará la versión "más cercana" basada en sus reglas mediación de dependencias y generará una advertencia "Tenemos una clase duplicada..." Si una firma de método/clase cambia entre las versiones, puede causar una excepción java.lang.IncompatibleClassChangeError si se usa la versión incorrecta en tiempo de ejecución.

Avanzado: Si A debe usar v1 de C y B debe usar v2 de C, entonces debemos reubicar C en A y B's poms para evitar conflictos de clases (tenemos una advertencia de clase duplicada) al construir el proyecto final que depende tanto de A como de B.

 1
Author: morpheus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:08

Compruebe si su código no consiste en dos proyectos de módulos que tengan los mismos nombres de clases y la misma definición de paquetes. Por ejemplo, esto podría suceder si alguien usa copiar y pegar para crear una nueva implementación de interfaz basada en la implementación anterior.

 0
Author: denu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-25 07:56:49

Si esto es un registro de posibles ocurrencias de este error entonces:

Acabo de recibir este error en FUE (8.5.0.1), durante la carga CXF (2.6.0) de la configuración de spring (3.1.1_release) donde una BeanInstantiationException rodó una CXF ExtensionException, rodando un IncompatibleClassChangeError. El siguiente fragmento muestra la esencia del seguimiento de pila:

Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.apache.cxf.bus.spring.SpringBus]: Constructor threw exception; nested exception is org.apache.cxf.bus.extension.ExtensionException
            at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:162)
            at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:76)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:990)
            ... 116 more
Caused by: org.apache.cxf.bus.extension.ExtensionException
            at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:167)
            at org.apache.cxf.bus.extension.Extension.getClassObject(Extension.java:179)
            at org.apache.cxf.bus.extension.ExtensionManagerImpl.activateAllByType(ExtensionManagerImpl.java:138)
            at org.apache.cxf.bus.extension.ExtensionManagerBus.<init>(ExtensionManagerBus.java:131)
            [etc...]
            at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
            ... 118 more

Caused by: java.lang.IncompatibleClassChangeError: 
org.apache.neethi.AssertionBuilderFactory
            at java.lang.ClassLoader.defineClassImpl(Native Method)
            at java.lang.ClassLoader.defineClass(ClassLoader.java:284)
            [etc...]
            at com.ibm.ws.classloader.CompoundClassLoader.loadClass(CompoundClassLoader.java:586)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:658)
            at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:163)
            ... 128 more

En este caso, la solución fue cambiar el orden de classpath del módulo en mi archivo war. Es decir, abrir el war aplicación en la consola WAS en y seleccione el módulo cliente(s). En la configuración del módulo, establezca la carga de clase como "padre último".

Esto se encuentra en la consola WAS:

  • Aplicaciones -> Tipos de aplicaciones - > Aplicaciones WebSphere Enterprise
  • Haga clic en el enlace que representa su solicitud (war)
  • Haga clic en" Administrar módulos "en la sección" Módulos "
  • Haga clic en el enlace para los módulos subyacentes
  • Cambie "Orden del cargador de clases" para ser "(padre último)".
 0
Author: wmorrison365,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-20 16:38:23

Documentando otro escenario después de quemar demasiado tiempo.

Asegúrese de no tener un jar de dependencias que tenga una clase con una anotación EJB.

Teníamos un archivo jar común que tenía una anotación @local. Esa clase fue más tarde trasladada de ese proyecto común a nuestro proyecto principal de jar de ejb. Nuestra jarra ejb y nuestra jarra común se agrupan dentro de una oreja. La versión de nuestra dependencia de common jar no se actualizó. Así 2 clases tratando de ser algo con cambios incompatibles.

 0
Author: Snekse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-09 18:53:14

Todo lo anterior - por cualquier razón estaba haciendo un gran refactor y empezando a conseguir esto. Cambié el nombre del paquete en el que estaba mi interfaz y eso lo borró. Espero que eso ayude.

 0
Author: bsautner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-17 19:36:15

Por alguna razón, la misma excepción también se genera cuando se usa JNI y se pasa el argumento jclass en lugar del jobject cuando se llama a Call*Method().

Esto es similar a la respuesta de Ogre Psalm33.

void example(JNIEnv *env, jobject inJavaList) {
    jclass class_List = env->FindClass("java/util/List");

    jmethodID method_size = env->GetMethodID(class_List, "size", "()I");
    long size = env->CallIntMethod(class_List, method_size); // should be passing 'inJavaList' instead of 'class_List'

    std::cout << "LIST SIZE " << size << std::endl;
}

Sé que es un poco tarde para responder a esta pregunta 5 años después de ser preguntado, pero este es uno de los mejores éxitos cuando se busca java.lang.IncompatibleClassChangeError así que quería documentar este caso especial.

 0
Author: Eric Obermühlner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-23 19:03:32

Añadiendo mis 2 centavos .Si está utilizando scala y sbt y scala-logging como dependencia; entonces esto puede suceder porque la versión anterior de scala-logging tenía el nombre scala-logging-api.So; esencialmente, las resoluciones de dependencias no ocurren debido a los diferentes nombres que conducen a errores de tiempo de ejecución al iniciar la aplicación scala.

 0
Author: sourabh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-19 13:47:21

Una causa adicional de este problema, es si tiene Instant Run habilitado para Android Studio.

La solución

Si encuentra que comienza a recibir este error, desactive Instant Run.

  1. Configuración principal de Android Studio
  2. Compilación, Ejecución, Despliegue
  3. Ejecución instantánea
  4. Desmarca "Habilitar ejecución instantánea..."

Por qué

Instant Run modifica un gran número de cosas durante el desarrollo, para que sea más rápido proporcionar actualizaciones a su aplicación en ejecución. Ahí corre al instante. Cuando funciona, es realmente útil. Sin embargo, cuando un problema como este golpea, lo mejor que puede hacer es desactivar Instant Run hasta la próxima versión de Android Studio lanza.

 0
Author: Knossos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-27 11:14:58