Dans mon bureau, la simple mention du mot Xerces suffit à susciter la rage meurtrière des développeurs. Un coup d'œil rapide aux autres questions sur Xerces sur SO semble indiquer que presque tous les utilisateurs de Maven sont "touchés" par ce problème à un moment ou à un autre. Malheureusement, pour comprendre le problème, il faut connaître un peu l'histoire de Xerces...
Histoire
-
Xerces est l'analyseur XML le plus largement utilisé dans l'écosystème Java. Presque toutes les bibliothèques ou frameworks écrits en Java utilisent Xerces d'une manière ou d'une autre (de manière transitive, sinon directement).
-
Les bocaux Xerces inclus dans le binaires officiels ne sont, à ce jour, pas versionnés. Par exemple, le jar de l'implémentation de Xerces 2.11.0 est nommé
xercesImpl.jar
et nonxercesImpl-2.11.0.jar
. -
L'équipe Xerces n'utilise pas Maven ce qui signifie qu'ils ne télécharger une version officielle sur Maven Central .
-
Xerces était publié sous forme de pot unique (
xerces.jar
), mais a été divisé en deux pots, l'un contenant l'API (xml-apis.jar
) et un autre contenant les implémentations de ces API (xercesImpl.jar
). De nombreux anciens POMs Maven déclarent encore une dépendance à l'égard dexerces.jar
. À un moment donné dans le passé, Xerces a également été publié sous le nom dexmlParserAPIs.jar
dont dépendent également certains anciens POM. -
Les versions attribuées aux jars xml-apis et xercesImpl par ceux qui déploient leurs jars dans les dépôts Maven sont souvent différentes. Par exemple, on peut attribuer à xml-apis la version 1.3.03 et à xercesImpl la version 2.8.0, même si les deux sont issus de Xerces 2.8.0. Ceci est dû au fait que les gens étiquettent souvent le jar xml-apis avec la version des spécifications qu'il implémente. Il existe une très belle, mais incomplète, décomposition de ceci ici .
-
Pour compliquer les choses, Xerces est l'analyseur XML utilisé dans l'implémentation de référence de l'API Java pour le traitement XML (JAXP), incluse dans le JRE. Les classes d'implémentation sont repackagées sous le nom de
com.sun.*
ce qui rend dangereux le fait d'y accéder directement, car ils peuvent ne pas être disponibles dans certains JRE. Cependant, toute la fonctionnalité de Xerces n'est pas exposée via l'espace de nomjava.*
yjavax.*
Par exemple, il n'y a pas d'API qui expose la sérialisation Xerces. -
Pour ajouter à la confusion, presque tous les conteneurs de servlets (JBoss, Jetty, Glassfish, Tomcat, etc.) sont livrés avec Xerces dans un ou plusieurs de leurs composants.
/lib
les dossiers.
Problèmes
Résolution des conflits
Pour certaines - ou peut-être pour toutes - les raisons ci-dessus, de nombreux organisations publient et consomment des constructions personnalisées de Xerces dans leurs POMs. Ce n'est pas vraiment un problème si vous avez une petite application et que vous n'utilisez que Maven Central, mais cela devient rapidement un problème pour les logiciels d'entreprise où Artifactory ou Nexus est le proxy de plusieurs référentiels (JBoss, Hibernate, etc.) :
Par exemple, l'organisation A pourrait publier xml-apis
comme :
<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>
Pendant ce temps, l'organisation B pourrait publier le même jar
comme :
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
Bien que B jar
est une version inférieure à celle de A jar
Maven ne sait pas qu'il s'agit du même artefact parce qu'ils sont différents. groupId
s. Ainsi, il ne peut pas effectuer de résolution de conflit et les deux jar
seront inclus comme dépendances résolues :
L'enfer des chargeurs de classe
Comme mentionné ci-dessus, le JRE est livré avec Xerces dans le JAXP RI. Bien qu'il serait agréable de marquer toutes les dépendances Xerces Maven comme <exclusion>
ou comme <provided>
En effet, le code tiers dont vous dépendez peut ou non fonctionner avec la version fournie dans JAXP du JDK que vous utilisez. En outre, vous devez faire face aux bocaux Xerces livrés avec votre conteneur de servlets. Vous avez donc un certain nombre de choix : Supprimez-vous la version du servlet et espérez que votre conteneur fonctionne avec la version JAXP ? Est-il préférable de laisser la version servlet et d'espérer que vos cadres d'application fonctionnent sur la version servlet ? Si un ou deux des conflits non résolus décrits ci-dessus parviennent à se glisser dans votre produit (ce qui est facile à faire dans une grande organisation), vous vous retrouvez rapidement dans l'enfer du classloader, à vous demander quelle version de Xerces le classloader choisit au moment de l'exécution et s'il choisira ou non le même jar sous Windows et sous Linux (probablement pas).
Des solutions ?
Nous avons essayé de marquer toutes les dépendances de Xerces Maven en tant que <provided>
ou en tant que <exclusion>
mais cela est difficile à appliquer (surtout avec une grande équipe) étant donné que les artefacts ont tellement d'alias ( xml-apis
, xerces
, xercesImpl
, xmlParserAPIs
etc.). En outre, nos librairies/frames de tiers peuvent ne pas fonctionner avec la version JAXP ou la version fournie par un conteneur de servlets.
Comment pouvons-nous résoudre au mieux ce problème avec Maven ? Devons-nous exercer un contrôle aussi fin sur nos dépendances, puis compter sur un chargement de classe à plusieurs niveaux ? Existe-t-il un moyen d'exclure globalement toutes les dépendances Xerces et de forcer tous nos frameworks/libs à utiliser la version JAXP ?
UPDATE : Joshua Spiewak a téléchargé une version corrigée de la construction de Xerces scripts à XERCESJ-1454 qui permet le téléchargement vers Maven Central. Votez/observez/contribuez à cette question et résolvons ce problème une fois pour toutes.
9 votes
Merci pour cette question détaillée. Je ne comprends pas la motivation de l'équipe xerces. J'imagine qu'ils sont fiers de leur produit et prennent plaisir à ce que d'autres l'utilisent, mais l'état actuel de xerces et de maven est honteux. Malgré tout, ils peuvent faire ce qu'ils veulent, même si cela n'a aucun sens pour moi. Je me demande si les gars de Sonatype ont des suggestions à faire.
39 votes
C'est peut-être hors sujet, mais c'est probablement le meilleur message que j'ai jamais vu. Plus en rapport avec la question, ce que vous décrivez est l'un des problèmes les plus douloureux que l'on puisse rencontrer. Excellente initiative !
2 votes
@TravisSchneeberger Une grande partie de la complexité est due au fait que Sun a choisi d'utiliser Xerces dans le JRE lui-même. On peut difficilement blâmer les gens de Xerces pour cela.
0 votes
Habituellement, nous essayons de trouver une version de Xerces qui satisfait toutes les bibliothèques dépendantes par essais et erreurs, si ce n'est pas possible, nous refactorons les WARs pour diviser l'application en WARs séparés (chargeurs de classes séparés). Cet outil (je l'ai écrit) aide à comprendre ce qui se passe jhades.org en permettant d'interroger le classpath pour les jars , et les classes - cela fonctionne aussi dans le cas où le serveur ne démarre pas encore
0 votes
Juste un petit commentaire si vous obtenez cette erreur en lançant servicemix à partir de git bash sous Windows : lancez-le plutôt à partir de cmd "normal".
0 votes
Il existe un plugin Maven qui vérifie les classes en double dans le classpath mis en place avec les dépendances Maven. Je ne connais pas son nom mais il devrait attraper les copies multiples de Xerces.
0 votes
Comment "uploader vers Maven Central" va résoudre le problème de transitivité où ce JAR est utilisé dans plusieurs autres modules, qui sont utilisés par un autre projet ?
0 votes
@GIIRRII Si le projet lui-même fait les téléchargements, personne d'autre ne sera tenté de télécharger sa propre version renommée, rebrandée, recompilée, patchée de manière incompétente, empaquetée de manière incompétente, etc. sur Maven Central. Ce qui signifie que d'autres projets ne les ramasseront pas, et si vous utilisez leur projet, vous n'hériterez pas des décisions de ces projets de ramasser une copie défectueuse de Xerces.