Vielleicht hilft das jemandem, weil es für mich ziemlich gut funktioniert. Das Problem kann gelöst werden, indem Sie Ihre eigenen Abhängigkeiten integrieren. Befolgen Sie diese einfachen Schritte
Überprüfen Sie zuerst den Fehler, der so aussehen sollte:
- Methodenausführung fehlgeschlagen:
- java.lang.LinkageError:Loader-Einschränkungsverletzung:
- beim Auflösen der Methode "org.slf4j.impl.StaticLoggerBinder .getLoggerFactory()Lorg/slf4j/ILoggerFactory;"
- der Klassenlader (Instanz von org/openmrs/module/ModuleClassLoader) der aktuellen Klasse, org/slf4j/LoggerFactory ,
- und der Klassenlader (Instanz von org/apache/catalina/loader/WebappClassLoader) für die aufgelöste Klasse org/slf4j/impl/StaticLoggerBinder ,
- haben verschiedene Klassenobjekte für den Typ taticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory; in der Signatur verwendet
-
Siehe die beiden hervorgehobenen Klassen. Google-Suche nach ihnen wie "StaticLoggerBinder.class jar download" &"LoggeraFactory.class jar download". Dies zeigt Ihnen den ersten oder in einigen Fällen den zweiten Link (Site ist http://www.java2s.com ), der eine der JAR-Versionen ist, die Sie in Ihr Projekt aufgenommen haben. Sie können es selbst intelligent identifizieren, aber wir sind süchtig nach Google;)
-
Danach kennen Sie den Namen der JAR-Datei, in meinem Fall lautet er wie folgt:slf4j-log4j12-1.5.6.jar &slf4j-api-1.5.8
- Jetzt ist die neuste Version dieser Datei hier verfügbar http://mvnrepository.com/ (eigentlich alle Versionen bis heute, das ist die Seite, von der Maven Ihre Abhängigkeiten erhält).
- Fügen Sie nun beide Dateien als Abhängigkeiten mit der neuesten Version hinzu (oder lassen Sie beide Dateiversionen gleich, eine der ausgewählten Versionen ist alt). Das Folgende ist die Abhängigkeit, die Sie in pom.xml aufnehmen müssen
<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>
Können Sie einen Klassenlader angeben? Wenn nicht, versuchen Sie, den Kontextklassenlader wie folgt anzugeben:
Thread thread = Thread.currentThread();
ClassLoader contextClassLoader = thread.getContextClassLoader();
try {
thread.setContextClassLoader(yourClassLoader);
callDom4j();
} finally {
thread.setContextClassLoader(contextClassLoader);
}
Ich bin mit dem Java Plugin Framework nicht vertraut, aber ich schreibe Code für Eclipse und stoße von Zeit zu Zeit auf ähnliche Probleme. Ich garantiere nicht, dass es das Problem beheben wird, aber es ist wahrscheinlich einen Versuch wert.
Klingt nach einem Classloader-Hierarchieproblem. Ich kann nicht sagen, in welcher Art von Umgebung Ihre Anwendung bereitgestellt wird, aber manchmal kann dieses Problem in einer Webumgebung auftreten, in der der Anwendungsserver eine Hierarchie von Classloadern erstellt, die etwa so aussieht:
javahome/lib - als root
appserver/lib - als untergeordnetes Element von root
webapp/WEB-INF/lib - als untergeordnetes Element von untergeordnetem Element von root
usw.
Normalerweise delegieren Classloader das Laden an ihren übergeordneten Classloader (dies ist bekannt als „parent-first
"), und wenn dieser Klassenlader die Klasse nicht finden kann, versucht es der untergeordnete Klassenlader. Wenn beispielsweise eine als JAR in webapp/WEB-INF/lib bereitgestellte Klasse versucht, eine Klasse zu laden, fragt sie zuerst den entsprechenden Klassenlader appserver/lib, um die Klasse zu laden (was wiederum den classloader entsprechend javahome/lib auffordert, die Klasse zu laden), und wenn diese Suche fehlschlägt, wird WEB-INF/lib nach einer Übereinstimmung mit dieser Klasse durchsucht.
In einer Webumgebung können Sie mit dieser Hierarchie auf Probleme stoßen. Ein Fehler/Problem, auf das ich zuvor gestoßen bin, war beispielsweise, als eine Klasse in WEB-INF/lib von einer Klasse abhing, die in appserver/lib bereitgestellt wurde, die wiederum von einer Klasse abhing, die in WEB-INF/lib bereitgestellt wurde. Dies führte zu Fehlern, da Classloader zwar an den übergeordneten Classloader delegieren können, aber nicht zurück in den Baum. Der WEB-INF/lib-Klassenlader würde also appserver/lib-Klassenlader nach einer Klasse fragen, appserver/lib-Klassenlader würde diese Klasse laden und versuchen, die abhängige Klasse zu laden, und scheitern, da er diese Klasse in appserver/lib oder javahome nicht finden konnte /lib.
Auch wenn Sie Ihre App möglicherweise nicht in einer Web-/App-Serverumgebung bereitstellen, trifft meine zu lange Erklärung möglicherweise auf Sie zu, wenn in Ihrer Umgebung eine Hierarchie von Classloadern eingerichtet ist. Macht es? Führt JPF eine Art Classloader-Magie durch, um seine Plugin-Funktionen implementieren zu können?
LinkageError ist das, was Sie in einem klassischen Fall erhalten, in dem Sie eine Klasse C von mehr als einem Classloader geladen haben und diese Klassen zusammen im selben Code verwendet werden (Vergleich, Umwandlung usw.). Es spielt keine Rolle, ob es sich um den gleichen Klassennamen handelt oder sogar, ob sie aus dem identischen JAR geladen wurde - eine Klasse von einem Classloader wird immer als eine andere Klasse behandelt, wenn sie von einem anderen Classloader geladen wird.
Die Nachricht (die sich im Laufe der Jahre stark verbessert hat) lautet:
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
Hier besteht das Problem also darin, die Methode SVGOMDocument.createAttribute() aufzulösen, die org.w3c.dom.Attr (Teil der Standard-DOM-Bibliothek) verwendet. Die mit Batik geladene Version von Attr wurde jedoch von einem anderen Classloader geladen als die Instanz von Attr, die Sie an die Methode übergeben.
Sie werden sehen, dass Batiks Version anscheinend vom Java-Plug-in geladen wird. Und Ihres wird von " " geladen, was höchstwahrscheinlich einer der integrierten JVM-Loader ist (Boot-Klassenpfad, ESOM oder Klassenpfad).
Die drei bekanntesten Classloader-Modelle sind:
- Delegation (der Standard im JDK - Eltern fragen, dann mich)
- Post-Delegation (häufig in Plugins, Servlets und Orten, an denen Sie Isolation wünschen - fragen Sie mich, dann Eltern)
- Geschwister (häufig in Abhängigkeitsmodellen wie OSGi, Eclipse usw.)
Ich weiß nicht, welche Delegierungsstrategie der JPF-Classloader verwendet, aber der Schlüssel ist, dass Sie möchten, dass eine Version der Dom-Bibliothek geladen wird und jeder diese Klasse vom selben Ort bezieht. Das kann bedeuten, es aus dem Klassenpfad zu entfernen und als Plugin zu laden, oder Batik daran zu hindern, es zu laden, oder etwas anderes.