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 nichtxercesImpl-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 vonxerces.jar
. Irgendwann in der Vergangenheit wurde Xerces auch veröffentlicht alsxmlParserAPIs.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 diejava.*
yjavax.*
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:
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:
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.