¿Por qué obtengo un NoClassDefFoundError en Java?

NoClassDefFoundError un NoClassDefFoundError cuando ejecuto mi aplicación Java. ¿Cuál es típicamente la causa de esto?

Esto se produce cuando hay un archivo de clase del que depende su código y está presente en el momento de la comstackción, pero no se encuentra en el tiempo de ejecución. Busque diferencias en su tiempo de comstackción y classpaths en tiempo de ejecución.

Si bien es posible que esto se deba a una discrepancia de ruta de clase entre el tiempo de comstackción y el tiempo de ejecución, no es necesariamente cierto.

Es importante mantener dos o tres excepciones diferentes directamente en nuestra cabeza en este caso:

  1. java.lang.ClassNotFoundException Esta excepción indica que la clase no se encontró en classpath. Esto indica que estábamos tratando de cargar la definición de la clase, y la clase no existía en la ruta de clases.

  2. java.lang.NoClassDefFoundError Esta excepción indica que la JVM buscó en su estructura de datos de definición de clase interna la definición de una clase y no la encontró. Esto es diferente a decir que no se pudo cargar desde classpath. Por lo general, esto indica que previamente intentamos cargar una clase desde classpath, pero falló por alguna razón, ahora estamos tratando de usar la clase nuevamente (y por lo tanto necesitamos cargarla, ya que falló la última vez), pero nosotros ‘ ni siquiera intentaremos cargarlo, porque no lo cargamos antes (y sospechamos razonablemente que fallaríamos de nuevo). La falla anterior podría ser una ClassNotFoundException o un ExceptionInInitializerError (que indica una falla en el bloque de inicialización estática) o cualquier cantidad de otros problemas. El punto es que un NoClassDefFoundError no es necesariamente un problema de classpath.

Aquí está el código para ilustrar java.lang.NoClassDefFoundError . Por favor, mira la respuesta de Jared para una explicación detallada.

