¿Tratar con el "infierno de Xerces" en Java / Maven?

En mi oficina, la mera mención de la palabra Xerces es suficiente para incitar a la rabia asesina de los desarrolladores. Una mirada rápida 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, entender el problema requiere un poco de conocimiento sobre la historia de Xerces ...

Historia

Xerces es el analizador XML más utilizado en el ecosistema de Java. Casi todas las bibliotecas o marcos escritos en Java usan Xerces en alguna capacidad (transitivamente, si no directamente).

Los frascos de Xerces incluidos en elbinarios oficiales Son, hasta el día de hoy, no versionados. Por ejemplo, el jar de implementación Xerces 2.11.0 se llamaxercesImpl.jar y noxercesImpl-2.11.0.jar.

El equipo de Xerces.no usa maven, lo que significa que no suben un comunicado oficial aMaven Central.

Xerces solía serlanzado como un solo frasco (xerces.jar), pero se dividió en dos frascos, uno que contiene la API (xml-apis.jar) y una que contiene las implementaciones de esas API (xercesImpl.jar). Muchos POM de Maven más viejos todavía declaran una dependencia enxerces.jar. En algún momento en el pasado, Xerces también fue lanzado comoxmlParserAPIs.jar, que algunos POMs más antiguos también dependen.

Las versiones asignadas a los archivos xml-apis y xercesImpl por aquellos que implementan sus archivos jar en los repositorios de Maven a menudo son diferentes. Por ejemplo, a xml-apis se le puede dar la versión 1.3.03 y a xercesImpl se le puede dar la versión 2.8.0, aunque ambas sean de Xerces 2.8.0. Esto se debe a que la gente suele etiquetar el tarro xml-apis con la versión de las especificaciones que implementa. Hay un desglose muy bonito, pero incompleto de esto.aquí.

Para complicar las cosas, Xerces es el analizador de XML utilizado en la implementación de referencia de la API de Java para el procesamiento de XML (JAXP), incluido en el JRE. Las clases de implementación son reenvasadas bajo elcom.sun.* espacio de nombres, lo que hace que sea peligroso acceder a ellos directamente, ya que es posible que no estén disponibles en algunos JRE. Sin embargo, no toda la funcionalidad de Xerces está expuesta a través deljava.* yjavax.* APIs; por ejemplo, no hay una API que exponga la serialización de Xerces.

Además del confuso lío, casi todos los contenedores de servlets (JBoss, Jetty, Glassfish, Tomcat, etc.) se envían con Xerces en uno o más de sus/lib carpetas

ProblemasLa resolución de conflictos

Por alguna o muchas de 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á usando Maven Central, pero rápidamente se convierte en un problema para el software empresarial donde Artifactory o Nexus está procesando varios repositorios (JBoss, Hibernate, etc.):

Por ejemplo, la organización A podría publicarxml-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 como:

<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>

Aunque bjar es una versión más baja que la de Ajar, Maven no sabe que son el mismo artefacto porque tienen diferentesgroupIds. Por lo tanto, no puede realizar la resolución de conflictos y tantojars se incluirán como dependencias resueltas:

Classloader Hell

Como se mencionó anteriormente, el JRE se envía con Xerces en el JAXP RI. Si bien sería bueno marcar todas las dependencias de Xerces Maven como<exclusion>s o como<provided>, el código de terceros del que depende puede o no funcionar con la versión provista en JAXP del JDK que está utilizando. Además, tiene los frascos de Xerces enviados en su contenedor de servlets para enfrentarlos. Esto lo deja con una serie de opciones: ¿Borra la versión del servlet y espera que su contenedor se ejecute en la versión JAXP? ¿Es mejor dejar la versión del servlet y esperar que los marcos de aplicación se ejecuten en la versión del servlet? Si uno o dos de los conflictos no resueltos descritos anteriormente logran deslizarse en su producto (es fácil de pasar en una gran organización), se encontrará rápidamente en el infierno del cargador de clases, preguntándose qué versión de Xerces está seleccionando el cargador de clases en tiempo de ejecución y si es o no Escogerá el mismo jar en Windows y Linux (probablemente no).

Soluciones?

Hemos intentado marcar todas las dependencias de Xerces Maven como<provided> o como un<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, nuestras bibliotecas / marcos de terceros pueden no ejecutarse en la versión de JAXP o en la versión proporcionada por un contenedor de servlets.

¿Cómo podemos abordar mejor este problema con Maven? ¿Debemos 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 forzar a todos nuestros marcos / libs a usar la versión JAXP?

ACTUALIZAR: Joshua Spiewak ha subido una versión parcheada de los scripts de compilación de Xerces aXERCESJ-1454 que permite subir a Maven Central. Vote / vea / contribuya a este problema y solucionemos este problema de una vez por todas.

Respuestas a la pregunta(11)

Su respuesta a la pregunta