Frage

eine stark XML-basierte Java-Anwendung entwickeln, die ich gestoßen kürzlich ein interessantes Problem auf Ubuntu Linux.

Meine Anwendung, die Java Plugin Framework- verwendet, wird nicht in der Lage dom4j -created XML-Dokument href="http://xmlgraphics.apache.org/batik/" zum Batiks Umsetzung der SVG-Spezifikation.

Auf der Konsole, erfahre ich, dass ein Fehler auftritt:

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 <bootloader>) for interface org/w3c/dom/Document have different Class objects for the type org/w3c/dom/Attr used in the signature
    at org.apache.batik.dom.svg.SVGDOMImplementation.createDocument(SVGDOMImplementation.java:149)
    at org.dom4j.io.DOMWriter.createDomDocument(DOMWriter.java:361)
    at org.dom4j.io.DOMWriter.write(DOMWriter.java:138)

Ich vermute, dass das Problem durch einen Konflikt zwischen den Original-Classloader von der JVM und dem Klassenlader durch den Plugin-Framework zum Einsatz verursacht wird.

Mein Wissen ist es nicht möglich, einen Classloader für den Rahmen angeben, zu verwenden. Es könnte möglich sein, es zu hacken, aber ich würde einen weniger aggressiven Ansatz zur Lösung dieses Problems bevorzugen, da (aus irgendeinem Grunde) kommt es nur auf Linux-Systemen.

Hat einer von euch so ein Problem festgestellt und hat keine Ahnung, wie es zu beheben oder zumindest auf den Kern des Problems zu bekommen?

War es hilfreich?

Lösung

LinkageError ist, was Sie in einem klassischen Fall erhalten werden, wo Sie eine Klasse C um mehr als ein Klassenladeprogramm geladen haben und diese Klassen verwendet werden, um zusammen in dem gleichen Code (verglichen, gegossen, etc). Dabei spielt es keine Rolle, ob es der gleiche Klassenname ist oder auch wenn es aus dem gleichen Glas geladen wird - a. Klasse von einem Classloader wird immer als eine andere Klasse behandelt, wenn von einem anderen Classloader geladen

Die Nachricht (die sich im Laufe der Jahre verbessert hat) sagt:

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

So, hier ist das Problem der SVGOMDocument.createAttribute () -Methode bei der Lösung, die org.w3c.dom.Attr (Teil der Standard-DOM-Bibliothek) verwendet. Aber die Version von Attr mit Batik geladen wurde von einem anderen Klassenlader als die Instanz geladen Attr Sie auf das Verfahren vorbei sind.

Sie werden sehen, dass Batik-Version aus der Java-Plugin geladen zu sein scheint. Und Sie werden von „“ geladen, was am wahrscheinlichsten ist eine des integrierten in JVM Lader (Boot-Classpath, ESOM oder Classpath).

Die drei prominenten Classloader-Modelle sind:

  • Delegation (der Standard in der JDK - fragen Eltern, dann me)
  • post-Delegation (common in Plugins, Servlets und Orte, wo man Isolation wollen - fragen Sie mich, dann parent)
  • Geschwister (häufig in Abhängigkeit Modelle wie OSGi, Eclipse etc.)

Ich weiß nicht, welche Delegation Strategie der JPF Classloader verwendet, aber der Schlüssel ist, dass Sie eine Version der dom-Bibliothek wollen diese Klasse von der gleichen Stelle geladen werden und alle zu beziehen. Das kann bedeuten, dass es aus dem Classpath und Laden als Plugin zu entfernen oder zu verhindern Batik aus Laden Sie es, oder etwas anderes.

Andere Tipps

Klingt wie ein Klassenlader Hierarchieproblem. Ich kann nicht sagen, welche Art von Umgebung ist Ihre Anwendung bereitgestellt wird, aber manchmal kann dieses Problem in einer Web-Umgebung auftreten - der der Anwendungsserver eine Hierarchie der Klassenladeprogramme erstellt, ähnelt etwas wie:

javahome / lib - als root
appserver / lib - als Kind der Wurzel
webapp / WEB-INF / lib - als Kind Kind Wurzel
etc

Normalerweise Classloader Belastung an ihre Mutterclassloader übertragen (dies wird als „parent-first“ bekannt ist), und wenn das nicht die Klasse Classloader finden können, dann das Kind versucht, Classloader. Wenn beispielsweise eine Klasse als JAR in webapp / WEB-INF / lib Versuchen eingesetzt, eine Klasse zu laden, erste, fragt er den Klassenlader zu appserver / lib entspricht, um die Klasse zu laden (die wiederum fragt den Klassenlader / lib zu Javahome entsprechenden lädt die Klasse), und wenn diese Suche fehlschlägt, dann WEB-INF / lib ist für ein Spiel dieser Klasse gesucht.

