GNU/Linux >> Linux Esercitazione >  >> Linux

Come gestire LinkageErrors in Java?

Può essere che questo aiuterà qualcuno perché funziona abbastanza bene per me. Il problema può essere risolto integrando le proprie dipendenze. Segui questi semplici passaggi

Per prima cosa controlla l'errore che dovrebbe essere così :

  • Esecuzione del metodo non riuscita:
  • java.lang.LinkageError:violazione del vincolo del caricatore:
  • durante la risoluzione del metodo "org.slf4j.impl.StaticLoggerBinder .getLoggerFactory()Lorg/slf4j/ILoggerFactory;"
  • il caricatore di classe (istanza di org/openmrs/module/ModuleClassLoader) della classe corrente, org/slf4j/LoggerFactory ,
  • e il caricatore di classe (istanza di org/apache/catalina/loader/WebappClassLoader) per la classe risolta, org/slf4j/impl/StaticLoggerBinder ,
  • avere diversi oggetti Class per il tipo taticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory; utilizzato nella firma
  1. Vedi le due classi evidenziate. Cercali su Google come "StaticLoggerBinder.class jar download" e "LoggeraFactory.class jar download". Questo ti mostrerà il primo o in alcuni casi il secondo link (il sito è http://www.java2s.com ) che è una delle versioni jar che hai incluso nel tuo progetto. Puoi identificarlo in modo intelligente da solo, ma siamo dipendenti da Google;)

  2. Dopodiché conoscerai il nome del file jar, nel mio caso è come slf4j-log4j12-1.5.6.jar &slf4j-api-1.5.8

  3. Ora l'ultima versione di questo file è disponibile qui http://mvnrepository.com/ (in realtà tutte le versioni fino ad oggi, questo è il sito da cui Maven ottiene le tue dipendenze).
  4. Ora aggiungi entrambi i file come dipendenze con l'ultima versione (o mantieni la stessa versione di entrambi i file, entrambe le versioni scelte sono vecchie). Quella che segue è la dipendenza che devi includere in 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>


Puoi specificare un caricatore di classi? In caso contrario, prova a specificare il caricatore di classi di contesto in questo modo:

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

Non ho familiarità con Java Plugin Framework, ma scrivo codice per Eclipse e di tanto in tanto mi imbatto in problemi simili. Non garantisco che risolverà il problema, ma probabilmente vale la pena tentare.


Sembra un problema di gerarchia del caricatore di classi. Non posso dire in quale tipo di ambiente è distribuita la tua applicazione, ma a volte questo problema può verificarsi in un ambiente web, dove il server delle applicazioni crea una gerarchia di classloader, simile a qualcosa del tipo:

javahome/lib - come root
appserver/lib - come figlio di root
webapp/WEB-INF/lib - come figlio di figlio di root
ecc

Di solito i classloader delegano il caricamento al loro classloader genitore (questo è noto come "parent-first "), e se quel classloader non riesce a trovare la classe, allora il classloader figlio tenta di farlo. Ad esempio, se una classe distribuita come JAR in webapp/WEB-INF/lib prova a caricare una classe, prima chiede al classloader corrispondente a appserver/lib per caricare la classe (che a sua volta chiede al classloader corrispondente a javahome/lib di caricare la classe), e se questa ricerca fallisce, WEB-INF/lib viene cercato per una corrispondenza con questa classe.

In un ambiente web, puoi incorrere in problemi con questa gerarchia. Ad esempio, un errore/problema in cui mi sono imbattuto in precedenza è stato quando una classe in WEB-INF/lib dipendeva da una classe distribuita in appserver/lib, che a sua volta dipendeva da una classe distribuita in WEB-INF/lib. Ciò ha causato errori perché mentre i programmi di caricamento classi sono in grado di delegare al programma di caricamento classi padre, non possono delegare a ritroso l'albero. Quindi, il classloader WEB-INF/lib chiederebbe a appserver/lib classloader una classe, appserver/lib classloader caricherebbe quella classe e proverebbe a caricare la classe dipendente, e fallirebbe poiché non potrebbe trovare quella classe in appserver/lib o javahome /lib.

Quindi, anche se potresti non distribuire la tua app in un ambiente server web/app, la mia spiegazione troppo lunga potrebbe applicarsi a te se il tuo ambiente ha una gerarchia di classloader configurata. Lo fa? JPF sta facendo una sorta di magia del classloader per essere in grado di implementare le sue funzionalità di plugin?


LinkageError è ciò che otterrai in un caso classico in cui hai una classe C caricata da più di un classloader e quelle classi vengono utilizzate insieme nello stesso codice (confronto, cast, ecc.). Non importa se è lo stesso nome di classe o anche se è stato caricato dallo stesso jar:una classe di un classloader viene sempre trattata come una classe diversa se caricata da un altro classloader.

Il messaggio (che è migliorato molto nel corso degli anni) 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

Quindi, qui il problema è risolvere il metodo SVGOMDocument.createAttribute(), che utilizza org.w3c.dom.Attr (parte della libreria DOM standard). Tuttavia, la versione di Attr caricata con Batik è stata caricata da un programma di caricamento classi diverso rispetto all'istanza di Attr che stai passando al metodo.

Vedrai che la versione di Batik sembra essere caricata dal plugin Java. E il tuo viene caricato da " ", che molto probabilmente è uno dei caricatori JVM integrati (boot classpath, ESOM o classpath).

I tre principali modelli di classloader sono:

  • delega (l'impostazione predefinita nel JDK - chiedi al genitore, poi a me)
  • post-delega (comune in plug-in, servlet e luoghi in cui desideri l'isolamento:chiedimi, quindi genitore)
  • fratello (comune nei modelli di dipendenza come OSGi, Eclipse, ecc.)

Non so quale strategia di delega utilizzi il classloader JPF, ma la chiave è che vuoi che venga caricata una versione della libreria dom e che tutti possano procurarsi quella classe dalla stessa posizione. Ciò potrebbe significare rimuoverlo dal classpath e caricarlo come plugin, o impedire a Batik di caricarlo, o qualcos'altro.


Linux
  1. Come installare Java su Linux

  2. Linux:come far funzionare Oracle Java 7 con Setcap Cap_net_bind_service+ep?

  3. Come gestire il malware sul laptop?

  4. Come installare/passare tra più versioni Java con SDKMAN

  5. In che modo Linux gestisce gli script di shell?

Come installare Java con Apt su Ubuntu 20.04

Come installare Java su Ubuntu 18.04

Procedura:Programmazione orientata agli oggetti – Altro con classi e oggetti

Come installare Java su CentOS 8

Come installare Java su Ubuntu 18.04?

Come creare un e-commerce con Magento