In meinem Büro reicht die bloße Erwähnung des Wortes Xerces aus, um Entwickler zu mörderischer Wut anzuregen. 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" 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 in Java geschriebene Bibliothek oder jedes in Java geschriebene Framework verwendet Xerces in irgendeiner Form (transitiv, wenn nicht direkt).
Die in den offiziellen Binärdateien enthaltenen Xerces-Gläser sind bis heute nicht versioniert. Beispielsweise wird das Implementierungsglas für Xerces 2.11.0 benannt
xercesImpl.jar
und nichtxercesImpl-2.11.0.jar
.Das Xerces-Team verwendet Maven nicht, dh es wird keine offizielle Version auf Maven Central hochgeladen .
Xerces wurde früher als einzelnes jar (
xerces.jar
) veröffentlicht, wurde jedoch in zwei Jars aufgeteilt, von denen eines die API (xml-apis.jar
) und eines die Implementierungen dieser APIs (xercesImpl.jar
) enthielt . 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 dem auch einige ältere POMs abhängen.Die Versionen, die den JARs xml-apis und xercesImpl von denjenigen zugewiesen werden, die ihre Jars in Maven-Repositorys bereitstellen, sind häufig unterschiedlich. Beispielsweise könnte xml-apis die Version 1.3.03 und xercesImpl die Version 2.8.0 erhalten, obwohl beide von Xerces 2.8.0 stammen. Dies liegt daran, dass Benutzer das xml-apis-Glas häufig mit der Version der von ihm implementierten Spezifikationen versehen. Es ist eine sehr schöne, aber unvollständige Aufteilung dieses hier .
Xerces ist der XML-Parser, der in der Referenzimplementierung der in der JRE enthaltenen Java-API für die XML-Verarbeitung (JAXP) verwendet wird. Die Implementierungsklassen werden unter dem
com.sun.*
Namespace neu gepackt, was den direkten Zugriff auf sie gefährlich macht, da sie in einigen JREs möglicherweise nicht verfügbar sind. Es wird jedoch nicht die gesamte Xerces-Funktionalität über die APIsjava.*
undjavax.*
bereitgestellt. Beispielsweise gibt es keine API, die die Xerces-Serialisierung verfügbar macht.Zusätzlich zu dem verwirrenden Durcheinander werden fast alle Servlet-Container (JBoss, Jetty, Glassfish, Tomcat usw.) mit Xerces in einem oder mehreren ihrer
/lib
Ordner ausgeliefert.
Probleme
Konfliktlösung
Aus einigen - oder vielleicht 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.) als Proxy verwenden:
Beispielsweise könnte Organisation A Folgendes veröffentlichen xml-apis
:
<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>
In der Zwischenzeit könnte Organisation B dasselbe veröffentlichen jar
wie:
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
Obwohl B jar
eine niedrigere Version als A ist jar
, weiß Maven nicht, dass sie dasselbe Artefakt sind, weil sie unterschiedliche
groupId
s haben. Daher kann keine Konfliktlösung durchgeführt werden, und beide
jar
s werden als gelöste Abhängigkeiten aufgenommen:
Klassenlader 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 <exclusion>
s oder als zu markieren<provided>
Der Code eines Drittanbieters, von dem Sie abhängig sind, funktioniert möglicherweise nicht mit der in JAXP des von Ihnen verwendeten JDK bereitgestellten Version. Außerdem haben Sie die Xerces-Gläser in Ihrem Servlet-Container, um damit fertig zu werden. 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 Anwendungsframeworks auf der Servlet-Version ausgeführt werden? Wenn es einem oder zwei der oben beschriebenen ungelösten Konflikte gelingt, in Ihr Produkt einzudringen (was in einer großen Organisation leicht vorkommt), befinden Sie sich schnell in der Hölle der Klassenlader und fragen sich, welche Version von Xerces der Klassenlader zur Laufzeit auswählt und ob dies der Fall ist oder nicht wird das gleiche Glas in Windows und Linux auswählen (wahrscheinlich nicht).
Lösungen?
Wir haben versucht , alle Xerces Maven Abhängigkeiten als Markierung <provided>
oder als ein <exclusion>
, aber das ist schwer durchzusetzen (vor allem mit einem großen Team) gegeben , dass die Artefakte haben so viele Aliase ( xml-apis
, xerces
, xercesImpl
, xmlParserAPIs
, etc.). Darüber hinaus können unsere Bibliotheken / 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 unsere Abhängigkeiten so genau kontrollieren 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 / Bibliotheken zur Verwendung der JAXP-Version zu zwingen?
UPDATE : Joshua Spiewak hat eine gepatchte Version der Xerces-Build-Skripte auf XERCESJ-1454 hochgeladen , die das Hochladen auf Maven Central ermöglicht. Stimmen Sie ab / schauen Sie zu / tragen Sie zu diesem Problem bei und lassen Sie uns dieses Problem ein für alle Mal beheben.