Esto no responde a la pregunta original, pero como la pregunta está altamente clasificada y vinculada a cualquier ContextClassLoader
consulta, creo que es importante responder la pregunta relacionada de cuándo se debe usar el cargador de clases de contexto. Respuesta corta: ¡ nunca use el cargador de clases de contexto ! Pero configúralo engetClass().getClassLoader()
cuando tenga que llamar a un método al que le falta unClassLoader
parámetro.
Cuando el código de una clase pide cargar otra clase, el cargador de clases correcto para usar es el mismo cargador de clases que la clase que llama (es decir, getClass().getClassLoader()
). Así es como funcionan las cosas el 99.9% del tiempo porque esto es lo que hace la JVM la primera vez que construye una instancia de una nueva clase, invoca un método estático o accede a un campo estático.
Cuando desee crear una clase utilizando la reflexión (como al deserializar o cargar una clase con nombre configurable), la biblioteca que hace la reflexión siempre debe preguntarle a la aplicación qué cargador de clase usar, al recibir el ClassLoader
parámetro como parte de la aplicación. La aplicación (que conoce todas las clases que necesitan construirse) debería pasarlagetClass().getClassLoader()
.
Cualquier otra forma de obtener un cargador de clases es incorrecta. Si una biblioteca usa hacks como Thread.getContextClassLoader()
, sun.misc.VM.latestUserDefinedLoader()
o sun.reflect.Reflection.getCallerClass()
es un error causado por una deficiencia en la API. Básicamente, Thread.getContextClassLoader()
existe solo porque quien diseñó la ObjectInputStream
API olvidó aceptar elClassLoader
como parámetro, y este error ha perseguido a la comunidad Java hasta el día de hoy.
Dicho esto, muchas clases de JDK usan uno de los pocos hacks para adivinar algún cargador de clases para usar. Algunos usan el ContextClassLoader
(que falla cuando ejecuta diferentes aplicaciones en un grupo de subprocesos compartido, o cuando abandona el ContextClassLoader null
), algunos recorren la pila (que falla cuando el llamante directo de la clase es una biblioteca), algunos usan el cargador de clases del sistema (lo cual está bien, siempre que esté documentado para usar solo clases en elCLASSPATH
) o cargador de clases bootstrap, y algunos usan una combinación impredecible de las técnicas anteriores (lo que solo hace las cosas más confusas). Esto ha resultado en mucho llanto y crujir de dientes.
Cuando utilice una API de este tipo, primero, trate de encontrar una sobrecarga del método que acepte el cargador de clases como parámetro . Si no hay un método razonable, intente configurar ContextClassLoader
antes de la llamada API (y restablecerlo después):
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
// call some API that uses reflection without taking ClassLoader param
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
ClassB
debe estar en el classpath delClassA
cargador de (oClassA
los padres del cargador)? ¿No es posible queClassA
el cargador se anuleloadClass()
, de modo que se pueda cargar con éxitoClassB
incluso cuandoClassB
no está en su classpath?