Dans mon bureau, la simple mention du mot Xerces suffit pour inciter les développeurs à la rage meurtrière. Un coup d'œil rapide aux autres questions de Xerces sur SO semble indiquer que presque tous les utilisateurs de Maven sont "touchés" par ce problème à un moment donné. Malheureusement, comprendre le problème nécessite un peu de connaissance sur l'histoire de Xerces ...
Histoire
Xerces est l'analyseur XML le plus utilisé dans l'écosystème Java. Presque toutes les bibliothèques ou frameworks écrits en Java utilisent Xerces dans une certaine mesure (de manière transitoire, sinon directement).
Les bocaux Xerces inclus dans les binaires officiels ne sont pas, à ce jour, versionnés. Par exemple, le pot d'implémentation Xerces 2.11.0 est nommé
xercesImpl.jar
et nonxercesImpl-2.11.0.jar
.L'équipe de Xerces n'utilise pas Maven , ce qui signifie qu'elle ne télécharge pas de version officielle sur Maven Central .
Xerces était auparavant publié sous la forme d'un seul pot (
xerces.jar
), mais était divisé en deux pots, l'un contenant l'API (xml-apis.jar
) et l'autre contenant les implémentations de ces API (xercesImpl.jar
). De nombreux POM Maven plus anciens déclarent toujours une dépendancexerces.jar
. À un moment donné dans le passé, Xerces a également été publié en tant quexmlParserAPIs.jar
, dont certains POM plus anciens dépendent également.Les versions attribuées aux fichiers xml-apis et xercesImpl par ceux qui déploient leurs fichiers dans les référentiels Maven sont souvent différentes. Par exemple, xml-apis peut recevoir la version 1.3.03 et xercesImpl peut recevoir la version 2.8.0, même si les deux proviennent de Xerces 2.8.0. C'est parce que les gens marquent souvent le pot xml-apis avec la version des spécifications qu'il implémente. Il y a une ventilation très agréable, mais incomplète de cette 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), inclus dans le JRE. Les classes d'implémentation sont reconditionnées sous l'
com.sun.*
espace de noms, ce qui rend leur accès direct dangereux, car elles peuvent ne pas être disponibles dans certains JRE. Cependant, toutes les fonctionnalités de Xerces ne sont pas exposées via lejava.*
javax.*
API et ; par exemple, il n'y a pas d'API qui expose la sérialisation de Xerces.Ajoutant au désordre déroutant, presque tous les conteneurs de servlets (JBoss, Jetty, Glassfish, Tomcat, etc.), sont expédiés avec Xerces dans un ou plusieurs de leurs
/lib
dossiers.
Problèmes
Résolution de conflit
Pour certaines - ou peut-être toutes - des raisons ci-dessus, de nombreuses organisations publient et utilisent des versions personnalisées de Xerces dans leurs POM. 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 assure le proxy de plusieurs référentiels (JBoss, Hibernate, etc.):
Par exemple, l'organisation A peut publier en xml-apis
tant que:
<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>
Pendant ce temps, l'organisation B pourrait publier les mêmes jar
que:
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
Bien que les B jar
soient une version inférieure aux A jar
, Maven ne sait pas qu'ils sont le même artefact car ils ont des groupId
s différents
. Ainsi, il ne peut pas effectuer la résolution des conflits et les deux
jar
s seront inclus en tant que dépendances résolues:
Classloader Hell
Comme mentionné ci-dessus, le JRE est livré avec Xerces dans le JAXP RI. Bien qu'il serait bien de marquer toutes les dépendances de Xerces Maven comme<exclusion>
s ou comme<provided>
, le code tiers dont vous dépendez peut ou non fonctionner avec la version fournie dans JAXP du JDK que vous utilisez. De plus, vous avez les pots Xerces expédiés dans votre conteneur de servlet pour faire face. Cela vous laisse un certain nombre de choix: supprimez-vous la version du servlet et espérez-vous que votre conteneur fonctionne sur la version JAXP? Est-il préférable de laisser la version du servlet et d'espérer que vos frameworks d'application fonctionnent sur la version du servlet? Si un ou deux des conflits non résolus décrits ci-dessus parviennent à se glisser dans votre produit (facile à produire dans une grande organisation), vous vous retrouvez rapidement dans l'enfer du chargeur de classe, en vous demandant quelle version de Xerces le chargeur de classe choisit au moment de l'exécution et si oui ou non il choisira le même pot sous Windows et Linux (probablement pas).
Solutions?
Nous avons essayé de marquer toutes les dépendances Xerces Maven <provided>
ou comme <exclusion>
, mais cela est difficile à appliquer ( en particulier avec une grande équipe) étant donné que les objets ont tant d'alias ( xml-apis
, xerces
, xercesImpl
,xmlParserAPIs
, etc.). De plus, nos bibliothèques / frameworks tiers peuvent ne pas fonctionner sur la version JAXP ou la version fournie par un conteneur de servlet.
Comment pouvons-nous résoudre au mieux ce problème avec Maven? Doit-on exercer un contrôle aussi fin sur nos dépendances, puis s'appuyer sur un chargement de classe à plusieurs niveaux? Existe-t-il un moyen d'exclure globalement toutes les dépendances de Xerces et de forcer tous nos frameworks / bibliothèques à utiliser la version JAXP?
MISE À JOUR : Joshua Spiewak a téléchargé une version corrigée des scripts de construction de Xerces sur XERCESJ-1454 qui permet le téléchargement sur Maven Central. Votez / regardez / contribuez à ce problème et résolvons ce problème une fois pour toutes.