Esta excepción esta muy relacionada con el artículo anterior java.lang.NoClassDefFoundError, Caused by: java.lang.ClassNotFoundException.
A menudo nos encontraremos ambas excepciones, pero en ocasiones solo nos encontraremos con java.lang.ClassNotFoundException.
El motivo de esta excepción es prácticamente el mismo. En la documentación nos dice que esta excepción se produce cuando el ClassLoader intenta leer la descripción de una clase, y la definición de dicha clase no es encontrada.
Estamos ante el mismo motivo visto en el artículo anterior. La definición de la clase no se encuentra debido a que la librería que lo contiene no esta en el classpath de la aplicación, o bien, si estamos ante un servidor de aplicaciones, la librería no está o el classloader que intenta cargarla no tiene visible esa librería. En cualquier caso tenemos que repasar la configuración de nuestras aplicaciones para solucionar este tipo de errores.
En los servidores de aplicaciones es más común encontrarnos con estas excepciones, ya que existen varios ClassLoader diferentes para una aplicación, y distinta políticas de carga de clases. Tenemos un ClassLoader para el servidor, uno para librerías comunes a todas las aplicaciones, y un ClassLoader para cada aplicación. La jerarquía normalmente es esta aunque depende del servidor de aplicaciones. Así por ejemplo si se delega la carga de clases al classloader del servidor, y la librería con definición de la clase se encuentra en la aplicación (es decir en el WEB-INF/lib) al final obtendremos esta excepción o la que comentábamos en el artículo anterior.
Vamos a reproducir esta excepción y así veremos como es el código que provoca estos errores.
Creación de la estructura del proyecto
mkdir a mkdir b mkdir main
Creación de la clase A.java
La creamos en el directorio o paquete a.
package a; public class A { public void echo() { System.out.println("Hello from A !"); } }
Creación de la clase B.java
La creamos en el directorio o paquete b.
package b; public class B { public void echo() { System.out.println("Hello from B !"); } }
Creación de la clase MainClass.java
Esta clase hace uso de las dos anteriores, y la creamos en el directorio o paquete main.
package main; import b.*; import a.*; public class MainClass { public static final void main(String argv[]) { A a = new A(); a.echo(); try { Class bclass = Class.forName("b.B"); B b = (B) bclass.newInstance(); b.echo(); } catch(Throwable ex) { ex.printStackTrace(); } } }
Compilamos los fuentes
Nos situamos en el directorio raiz y compilamos
$ javac a*.java b*.java main*.java
Ejecutamos la clase principal
$ java -cp . main.MainClass Hello from A ! Hello from B !
Provocamos la excepción java.lang.ClassNotFoundException
La forma mas sencilla es renombrar el directorio b por otro nombre, y así la clase B ya no es encontrara por la Jvm, ya que deja de existir el package b.
Ejecutamos de nuevo la aplicación y obtendremos la excepción esperada.
$ java -cp . main.MainClass Hello from A ! java.lang.ClassNotFoundException: b.B at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown S at java.lang.ClassLoader.loadClass(Unknown Source) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Unknown Source) at main.MainClass.main(MainClass.java:10)
En esta ocasión el error no se produce en la creación de la clase (new B()), si no cuando intentamos leer su definición
Class bclass = Class.forName("b.B");