Имеете дело с «Xerces ад» в Java / Maven?

В моем офисе простого упоминания слова Xerces достаточно, чтобы разжечь убийственную ярость от разработчиков. Беглый взгляд на другие вопросы Xerces по SO, похоже, указывает на то, что почти все пользователи Maven «тронуты». по этой проблеме в какой-то момент. К сожалению, понимание проблемы требует немного знаний об истории Xerces ...

History

Xerces is the most widely used XML parser in the Java ecosystem. Almost every library or framework written in Java uses Xerces in some capacity (transitively, if not directly).

The Xerces jars included in the official binaries are, to this day, not versioned. For example, the Xerces 2.11.0 implementation jar is named xercesImpl.jar and not xercesImpl-2.11.0.jar.

The Xerces team does not use Maven, which means they do not upload an official release to Maven Central.

Xerces used to be released as a single jar (xerces.jar), but was split into two jars, one containing the API (xml-apis.jar) and one containing the implementations of those APIs (xercesImpl.jar). Many older Maven POMs still declare a dependency on xerces.jar. At some point in the past, Xerces was also released as xmlParserAPIs.jar, which some older POMs also depend on.

The versions assigned to the xml-apis and xercesImpl jars by those who deploy their jars to Maven repositories are often different. For example, xml-apis might be given version 1.3.03 and xercesImpl might be given version 2.8.0, even though both are from Xerces 2.8.0. This is because people often tag the xml-apis jar with the version of the specifications that it implements. There is a very nice, but incomplete breakdown of this here.

To complicate matters, Xerces is the XML parser used in the reference implementation of the Java API for XML Processing (JAXP), included in the JRE. The implementation classes are repackaged under the com.sun.* namespace, which makes it dangerous to access them directly, as they may not be available in some JREs. However, not all of the Xerces functionality is exposed via the java.* and javax.* APIs; for example, there is no API that exposes Xerces serialization.

Adding to the confusing mess, almost all servlet containers (JBoss, Jetty, Glassfish, Tomcat, etc.), ship with Xerces in one or more of their /lib folders.

Problems Conflict Resolution

По некоторым - или, возможно, по всем - причинам выше, многие организации публикуют и используют пользовательские сборки Xerces в своих РОМ. На самом деле это не проблема, если у вас небольшое приложение и вы используете только Maven Central, но это быстро становится проблемой для корпоративного программного обеспечения, где Artifactory или Nexus проксирует несколько репозиториев (JBoss, Hibernate и т. Д.):

xml-apis proxied by Artifactory

Например, организация А может опубликоватьxml-apis как:

<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>

Между тем, организация B может опубликоватьjar как:

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

Хотя B 'sjar является более низкой версией, чем A 'sjarМэйвен не знает что это один и тот же артефакт, потому что они имеют разные groupIds. Таким образом, он не может выполнять разрешение конфликтов и оба jars будут включены как разрешенные зависимости:

resolved dependencies with multiple xml-apis

Classloader Hell

Как упоминалось выше, JRE поставляется с Xerces в JAXP RI. Хотя было бы неплохо отметить все зависимости Xerces Maven как<exclusion>с или как<provided>сторонний код, от которого вы зависите, может работать или не работать с версией, предоставленной в JAXP той JDK, которую вы используете. Кроме того, у вас есть контейнеры Xerces, отправленные в ваш контейнер сервлетов для борьбы. Это оставляет вам несколько вариантов: вы удаляете версию сервлета и надеетесь, что ваш контейнер работает на версии JAXP? Лучше ли оставить версию сервлета и надеяться, что фреймворки ваших приложений будут работать на версии сервлета? Если одному или двум из неразрешенных конфликтов, описанных выше, удастся проникнуть в ваш продукт (это легко случится в большой организации), вы быстро окажетесь в аду загрузчика классов, задаваясь вопросом, какую версию Xerces выбирает загрузчик классов во время выполнения и действительно ли выберу одну и ту же банку в Windows и Linux (вероятно, нет).

Solutions?

Мы пытались пометить все зависимости Xerces Maven как<provided> или как<exclusion>, но это трудно осуществить (особенно с большой командой), учитывая, что артефакты имеют так много псевдонимов (xml-apis, xerces, xercesImpl, xmlParserAPIs, так далее.). Кроме того, наши сторонние библиотеки / фреймворки могут не работать на версии JAXP или версии, предоставляемой контейнером сервлета.

How can we best address this problem with Maven? Do we have to exercise such fine-grained control over our dependencies, and then rely on tiered classloading? Is there some way to globally exclude all Xerces dependencies, and force all of our frameworks/libs to use the JAXP version?

UPDATE: Джошуа Спивак загрузил исправленную версию сценариев сборки Xerces вXERCESJ-1454 что позволяет загружать в Maven Central. Проголосуйте / посмотрите / внесите свой вклад в решение этой проблемы и дайте ей раз и навсегда решить эту проблему.

Ответы на вопрос(11)

Ваш ответ на вопрос