GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo lidiar con LinkageErrors en Java?

Puede ser que esto ayude a alguien porque funciona bastante bien para mí. El problema se puede resolver integrando sus propias dependencias. Sigue estos sencillos pasos

Primero verifique el error que debería ser así:

  • Error en la ejecución del método:
  • java.lang.LinkageError:violación de la restricción del cargador:
  • al resolver el método "org.slf4j.impl.StaticLoggerBinder .getLoggerFactory()Lorg/slf4j/ILoggerFactory;"
  • el cargador de clases (instancia de org/openmrs/module/ModuleClassLoader) de la clase actual, org/slf4j/LoggerFactory ,
  • y el cargador de clases (instancia de org/apache/catalina/loader/WebappClassLoader) para la clase resuelta, org/slf4j/impl/StaticLoggerBinder ,
  • tiene diferentes objetos Class para el tipo taticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory; usado en la firma
  1. Vea las dos clases resaltadas. Búsquelos en Google como "StaticLoggerBinder.class jar download" y "LoggeraFactory.class jar download". Esto le mostrará el primer enlace o, en algunos casos, el segundo enlace (el sitio es http://www.java2s.com), que es una de las versiones de jar que ha incluido en su proyecto. Puede identificarlo inteligentemente usted mismo, pero somos adictos a Google;)

  2. Después de eso sabrá el nombre del archivo jar, en mi caso es como slf4j-log4j12-1.5.6.jar &slf4j-api-1.5.8

  3. Ahora, la última versión de este archivo está disponible aquí http://mvnrepository.com/ (en realidad, todas las versiones hasta la fecha, este es el sitio desde donde Maven obtiene sus dependencias).
  4. Ahora agregue ambos archivos como dependencias con la última versión (o mantenga la misma versión de ambos archivos, cualquiera de las versiones elegidas es antigua). La siguiente es la dependencia que debe incluir en pom.xml
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.7</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.7</version>
</dependency>


¿Puedes especificar un cargador de clases? De lo contrario, intente especificar el cargador de clases de contexto de la siguiente manera:

Thread thread = Thread.currentThread();
ClassLoader contextClassLoader = thread.getContextClassLoader();
try {
    thread.setContextClassLoader(yourClassLoader);
    callDom4j();
} finally {
    thread.setContextClassLoader(contextClassLoader);
}

No estoy familiarizado con Java Plugin Framework, pero escribo código para Eclipse y me encuentro con problemas similares de vez en cuando. No garantizo que lo solucionará, pero probablemente valga la pena intentarlo.


Suena como un problema de jerarquía del cargador de clases. No puedo decir en qué tipo de entorno se implementa su aplicación, pero a veces este problema puede ocurrir en un entorno web, donde el servidor de aplicaciones crea una jerarquía de cargadores de clases, similar a algo como:

javahome/lib - como root
appserver/lib - como hijo de root
webapp/WEB-INF/lib - como hijo de hijo de raíz
etc.

Por lo general, los cargadores de clases delegan la carga a su cargador de clases principal (esto se conoce como "parent-first "), y si ese cargador de clases no puede encontrar la clase, entonces el cargador de clases secundario intenta hacerlo. Por ejemplo, si una clase implementada como un JAR en webapp/WEB-INF/lib intenta cargar una clase, primero le pregunta al cargador de clases correspondiente a appserver/lib para cargar la clase (que a su vez le pide al cargador de clases correspondiente a javahome/lib que cargue la clase), y si esta búsqueda falla, se busca en WEB-INF/lib una coincidencia con esta clase.

En un entorno web, puede tener problemas con esta jerarquía. Por ejemplo, un error/problema con el que me encontré antes fue cuando una clase en WEB-INF/lib dependía de una clase implementada en appserver/lib, que a su vez dependía de una clase implementada en WEB-INF/lib. Esto provocó fallas porque, si bien los cargadores de clases pueden delegar en el cargador de clases principal, no pueden delegar hacia abajo en el árbol. Entonces, el cargador de clases WEB-INF/lib le pediría una clase al cargador de clases appserver/lib, el cargador de clases appserver/lib cargaría esa clase e intentaría cargar la clase dependiente, y fallaría porque no pudo encontrar esa clase en appserver/lib o javahome /lib.

Por lo tanto, si bien es posible que no esté implementando su aplicación en un entorno de servidor web/aplicación, mi explicación demasiado larga podría aplicarse a usted si su entorno tiene configurada una jerarquía de cargadores de clases. ¿Lo hace? ¿JPF está haciendo algún tipo de magia de cargador de clases para poder implementar sus funciones de complemento?


LinkageError es lo que obtendrá en un caso clásico en el que tiene una clase C cargada por más de un cargador de clases y esas clases se usan juntas en el mismo código (comparado, emitido, etc.). No importa si es el mismo nombre de clase o incluso si se carga desde el mismo jar:una clase de un cargador de clases siempre se trata como una clase diferente si se carga desde otro cargador de clases.

El mensaje (que ha mejorado mucho con los años) dice:

Exception in thread "AWT-EventQueue-0" java.lang.LinkageError: 
loader constraint violation in interface itable initialization: 
when resolving method "org.apache.batik.dom.svg.SVGOMDocument.createAttribute(Ljava/lang/String;)Lorg/w3c/dom/Attr;" 
the class loader (instance of org/java/plugin/standard/StandardPluginClassLoader) 
of the current class, org/apache/batik/dom/svg/SVGOMDocument, 
and the class loader (instance of ) for interface org/w3c/dom/Document 
have different Class objects for the type org/w3c/dom/Attr used in the signature

Entonces, aquí el problema está en resolver el método SVGOMDocument.createAttribute(), que usa org.w3c.dom.Attr (parte de la biblioteca DOM estándar). Sin embargo, la versión de Attr cargada con Batik se cargó desde un cargador de clases diferente al de la instancia de Attr que está pasando al método.

Verás que la versión de Batik parece estar cargada desde el complemento de Java. Y el suyo se está cargando desde " ", que probablemente sea uno de los cargadores JVM integrados (ruta de clase de arranque, ESOM o ruta de clase).

Los tres modelos destacados de cargadores de clases son:

  • delegación (el valor predeterminado en el JDK:pregúntele a los padres, luego a mí)
  • después de la delegación (común en complementos, servlets y lugares donde desea aislamiento; pregúnteme a mí y luego a los padres)
  • hermano (común en modelos de dependencia como OSGi, Eclipse, etc.)

No sé qué estrategia de delegación usa el cargador de clases JPF, pero la clave es que desea que se cargue una versión de la biblioteca dom y que todos obtengan esa clase desde la misma ubicación. Eso puede significar eliminarlo del classpath y cargarlo como un complemento, o evitar que Batik lo cargue, o algo más.


Linux
  1. Linux:¿cómo hacer que Oracle Java 7 funcione con Setcap Cap_net_bind_service+ep?

  2. ¿Cómo lidiar con el malware en la computadora portátil?

  3. Cómo instalar/cambiar entre varias versiones de Java con SDKMAN

  4. ¿Cómo ejecutar el comando bash con privilegios sudo en Java?

  5. ¿Cómo rellenar un archivo con FF usando dd?

Cómo instalar Java con Apt en Ubuntu 20.04

Cómo instalar Java en Ubuntu 18.04

Cómo:Programación orientada a objetos:más con clases y objetos

Cómo instalar Java en CentOS 8

¿Cómo instalar Java en Ubuntu 18.04?

Cómo crear un comercio electrónico con Magento