In einer Web-Umgebung, können Sie Probleme mit dieser Hierarchie laufen. Zum Beispiel war ein Fehler / Problem, das ich in vor ausgeführt habe, wenn eine Klasse in WEB-INF / lib auf einer Klasse hing in appserver / lib eingesetzt, die wiederum auf einer Klasse hingen in WEB-INF / lib im Einsatz. Dies verursachte Ausfälle, weil während Classloader der Lage sind, auf das übergeordnete Klassenlader zu delegieren, können sie nicht zurück in den Baum übertragen. So ist der WEB-INF / lib Classloader würde fragen appserver / lib Classloader für eine Klasse, appserver / lib Classloader die Klasse laden und versuchen würde, die abhängige Klasse zu laden, und scheitern, da es nicht die Klasse in appserver / lib oder javahome finden konnte, / lib.

Also, wenn Sie nicht Ihre Anwendung in einem Web / app-Server-Umgebung bereitstellen können, meine allzu lange Erklärung könnte sein, dass Sie sich bewerben, wenn Ihre Umgebung eine Hierarchie von Classloader hat eingerichtet. Macht es? Ist JPF irgendeine Art von Magie zu tun Klassenlader der Lage sein, es ist Plugin-Funktionen zu implementieren?

Kann dies jemand helfen wird, weil es für mich ziemlich gut funktioniert. Das Problem kann durch die Integration Ihrer eigenen Abhängigkeiten lösen sein. Folgen Sie dieser einfachen Schritten

zuerst den Fehler überprüfen, die wie folgt sein sollte:

  • Method Ausführung fehlgeschlagen:
  • java.lang.LinkageError: loader Einschränkungsverletzung:
  • bei der Lösung 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 aufgelöste Klasse, org / slf4j / impl / StaticLoggerBinder ,
  • haben unterschiedliche Klassenobjekte für den Typ taticLoggerBinder.getLoggerFactory () Lorg / slf4j / ILoggerFactory; in der Signatur verwendet

  1. Sehen Sie die beiden markierten Klasse. Google für sie wie "StaticLoggerBinder.class jar herunterladen" search & "LoggeraFactory.class jar herunterladen". Dies zeigt Ihnen erste oder in einigen Fällen zweiten Link (Site ist http://www.java2s.com ) das ist eine der jar-Version Sie in Ihrem Projekt aufgenommen haben. Sie können es klug, sich identifizieren, aber wir sind süchtig von Google;)

  2. Nach dass Sie der JAR-Datei Name, in meinem Fall wissen, es ist wie slf4j-log4j12-1.5.6.jar & slf4j-api-1.5.8

  3. Geben Sie nun die neueste Version dieser Datei ist hier verfügbar http://mvnrepository.com/ (eigentlich alle Version bis heute ist dies der Ort, von wo maven Ihre Abhängigkeiten erhalten).
  4. Geben Sie nun sowohl Datei als Abhängigkeiten mit der neuesten Version hinzufügen (oder beide Dateiversion gleichen halten, entweder gewählte Version ist alt). Im Anschluss wird die Abhängigkeit haben Sie in pom.xml enthalten

<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>

Wie dependecy Definition von Maven-Site bekommen

Können Sie einen Class Loader angeben? Wenn nicht, versuchen Sie das Kontextklassenlader Angabe wie folgt:

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

Ich bin nicht vertraut mit dem Java-Plugin-Framework, aber ich schreibe Code für Eclipse, und ich laufe in ähnliche Probleme von Zeit zu Zeit. Ich garantiere nicht, es wird es beheben, aber es ist wahrscheinlich ein Versuch wert.

Die Antworten von Alex und Matt sind sehr hilfreich. Ich könnte auch aus ihrer Analyse profitieren.

Ich hatte das gleiche Problem, wenn die Batik-Bibliothek in einem Netbeans RCP-Framework, wobei die Batik-Bibliothek als „Bibliothek Wrapper Module“ enthalten. Wenn ein anderes Modul Verwendung von XML-APIs macht, und keine Abhängigkeit von Batik benötigt wird und für dieses Modul etabliert, stellt sich die Klassenladeeinschränkungsverletzung Problem mit ähnlichen Fehlermeldungen.

In Netbeans, einzelne Module verwenden spezielle Klassenlader und die Abhängigkeitsbeziehung zwischen den Modulen beinhaltet geeignete Klassenlade Delegation Routing.

Ich kann das Problem lösen, indem einfach die XML-apis jar-Datei aus dem Batik Bibliothek Bündel weggelassen wird.

Wie in diese Frage , so dass die -verbose:class wird die JVM Log-Informationen über alle Klassen macht geladen, die unglaublich nützlich sein kann, zu verstehen, wo die Klassen kommen in komplexeren Szenarien und Anwendungen.

Der Ausgang Sie sieht wie folgt aus (aus dieser Frage kopiert) in etwa erhalten:

[Opened /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/sunrsasign.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/jsse.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/jce.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/charsets.jar]
[Loaded java.lang.Object from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.io.Serializable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.Comparable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.CharSequence from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.String from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top