NoClassDefFoundErrorDemo.java

 public class NoClassDefFoundErrorDemo { public static void main(String[] args) { try { // The following line would throw ExceptionInInitializerError SimpleCalculator calculator1 = new SimpleCalculator(); } catch (Throwable t) { System.out.println(t); } // The following line would cause NoClassDefFoundError SimpleCalculator calculator2 = new SimpleCalculator(); } } 

SimpleCalculator.java

 public class SimpleCalculator { static int undefined = 1 / 0; } 

He descubierto que a veces obtengo un error NoClassDefFound cuando el código se comstack con una versión incompatible de la clase encontrada en tiempo de ejecución. La instancia específica que recuerdo es con la biblioteca del eje apache. En realidad, había 2 versiones en mi classpath en tiempo de ejecución y estaba recogiendo la versión desactualizada e incompatible y no la correcta, lo que causaba un error NoClassDefFound. Esto fue en una aplicación de línea de comandos donde estaba usando un comando similar a esto.

 set classpath=%classpath%;axis.jar 

Pude hacer que recoja la versión correcta usando:

 set classpath=axis.jar;%classpath%; 

NoClassDefFoundError en Java

Definición:

  1. Java Virtual Machine no puede encontrar una clase particular en tiempo de ejecución que estuvo disponible en tiempo de comstackción.

  2. Si una clase estuvo presente durante el tiempo de comstackción pero no está disponible en el classpath de java durante el tiempo de ejecución.

enter image description here

Ejemplos:

  1. La clase no está en Classpath, no hay forma segura de saberlo, pero muchas veces puedes echar un vistazo para imprimir System.getproperty (“java.classpath”) e imprimirá el classpath desde allí, al menos puedes obtener una idea de tu ruta de clase de tiempo de ejecución real.
  2. Un ejemplo simple de NoClassDefFoundError es que la clase pertenece a un archivo JAR faltante o JAR no se agregó a classpath o, a veces, el nombre de jar ha sido cambiado por alguien como en mi caso uno de mis colegas ha cambiado tibco.jar en tibco_v3.jar y el progtwig está fallando con java.lang.NoClassDefFoundError y me preguntaba qué pasa.

  3. Simplemente intente ejecutar con la opción explícitamente classpath con la ruta de clases que cree que funcionará y, si está funcionando, entonces es una señal segura de que alguien está anulando la ruta de clases de Java.

  4. El problema de permiso en el archivo JAR también puede causar NoClassDefFoundError en Java.
  5. Typo on XML Configuration también puede causar NoClassDefFoundError en Java.
  6. cuando su clase comstackda que se define en un paquete, no se presenta en el mismo paquete mientras se carga como en el caso de JApplet, arrojará NoClassDefFoundError en Java.

Soluciones posibles:

  1. La clase no está disponible en Java Classpath.
  2. Si está trabajando en un entorno J2EE, la visibilidad de Class entre múltiples Classloader también puede causar java.lang.NoClassDefFoundError, consulte la sección de ejemplos y escenarios para una discusión detallada.
  3. Busque java.lang.ExceptionInInitializerError en su archivo de registro. NoClassDefFoundError debido a la falla de la inicialización estática es bastante común.
  4. Como NoClassDefFoundError es una subclase de java.lang.LinkageError, también puede venir si una de sus dependencias, como la biblioteca nativa, no está disponible.
  5. Cualquier secuencia de comandos de inicio está anulando la variable de entorno Classpath.
  6. Puede ejecutar su progtwig utilizando el comando jar y la clase no estaba definida en el atributo ClassPath del archivo de manifiesto.

Recursos:

3 formas de resolver NoClassDefFoundError

java.lang.NoClassDefFoundError Patrones de problemas

Obtengo NoClassFoundError cuando las clases cargadas por el cargador de clases de tiempo de ejecución no pueden acceder a las clases ya cargadas por el cargador de raíz de Java. Debido a que los diferentes cargadores de clases se encuentran en diferentes dominios de seguridad (según java), el jvm no permitirá que las clases ya cargadas por el cargador de la raíz se resuelvan en el espacio de direcciones del cargador de tiempo de ejecución.

Ejecute su progtwig con ‘java -javaagent: tracer.jar [YOUR java ARGS]’

Produce resultados que muestran la clase cargada y el cargador env que cargó la clase. Es muy útil rastrear por qué una clase no se puede resolver.

 // ClassLoaderTracer.java // From: https://blogs.oracle.com/sundararajan/entry/tracing_class_loading_1_5 import java.lang.instrument.*; import java.security.*; // manifest.mf // Premain-Class: ClassLoadTracer // jar -cvfm tracer.jar manifest.mf ClassLoaderTracer.class // java -javaagent:tracer.jar [...] public class ClassLoadTracer { public static void premain(String agentArgs, Instrumentation inst) { final java.io.PrintStream out = System.out; inst.addTransformer(new ClassFileTransformer() { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { String pd = (null == protectionDomain) ? "null" : protectionDomain.getCodeSource().toString(); out.println(className + " loaded by " + loader + " at " + new java.util.Date() + " in " + pd); // dump stack trace of the thread loading class Thread.dumpStack(); // we just want the original .class bytes to be loaded! // we are not instrumenting it... return null; } }); } } 

Esta es la mejor solución que encontré hasta ahora.

Supongamos que tenemos un paquete llamado org.mypackage contiene las clases:

  • HelloWorld (clase principal)
  • SupportClass
  • UtilClass

y los archivos que definen este paquete se almacenan físicamente en el directorio D:\myprogram (en Windows) o /home/user/myprogram (en Linux).

La estructura del archivo se verá así: enter image description here

Cuando invocamos Java, especificamos el nombre de la aplicación para ejecutar: org.mypackage.HelloWorld . Sin embargo, también debemos indicarle a Java dónde buscar los archivos y directorios que definen nuestro paquete. Entonces, para lanzar el progtwig, debemos usar el siguiente comando: enter image description here

Estaba usando Spring Framework con Maven y resolví este error en mi proyecto.

Hubo un error de tiempo de ejecución en la clase. Estaba leyendo una propiedad como un entero, pero cuando se leyó el valor del archivo de propiedades, su valor fue doble.

Spring no me proporcionó un rastro de stack completa de la línea en la que falló el tiempo de ejecución. Simplemente dijo NoClassDefFoundError . Pero cuando lo ejecuté como una aplicación nativa de Java (sacándolo de MVC), dio ExceptionInInitializerError que era la verdadera causa y así es como tracé el error.

La respuesta de @xli me dio una idea de lo que podría estar mal en mi código.

En caso de que tenga código generado (EMF, etc.), puede haber demasiados inicializadores estáticos que consumen todo el espacio de la stack.

Consulte Pregunta de desbordamiento de stack ¿ Cómo boost el tamaño de stack de Java? .

La siguiente técnica me ayudó muchas veces:

 System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation()); 

donde TheNoDefFoundClass es la clase que podría “perderse” debido a una preferencia por una versión anterior de la misma biblioteca utilizada por su progtwig. Esto ocurre con mayor frecuencia en los casos en que el software del cliente se implementa en un contenedor dominante, armado con sus propios cargadores de clases y toneladas de versiones antiguas de las librerías más populares.

Si alguien viene aquí debido al error java.lang.NoClassDefFoundError: org/apache/log4j/Logger , en mi caso fue producido porque utilicé log4j 2 (pero no agregué todos los archivos que vienen con él), y algunos la biblioteca de dependencias usó log4j 1. La solución fue agregar el puente Log4j 1.x: el jar log4j-1.2-api-.jar que viene con log4j 2. Más información en la migración de log4j 2.

Dos copias de pago diferentes del mismo proyecto

En mi caso, el problema era la incapacidad de Eclipse de diferenciar entre dos copias diferentes del mismo proyecto. Tengo uno bloqueado en el tronco (control de versión SVN) y el otro trabajando en una twig a la vez. Probé un cambio en la copia de trabajo como un caso de prueba JUnit, que incluía la extracción de una clase interna privada para que fuera una clase pública por sí sola y, mientras estaba funcionando, abro la otra copia del proyecto para mirar a otra parte parte del código que necesitaba cambios. En algún momento, apareció el NoClassDefFoundError quejándose de que la clase privada interna no estaba allí; haciendo doble clic en el trazado de la stack me llevó al archivo fuente en la copia del proyecto equivocada.

Al cerrar la copia troncal del proyecto y ejecutar el caso de prueba nuevamente, se eliminó el problema.

Java no pudo encontrar la clase A en tiempo de ejecución. La clase A estaba en el proyecto Maven ArtClient de un espacio de trabajo diferente. Así que importé ArtClient en mi proyecto de Eclipse. Dos de mis proyectos usaban ArtClient como dependencia. Cambié la referencia de la biblioteca a la referencia del proyecto para estos (Ruta de comstackción -> Configurar ruta de comstackción).

Y el problema desapareció

Solucioné mi problema deshabilitando las bibliotecas preDex para todos los módulos:

 dexOptions { preDexLibraries true ... 

Tuve el mismo problema, y ​​estuve en stock por muchas horas.

Encontré la solución. En mi caso, se definió el método estático debido a eso. La JVM no puede crear el otro objeto de esa clase.

Por ejemplo,

 private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http"); 

Este error puede deberse a los requisitos de versión de Java no revisados .

En mi caso, pude resolver este error, mientras construía un proyecto abierto de alto perfil, cambiando de Java 9 a Java 8 usando SDKMAN. .

 sdk list java sdk install java 8u152-zulu sdk use java 8u152-zulu 

Luego haga una instalación limpia como se describe a continuación.


Al usar Maven como su herramienta de comstackción, a veces resulta útil, y por lo general gratificante, hacer una comstackción limpia de “instalación” con las pruebas deshabilitadas .

 mvn clean install -DskipTests 

Ahora que todo se ha construido e instalado, puede continuar y ejecutar las pruebas.

 mvn test 

Recibí este mensaje después de eliminar dos archivos de la biblioteca de SRC, y cuando los devolví, seguí viendo este mensaje de error.

Mi solución fue: reiniciar Eclipse. Desde entonces no he vuelto a ver este mensaje 🙂

Asegúrese de que coincida con el module:app y module:lib :

 android { compileSdkVersion 23 buildToolsVersion '22.0.1' packagingOptions { } defaultConfig { minSdkVersion 17 targetSdkVersion 23 versionCode 11 versionName "2.1" }