817 Stimmen

Umgang mit der "Xerces-Hölle" in Java/Maven?

In meinem Büro reicht die bloße Erwähnung des Wortes Xerces aus, um bei den Entwicklern mörderische Wut hervorzurufen. Ein flüchtiger Blick auf die anderen Xerces-Fragen auf SO scheint darauf hinzuweisen, dass fast alle Maven-Benutzer irgendwann von diesem Problem "berührt" werden. Leider erfordert das Verständnis des Problems ein wenig Wissen über die Geschichte von Xerces...

Geschichte

  • Xerces ist der am häufigsten verwendete XML-Parser im Java-Ökosystem. Fast jede Bibliothek oder jedes Framework, das in Java geschrieben wurde, verwendet Xerces in irgendeiner Form (wenn auch nicht direkt, so doch indirekt).

  • Die Xerces-Gläser, die in der offizielle Binärdateien sind bis heute nicht versioniert. Das Xerces 2.11.0-Implementierungs-Jar heißt zum Beispiel xercesImpl.jar und nicht xercesImpl-2.11.0.jar .

  • Das Xerces-Team verwendet nicht Maven was bedeutet, dass sie nicht eine offizielle Veröffentlichung auf Maven-Zentrale .

  • Xerces war früher als einzelnes Gefäß freigegeben ( xerces.jar ), wurde aber in zwei Jars aufgeteilt, von denen eines die API ( xml-apis.jar ) und eine, die die Implementierungen dieser APIs enthält ( xercesImpl.jar ). Viele ältere Maven POMs deklarieren immer noch eine Abhängigkeit von xerces.jar . Irgendwann in der Vergangenheit wurde Xerces auch veröffentlicht als xmlParserAPIs.jar , auf die auch einige ältere POMs angewiesen sind.

  • Die Versionen, die den xml-apis und xercesImpl Jars von denjenigen zugewiesen werden, die ihre Jars in den Maven Repositories bereitstellen, sind oft unterschiedlich. Zum Beispiel könnte xml-apis die Version 1.3.03 und xercesImpl die Version 2.8.0 erhalten, obwohl beide aus Xerces 2.8.0 stammen. Das liegt daran, dass die Leute das xml-apis jar oft mit der Version der Spezifikationen, die es implementiert, kennzeichnen. Es gibt eine sehr schöne, aber unvollständige Aufschlüsselung dieses Sachverhalts aquí .

  • Erschwerend kommt hinzu, dass Xerces der XML-Parser ist, der in der Referenzimplementierung der Java API for XML Processing (JAXP) verwendet wird, die in der JRE enthalten ist. Die Implementierungsklassen sind unter dem Namen com.sun.* Namespace, was es gefährlich macht, direkt auf sie zuzugreifen, da sie in einigen JREs möglicherweise nicht verfügbar sind. Allerdings sind nicht alle Xerces-Funktionen über die java.* y javax.* APIs; zum Beispiel gibt es keine API, die die Xerces-Serialisierung offenlegt.

  • Zu dem verwirrenden Durcheinander kommt hinzu, dass fast alle Servlet-Container (JBoss, Jetty, Glassfish, Tomcat usw.) Xerces in einem oder mehreren ihrer /lib Mappen.

Probleme

Lösung von Konflikten

Aus einigen - oder vielleicht allen - der oben genannten Gründe sind viele Organisationen benutzerdefinierte Builds von Xerces in ihren POMs. Dies ist nicht wirklich ein Problem, wenn Sie eine kleine Anwendung haben und nur Maven Central verwenden, aber es wird schnell zu einem Problem für Unternehmenssoftware, bei der Artifactory oder Nexus mehrere Repositories (JBoss, Hibernate, etc.) vertritt:

xml-apis proxied by Artifactory

Organisation A könnte zum Beispiel Folgendes veröffentlichen xml-apis als:

<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>

In der Zwischenzeit könnte Organisation B die gleichen jar als:

<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>

Obwohl B's jar ist eine niedrigere Version als die von A jar kennt Maven nicht dass es sich um das gleiche Artefakt handelt, da sie unterschiedliche groupId s. Daher kann es keine Konfliktlösung durchführen und sowohl jar s werden als aufgelöste Abhängigkeiten aufgenommen:

resolved dependencies with multiple xml-apis

Classloader-Hölle

Wie bereits erwähnt, wird die JRE mit Xerces in der JAXP RI ausgeliefert. Es wäre zwar schön, alle Xerces-Maven-Abhängigkeiten als <exclusion> s oder als <provided> Der Code von Drittanbietern, auf den Sie angewiesen sind, kann mit der in JAXP bereitgestellten Version des von Ihnen verwendeten JDK funktionieren oder auch nicht. Darüber hinaus müssen Sie sich mit den Xerces-Jars auseinandersetzen, die in Ihrem Servlet-Container enthalten sind. Sie haben also mehrere Möglichkeiten: Löschen Sie die Servlet-Version und hoffen Sie, dass Ihr Container mit der JAXP-Version läuft? Ist es besser, die Servlet-Version beizubehalten und zu hoffen, dass Ihre Anwendungs-Frameworks mit der Servlet-Version laufen? Wenn es gelingt, einen oder zwei der oben beschriebenen ungelösten Konflikte in Ihr Produkt einzuschleusen (was in einem großen Unternehmen leicht passieren kann), finden Sie sich schnell in der Classloader-Hölle wieder und fragen sich, welche Version von Xerces der Classloader zur Laufzeit auswählt und ob er unter Windows und Linux das gleiche Jar auswählt (wahrscheinlich nicht).

