ClassNotFoundException frente a NoClassDefFoundError

1. Introducción

Tanto ClassNotFoundException como NoClassDefFoundError ocurren cuando la JVM no puede encontrar una clase solicitada en la ruta de clases. Aunque parecen familiares, existen algunas diferencias fundamentales entre estos dos.

En este tutorial, discutiremos algunas de las razones de sus ocurrencias y sus soluciones.

2. ClassNotFoundException

ClassNotFoundException es una excepción marcada que ocurre cuando una aplicación intenta cargar una clase a través de su nombre completo y no puede encontrar su definición en la ruta de clases.

Esto ocurre principalmente cuando se intenta cargar clases usando Class.forName () , ClassLoader.loadClass () o ClassLoader.findSystemClass () . Por lo tanto, debemos tener mucho cuidado con java.lang.ClassNotFoundException mientras trabajamos con la reflexión.

Por ejemplo, intentemos cargar la clase del controlador JDBC sin agregar las dependencias necesarias, lo que nos dará ClassNotFoundException:

@Test(expected = ClassNotFoundException.class) public void givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException() throws ClassNotFoundException { Class.forName("oracle.jdbc.driver.OracleDriver"); }

3. NoClassDefFoundError

NoClassDefFoundError es un error fatal. Ocurre cuando JVM no puede encontrar la definición de la clase mientras intenta:

  • Crea una instancia de una clase usando la nueva palabra clave
  • Cargar una clase con una llamada a un método

El error ocurre cuando un compilador pudo compilar correctamente la clase, pero el tiempo de ejecución de Java no pudo ubicar el archivo de la clase. Por lo general, sucede cuando hay una excepción al ejecutar un bloque estático o al inicializar campos estáticos de la clase, por lo que la inicialización de la clase falla.

Consideremos un escenario que es una forma sencilla de reproducir el problema. La inicialización de ClassWithInitErrors lanza una excepción. Entonces, cuando intentamos crear un objeto de ClassWithInitErrors, arroja ExceptionInInitializerError.

Si intentamos cargar la misma clase nuevamente, obtenemos NoClassDefFoundError:

public class ClassWithInitErrors { static int data = 1 / 0; }
public class NoClassDefFoundErrorExample { public ClassWithInitErrors getClassWithInitErrors() { ClassWithInitErrors test; try { test = new ClassWithInitErrors(); } catch (Throwable t) { System.out.println(t); } test = new ClassWithInitErrors(); return test; } }

Escribamos un caso de prueba para este escenario:

@Test(expected = NoClassDefFoundError.class) public void givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError() { NoClassDefFoundErrorExample sample = new NoClassDefFoundErrorExample(); sample.getClassWithInitErrors(); }

4. Resolución

A veces, diagnosticar y solucionar estos dos problemas puede llevar bastante tiempo. La razón principal de ambos problemas es la falta de disponibilidad del archivo de clase (en la ruta de clase) en tiempo de ejecución.

Echemos un vistazo a algunos enfoques que podemos considerar al tratar con cualquiera de estos:

  1. Necesitamos asegurarnos de si la clase o jar que contiene esa clase está disponible en la ruta de clases. Si no es así, debemos agregarlo
  2. Si está disponible en la ruta de clase de la aplicación, lo más probable es que se anule la ruta de clase. Para solucionarlo, necesitamos encontrar la ruta de clases exacta utilizada por nuestra aplicación
  3. Además, si una aplicación utiliza varios cargadores de clases, las clases cargadas por un cargador de clases pueden no estar disponibles para otros cargadores de clases. Para solucionarlo bien, es fundamental saber cómo funcionan los cargadores de clases en Java

5. Resumen

Si bien ambas excepciones están relacionadas con la ruta de clase y el tiempo de ejecución de Java que no puede encontrar una clase en el tiempo de ejecución, es importante tener en cuenta sus diferencias.

El tiempo de ejecución de Java lanza ClassNotFoundException al intentar cargar una clase solo en tiempo de ejecución y el nombre se proporcionó durante el tiempo de ejecución. En el caso de NoClassDefFoundError, la clase estaba presente en el momento de la compilación, pero el tiempo de ejecución de Java no pudo encontrarla en la ruta de clases de Java durante el tiempo de ejecución.

Como siempre, el código completo para todos los ejemplos se puede encontrar en GitHub.