En mi oficina, la mera mención de la palabra Xerces es suficiente para incitar la ira asesina de los desarrolladores. Una mirada superficial a las otras preguntas de Xerces sobre SO parece indicar que casi todos los usuarios de Maven están "tocados" por este problema en algún momento. Desafortunadamente, comprender el problema requiere un poco de conocimiento sobre la historia de Xerces ...
Historia
Xerces es el analizador XML más utilizado en el ecosistema Java. Casi todas las bibliotecas o frameworks escritos en Java usan Xerces en cierta capacidad (transitivamente, si no directamente).
Los frascos Xerces incluidos en los binarios oficiales no están, hasta el día de hoy, versionados. Por ejemplo, el jar de implementación Xerces 2.11.0 se nombra
xercesImpl.jar
y noxercesImpl-2.11.0.jar
.El equipo de Xerces no usa Maven , lo que significa que no sube un lanzamiento oficial a Maven Central .
Xerces solía lanzarse como un solo jar (
xerces.jar
), pero se dividió en dos tarros, uno que contenía la API (xml-apis.jar
) y otro que contenía las implementaciones de esas API (xercesImpl.jar
). Muchos POM Maven más antiguos todavía declaran una dependenciaxerces.jar
. En algún momento en el pasado, Xerces también se lanzó comoxmlParserAPIs.jar
, de lo que también dependen algunos POM más antiguos.Las versiones asignadas a los frascos xml-apis y xercesImpl por aquellos que implementan sus frascos en los repositorios de Maven a menudo son diferentes. Por ejemplo, xml-apis podría tener la versión 1.3.03 y xercesImpl podría tener la versión 2.8.0, aunque ambas son de Xerces 2.8.0. Esto se debe a que la gente suele etiquetar el xml-apis jar con la versión de las especificaciones que implementa. Hay un desglose muy agradable, pero incompleto de esto aquí .
Para complicar las cosas, Xerces es el analizador XML utilizado en la implementación de referencia de la API Java para el procesamiento XML (JAXP), incluido en el JRE. Las clases de implementación se vuelven a empaquetar bajo el
com.sun.*
espacio de nombres, lo que hace que sea peligroso acceder a ellas directamente, ya que pueden no estar disponibles en algunos JRE. Sin embargo, no toda la funcionalidad de Xerces se expone a través de las APIjava.*
yjavax.*
; por ejemplo, no hay API que exponga la serialización de Xerces.Además del confuso desorden, casi todos los contenedores de servlets (JBoss, Jetty, Glassfish, Tomcat, etc.) se envían con Xerces en una o más de sus
/lib
carpetas.
Problemas
La resolución de conflictos
Por algunas, o quizás por todas, las razones anteriores, muchas organizaciones publican y consumen compilaciones personalizadas de Xerces en sus POM. Esto no es realmente un problema si tiene una aplicación pequeña y solo está utilizando Maven Central, pero rápidamente se convierte en un problema para el software empresarial donde Artifactory o Nexus está representando múltiples repositorios (JBoss, Hibernate, etc.):
Por ejemplo, la organización A podría publicar xml-apis
como:
<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>
Mientras tanto, la organización B podría publicar lo mismo jar
que:
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
Aunque B's jar
es una versión más baja que A's jar
, Maven no sabe que son el mismo artefacto porque tienen diferentes
groupId
s. Por lo tanto, no puede realizar la resolución de conflictos y ambos
jar
s se incluirán como dependencias resueltas:
Infierno del cargador de clases
Como se mencionó anteriormente, el JRE se envía con Xerces en el JAXP RI. Mientras que sería bueno para marcar todas las dependencias de Maven como Xerces <exclusion>
s o como<provided>
, el código de terceros del que depende puede o no funcionar con la versión proporcionada en JAXP del JDK que está utilizando. Además, tiene los frascos Xerces enviados en su contenedor de servlets con los que lidiar. Esto le deja con una serie de opciones: ¿Elimina la versión del servlet y espera que su contenedor se ejecute en la versión JAXP? ¿Es mejor dejar la versión de servlet y esperar que los marcos de sus aplicaciones se ejecuten en la versión de servlet? Si uno o dos de los conflictos no resueltos descritos anteriormente logran deslizarse en su producto (fácil de suceder en una organización grande), rápidamente se encuentra en el infierno del cargador de clases, preguntándose qué versión de Xerces está eligiendo el cargador de clases en el tiempo de ejecución y si elegirá el mismo jar en Windows y Linux (probablemente no).
Soluciones?
Hemos intentado marcar todas las dependencias de Maven como Xerces <provided>
o como una <exclusion>
, pero esto es difícil de hacer cumplir (especialmente con un equipo grande) dado que los artefactos tienen tantos alias ( xml-apis
, xerces
, xercesImpl
, xmlParserAPIs
, etc.). Además, nuestros libs / frameworks de terceros pueden no ejecutarse en la versión JAXP o la versión proporcionada por un contenedor de servlet.
¿Cómo podemos abordar mejor este problema con Maven? ¿Tenemos que ejercer un control tan preciso sobre nuestras dependencias y luego confiar en la carga de clases por niveles? ¿Hay alguna forma de excluir globalmente todas las dependencias de Xerces y obligar a todos nuestros frameworks / libs a usar la versión JAXP?
ACTUALIZACIÓN : Joshua Spiewak ha subido una versión parcheada de los scripts de compilación de Xerces a XERCESJ-1454 que permite la carga en Maven Central. Vota / mira / contribuye a este problema y solucionemos este problema de una vez por todas.