Mit "Xerces Hell" in Java / Maven umgehen?

In meinem Büro reicht die bloße Erwähnung des Wortes Xerces aus, um mörderische Wut von Entwicklern auszulösen. Ein flüchtiger Blick auf die anderen Xerces-Fragen zu SO scheint darauf hinzudeuten, dass fast alle Maven-Benutzer irgendwann von diesem Problem "berührt" sind. 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. Nahezu jede in Java geschriebene Bibliothek oder jedes Framework verwendet Xerces in gewisser Weise (transitiv, wenn nicht direkt).

Die im Lieferumfang enthaltenen Xerces - Gläseroffizielle Binärdateien sind bis heute nicht versioniert. Beispielsweise wird das Implementierungs-JAR für Xerces 2.11.0 benanntxercesImpl.jar und nichtxercesImpl-2.11.0.jar.

Das Xerces-Teambenutzt Maven nicht, was bedeutet, dass sie keine offizielle Veröffentlichung auf hochladenMaven Central.

Früher waren es Xercesals einzelnes Glas veröffentlicht (xerces.jar), wurde aber in zwei Gläser aufgeteilt, von denen eines die API enthielt (xml-apis.jar) und eine, die die Implementierungen dieser APIs enthält (xercesImpl.jar). Viele ältere Maven-POMs erklären immer noch eine Abhängigkeit vonxerces.jar. Irgendwann in der Vergangenheit wurde Xerces auch als veröffentlichtxmlParserAPIs.jar, von denen auch einige ältere POMs abhängen.

Die Versionen, die den Jars xml-apis und xercesImpl von denjenigen zugewiesen wurden, die ihre Jars in Maven-Repositorys bereitstellen, sind häufig unterschiedlich. Zum Beispiel könnten xml-apis die Version 1.3.03 und xercesImpl die Version 2.8.0 zugewiesen bekommen, obwohl beide von Xerces 2.8.0 stammen. Dies liegt daran, dass die Leute das xml-apis-jar oft mit der Version der Spezifikationen versehen, die es implementiert. Es gibt eine sehr schöne, aber unvollständige Aufschlüsselung davonHier.

Xerces ist der XML-Parser, der in der Referenzimplementierung der in der JRE enthaltenen Java-API für XML-Verarbeitung (JAXP) verwendet wird. Die Implementierungsklassen werden unter dem neu gepacktcom.sun.* Namespace, wodurch es gefährlich wird, direkt auf sie zuzugreifen, da sie in einigen JREs möglicherweise nicht verfügbar sind. Allerdings wird nicht die gesamte Xerces-Funktionalität über das verfügbar gemachtjava.* undjavax.* APIs; Beispielsweise gibt es keine API, die die Xerces-Serialisierung verfügbar macht.

Hinzu kommt, dass fast alle Servlet-Container (JBoss, Jetty, Glassfish, Tomcat usw.) mit Xerces in einem oder mehreren von ihnen ausgeliefert werden/lib Ordner.

ProblemeKonfliktlösung

Aus einigen oder allen der oben genannten Gründe veröffentlichen und verwenden viele Unternehmen benutzerdefinierte Builds von Xerces in ihren POMs. Dies ist kein wirkliches 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 Repositorys (JBoss, Hibernate usw.) proxysetzen:

Beispielsweise könnte Organisation A veröffentlichenxml-apis wie:

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

In der Zwischenzeit könnte Organisation B dasselbe veröffentlichenjar wie:

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

Obwohl B'sjar ist eine niedrigere Version als Ajar, Maven weiß nicht, dass sie dasselbe Artefakt sind, weil sie unterschiedlich sindgroupIds. Daher kann keine Konfliktlösung und beides durchgeführt werdenjars werden als aufgelöste Abhängigkeiten eingeschlossen:

Classloader Hölle

Wie oben erwähnt, wird die JRE mit Xerces im JAXP RI ausgeliefert. Es wäre zwar schön, alle Xerces Maven-Abhängigkeiten als zu markieren<exclusion>s oder als<provided>kann der Code von Drittanbietern, von dem Sie abhängig sind, mit der in JAXP des von Ihnen verwendeten JDK bereitgestellten Version funktionieren oder nicht. Außerdem haben Sie die Xerces-Gläser in Ihrem Servlet-Container, mit denen Sie fertig werden müssen. Sie haben also eine Reihe von Möglichkeiten: Löschen Sie die Servlet-Version und hoffen, dass Ihr Container auf der JAXP-Version ausgeführt wird? Ist es besser, die Servlet-Version zu verlassen und zu hoffen, dass Ihre Anwendungs-Frameworks auf der Servlet-Version ausgeführt werden? Wenn einer oder zwei der oben beschriebenen ungelösten Konflikte in Ihr Produkt eindringen (was in einer großen Organisation leicht vorkommt), befinden Sie sich schnell in der Hölle der Klassenladeprogramme und fragen sich, welche Version von Xerces das Klassenladeprogramm zur Laufzeit auswählt und ob dies der Fall ist oder nicht wird das gleiche jar in Windows und Linux auswählen (wahrscheinlich nicht).

Lösungen?

Wir haben versucht, alle Xerces Maven-Abhängigkeiten als zu markieren<provided> oder als<exclusion>Dies ist jedoch schwierig durchzusetzen (insbesondere bei einem großen Team), da die Artefakte so viele Aliase aufweisen (xml-apis, xerces, xercesImpl, xmlParserAPIs, usw.). Darüber hinaus können unsere Libs / Frameworks von Drittanbietern möglicherweise nicht auf der JAXP-Version oder der von einem Servlet-Container bereitgestellten Version ausgeführt werden.

Wie können wir dieses Problem am besten mit Maven lösen? Müssen wir eine so genaue Kontrolle über unsere Abhängigkeiten ausüben und uns dann auf das gestufte Laden von Klassen verlassen? Gibt es eine Möglichkeit, alle Xerces-Abhängigkeiten global auszuschließen und alle unsere Frameworks / Libs zur Verwendung der JAXP-Version zu zwingen?

AKTUALISIEREN: Joshua Spiewak hat eine gepatchte Version der Xerces-Build-Skripte hochgeladenXERCESJ-1454 Dies ermöglicht das Hochladen auf Maven Central. Stimmen Sie ab, schauen Sie zu, tragen Sie zu diesem Problem bei und lassen Sie uns das Problem ein für alle Mal beheben.

Antworten auf die Frage(11)

Ihre Antwort auf die Frage