Lösungen?

Wir haben versucht, alle Xerces-Maven-Abhängigkeiten als <provided> oder als <exclusion> Dies ist jedoch schwer durchzusetzen (insbesondere bei einem großen Team), da die Artefakte so viele Aliasnamen haben ( xml-apis , xerces , xercesImpl , xmlParserAPIs , etc.). Außerdem laufen unsere Bibliotheken/Frameworks von Drittanbietern möglicherweise nicht auf der JAXP-Version oder der von einem Servlet-Container bereitgestellten Version.

Wie können wir dieses Problem am besten mit Maven lösen? Müssen wir eine so feinkörnige Kontrolle über unsere Abhängigkeiten ausüben und uns dann auf ein abgestuftes Classloading verlassen? Gibt es eine Möglichkeit, alle Xerces-Abhängigkeiten global auszuschließen und alle unsere Frameworks/Libs zu zwingen, die JAXP-Version zu verwenden?


UPDATE : Joshua Spiewak hat eine gepatchte Version der Xerces-Bau-Skripte auf XERCESJ-1454 die den Upload zu Maven Central ermöglicht. Stimmen Sie ab, beobachten Sie, tragen Sie zu diesem Thema bei und lassen Sie uns dieses Problem ein für alle Mal beheben.

125voto

Grzegorz Grzybek Punkte 6002

Es gibt 2.11.0 JARs (und Quell-JARs!) von Xerces in Maven Central seit dem 20. Februar 2013! Siehe Xerces in Maven Central . Ich frage mich, warum sie das Problem nicht gelöst haben. https://issues.apache.org/jira/browse/XERCESJ-1454 ...

Ich habe verwendet:

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.11.0</version>
</dependency>

und alle Abhängigkeiten haben sich problemlos aufgelöst - sogar die richtige xml-apis-1.4.01 !

Und was am wichtigsten ist (und was in der Vergangenheit nicht offensichtlich war) - das JAR in Maven Central ist das gleiche JAR wie in der offiziellen Xerces-J-bin.2.11.0.zip Vertrieb .

Ich konnte jedoch nicht finden xml-schema-1.1-beta Version - es kann keine Maven-Version sein classifier -ed Version wegen zusätzlicher Abhängigkeiten.

68voto

jtahlborn Punkte 51903

Ehrlich gesagt funktioniert so ziemlich alles, was uns begegnet ist, auch mit der JAXP-Version, also wir siempre ausschließen xml-apis y xercesImpl .

47voto

Sie könnten das Maven Enforcer-Plugin mit der Regel für verbotene Abhängigkeiten verwenden. Dies würde Ihnen erlauben, alle Aliase zu verbieten, die Sie nicht wollen, und nur die zu erlauben, die Sie wollen. Diese Regeln lassen den Maven-Build Ihres Projekts fehlschlagen, wenn sie verletzt werden. Wenn diese Regel für alle Projekte in einem Unternehmen gilt, könnten Sie die Plugin-Konfiguration in ein übergeordnetes Pom einfügen.

siehe:

43voto

netmikey Punkte 2353

Ich weiß, dass dies nicht die Frage genau beantworten, aber für ppl kommen in von Google, die zufällig Gradle für ihre Abhängigkeitsmanagement verwenden:

Ich habe es geschafft, alle Xerces/Java8-Probleme mit Gradle auf diese Weise zu beseitigen:

configurations {
    all*.exclude group: 'xml-apis'
    all*.exclude group: 'xerces'
}

17voto

Jens Schauder Punkte 70079

Ich denke, es gibt eine Frage, die Sie beantworten müssen:

Gibt es eine xerces*.jar, mit der alle Teile Ihrer Anwendung leben können?

Wenn nicht, sind Sie im Grunde genommen aufgeschmissen und müssen etwas wie OSGI verwenden, das es Ihnen ermöglicht, verschiedene Versionen einer Bibliothek gleichzeitig zu laden. Seien Sie gewarnt, dass es im Grunde ersetzt jar Version Fragen mit Classloader Fragen ...

Wenn es eine solche Version gibt, können Sie Ihr Repository dazu bringen, diese Version für alle Arten von Abhängigkeiten zurückzugeben. Es ist ein hässlicher Hack und würde damit enden, dass dieselbe Xerces-Implementierung mehrfach in Ihrem Klassenpfad vorhanden ist, aber besser als mehrere verschiedene Versionen von Xerces zu haben.

Sie könnten alle Abhängigkeiten zu xerces ausschließen und eine zu der Version hinzufügen, die Sie verwenden möchten.

Ich frage mich, ob man eine Art Versionsauflösungsstrategie als Plugin für Maven schreiben kann. Dies wäre wahrscheinlich die schönste Lösung, aber wenn überhaupt machbar braucht einige Forschung und Kodierung.

Für die Version, die in Ihrer Laufzeitumgebung enthalten ist, müssen Sie sicherstellen, dass sie entweder aus dem Klassenpfad der Anwendung entfernt wird oder dass die Anwendungs-Jars zuerst für das Klassenladen berücksichtigt werden, bevor der Lib-Ordner des Servers berücksichtigt wird.

Also, um es zusammenzufassen: Es ist ein Schlamassel, und das wird sich nicht ändern.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X