hacer - importar librerias en java netbeans
Cargar un jar en el tiempo de ejecución causa un NoClassDefFoundError/ClassNotFoundException (1)
De manera embarazosa, encontré que la respuesta fue que el mensaje de error decía la verdad. javax.persistence.AttributeConverter
, la clase que el cargador reclamaba no estaba presente, no estaba en el contenedor.
Solucioné el problema cargando solo la clase principal y el ClassLoader
todas las clases de referencias, básicamente cargando todas las clases en el jar que se usan en el programa, que es todo lo que necesito.
Ahora, podría haber jurado que revisé esto antes y encontré esa clase; Me imagino que debo haber revisado el repositorio de código abierto de Apache para la clase en lugar del servidor real cuando lo comprobé. No puedo recordar
En cualquier caso, AttributeConverter
encuentra. No sé cómo ni por qué lograron compilar un contenedor con dependencias perdidas, pero supongo que sus procesos principales nunca usan esa parte del código, por lo que nunca lanzaron errores.
Lamento haber desperdiciado el tiempo de todos ... incluido el mío. He estado atascado en este problema desde hace un tiempo.
Moraleja de esta historia:
Si intenta cargar un archivo ejecutable, no se moleste en cargar todas las clases en un contenedor a menos que realmente tenga que hacerlo. Solo carga la clase principal; eso cargará todo lo que el programa necesita para ejecutarse.
//EDITAR:
Ahora comencé a tener el mismo error, pero no aparece hasta que intento llamar a un método de una clase cargada. La pregunta aparentemente sigue abierta. Por favor vote abajo y desestime esta respuesta.
Resumen: la carga de un jar desde un programa Java en ejecución causa un NoClassDefFoundError
causado por una NoClassDefFoundError
ClassNotFoundException
causada por dependencias entre clases (por ejemplo, sentencias de import
). ¿Cómo puedo evitarlo?
El problema en más detalle:
Estoy intentando cargar programáticamente un archivo jar -llamémoslo "Servidor" - en la Máquina Virtual Java a través de mi propio programa Java, llamémoslo "ServidorAPI", y usamos la extensión y algunos otros trucos para modificar el comportamiento. e interactuar con el servidor. ServerAPI depende del servidor, pero si el servidor no está presente, ServerAPI todavía tiene que poder ejecutar y descargar el servidor desde un sitio web.
Para evitar los errores causados por la carga de ServerAPI sin satisfacer sus dependencias del Servidor, he creado un iniciador, llamémoslo "Iniciador", que está destinado a descargar el Servidor y configurar ServerAPI según sea necesario, luego cargar el Servidor y ServidorAPI, luego ejecutar ServerAPI.
Sin embargo, cuando intento cargar frascos desde el Iniciador, recibo errores porque los ClassLoaders no pueden resolver las otras clases del archivo de las que depende la clase desde la que se carga. En resumen, si intento cargar la Clase A
, lanzará un error si A
importa B
porque aún no he cargado B
Sin embargo, si B
también importa A
, estoy atascado porque no puedo entender cómo cargar dos clases a la vez o cómo cargar una clase sin que la JVM ejecute su validación.
Por qué todas las restricciones me han llevado a este problema:
Estoy intentando modificar y agregar el comportamiento del servidor, pero por complicadas razones legales, no puedo modificar el programa directamente, así que he creado ServerAPI que depende y puede modificar el comportamiento del servidor desde el exterior.
Sin embargo, por razones legales más complicadas, Server y ServerAPI no pueden simplemente descargarse juntos. Launcher (ver arriba) tiene que ser descargado con ServerAPI, entonces Launcher necesita descargar el Servidor. Finalmente, ServerAPI se puede ejecutar usando Server como una dependencia. Es por eso que este problema es tan complejo.
Este problema también se aplicará a una parte posterior del proyecto, que incluirá una interfaz de API basada en un complemento que debe poder cargar y descargar complementos desde archivos jar mientras se ejecuta.
Investigación que ya hice sobre este problema:
He leído y no me ayudó:
- esta pregunta , que solo aborda el problema de un único método y no aborda los errores de dependencia entre clases;
- esta pregunta , que no funcionará porque no puedo apagar y reiniciar el programa cada vez que se carga o descarga un contenedor (principalmente para la parte del complemento que mencioné brevemente);
- esta pregunta , que solo funciona para situaciones donde las dependencias están presentes cuando se inicia el programa;
- esta pregunta , que tiene el mismo problema que el # 2;
- esta pregunta , que tiene el mismo problema que el # 3;
- este artículo , del cual aprendí sobre el método oculto de loadClass (String, boolean), pero probar con valores verdaderos y falsos no ayudó;
- esta pregunta , que tiene el mismo problema que el # 1;
y más. Nada ha funcionado.
// EDIT: intentos que he hecho hasta ahora:
He intentado usar URLClassLoaders para cargar el jar usando JarEntries
desde JarFile
similar a esta pregunta . Intenté esto utilizando y llamando a un URLClassLoader
loadClass(String)
URLClassLoader
y creando una clase que amplía URLClassLoader
para que pueda utilizar loadClass(String, boolean resolve)
para intentar obligar al ClassLoader
a resolver todas las clases que carga . En ambos sentidos, tengo el mismo error:
I couldn''t find the class in the JarEntry!
entry name="org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverter.class"
class name="org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter"
java.lang.NoClassDefFoundError: javax/persistence/AttributeConverter
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:455)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:367)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at Corundum.launcher.CorundumClassLoader.load(CorundumClassLoader.java:52)
at Corundum.launcher.CorundumLauncher.main(CorundumLauncher.java:47)
Caused by: java.lang.ClassNotFoundException: javax.persistence.AttributeConverter
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 12 more
// END EDIT
// EDIT 2:
Aquí hay una muestra del código que utilicé para cargar una clase al intentar resolverlo. Esto fue dentro de una clase que hice que extiende URLClassLoader
. En la línea que comienza con Class<?> clazz = loadClass(
, he intentado usar true y false como argumento booleano, ambos intentos dieron como resultado el mismo error anterior.
public boolean load(ClassLoadAction class_action, FinishLoadAction end_action) {
// establish the jar associated with this ClassLoader as a JarFile
JarFile jar;
try {
jar = new JarFile(jar_path);
} catch (IOException exception) {
System.out.println("There was a problem loading the " + jar_path + "!");
exception.printStackTrace();
return false;
}
// load each class in the JarFile through its JarEntries
Enumeration<JarEntry> entries = jar.entries();
if (entries.hasMoreElements())
for (JarEntry entry = entries.nextElement(); entries.hasMoreElements(); entry = entries.nextElement())
if (!entry.isDirectory() && entry.getName().endsWith(".class"))
try {
/* this "true" in the line below is the whole reason this class is necessary; it makes the URLClassLoader this class extends "resolve" the class,
* meaning it also loads all the classes this class refers to */
Class<?> clazz = loadClass(entry.getName().substring(0, entry.getName().length() - 6).replaceAll("/", "."), true);
class_action.onClassLoad(this, jar, clazz, end_action);
} catch (ClassNotFoundException | NoClassDefFoundError exception) {
try {
close();
} catch (IOException exception2) {
System.out.println("There was a problem closing the URLClassLoader after the following " + exception2.getClass().getSimpleName() + "!");
exception.printStackTrace();
}
try {
jar.close();
} catch (IOException exception2) {
System.out.println("There was a problem closing the JarFile after the following ClassNotFoundException!");
exception.printStackTrace();
}
System.out.println("I couldn''t find the class in the JarEntry!/nentry name=/"" + entry.getName() + "/"/nclass name=/""
+ entry.getName().substring(0, entry.getName().length() - 6).replaceAll("/", ".") + "/"");
exception.printStackTrace();
return false;
}
// once all the classes are loaded, close the ClassLoader and run the plugin''s main class(es) load() method(s)
try {
jar.close();
} catch (IOException exception) {
System.out.println("I couldn''t close the URLClassLoader used to load this jar file!/njar file=/"" + jar.getName() + "/"");
exception.printStackTrace();
return false;
}
end_action.onFinishLoad(this, null, class_action);
System.out.println("loaded " + jar_path);
// TODO TEST
try {
close();
} catch (IOException exception) {
System.out.println("I couldn''t close the URLClassLoader used to load this jar file!/njar file=/"" + jar_path + "/"");
exception.printStackTrace();
return false;
}
return true;
}
// END EDIT 2
Me doy cuenta de que debe haber una solución simple para esto, pero por mi vida parece que no puedo encontrarlo. Cualquier ayuda me haría eternamente agradecido. Gracias.