В моем офисе простого упоминания слова Xerces достаточно, чтобы вызвать убийственную ярость от разработчиков. Беглый взгляд на другие вопросы Xerces по SO, похоже, указывает на то, что в какой-то момент почти все пользователи Maven "затронуты" этой проблемой. К сожалению, понимание проблемы требует немного знаний об истории Xerces...
история
-
Xerces - наиболее широко используемый анализатор XML в экосистеме Java. Почти каждая библиотека или фреймворк, написанный на Java, в некоторой степени использует Xerces (транзитивно, если не напрямую).
-
Банки Xerces, включенные в официальные двоичные файлы, до настоящего времени не имеют версий. Например, jar реализации Xerces 2.11.0 называется
xercesImpl.jar
а неxercesImpl-2.11.0.jar
. -
Команда Xerces не использует Maven, что означает, что они не загружают официальный релиз в Maven Central.
-
Раньше Xerces выпускался как один jar (
xerces.jar
), но был разбит на два jar, один из которых содержал API (xml-apis.jar
), а другой содержал реализации этих API (xercesImpl.jar
). Многие старые POM Maven по-прежнему объявляют зависимость отxerces.jar
. В некоторый момент в прошлом Xerces также выпускался какxmlParserAPIs.jar
, от которого также зависят некоторые более старые POM. -
Версии, назначаемые банкам xml-apis и xercesImpl теми, кто развертывает свои банки в репозиториях Maven, часто различаются. Например, xml-apis может иметь версию 1.3.03, а xercesImpl - версию 2.8.0, даже если обе версии Xerces 2.8.0. Это связано с тем, что люди часто помечают jar xml-apis версией спецификаций, которые он реализует. Существует очень хороший, но неполный пробой этого здесь.
-
Чтобы усложнить ситуацию, Xerces - это анализатор XML, используемый в эталонной реализации Java API для обработки XML (JAXP), включенной в JRE. Классы реализации переупаковываются в пространстве имен
com.sun.*
, Что делает опасным прямой доступ к ним, поскольку они могут быть недоступны в некоторых JRE. Однако не все функциональные возможности Xerces доступны через APIjava.*
Иjavax.*
; например, нет API, который предоставляет сериализацию Xerces. -
Помимо этого запутанного беспорядка, почти все контейнеры сервлетов (JBoss, Jetty, Glassfish, Tomcat и т.д.) Поставляются с Xerces в одной или нескольких папках
/lib
.
Проблемы
Решение конфликта
По некоторым - или, возможно, по всем - причинам, изложенным выше, многие организации публикуют и используют пользовательские сборки Xerces в своих POM. На самом деле это не проблема, если у вас небольшое приложение и вы используете только Maven Central, но это быстро становится проблемой для корпоративного программного обеспечения, где Artifactory или Nexus проксирует несколько репозиториев (JBoss, Hibernate и т.д.):
Например, организация A может опубликовать 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 jar
является более низкой версией, чем A jar
, Maven не знает, что это один и тот же артефакт, поскольку у них разные groupId
. Таким образом, он не может выполнить разрешение конфликта, и оба jar
будут включены как разрешенные зависимости:
Classloader Hell
Как упоминалось выше, JRE поставляется с Xerces в JAXP RI. Хотя было бы неплохо пометить все зависимости Xerces Maven как <exclusion>
или как <provided>
, сторонний код, от которого вы зависите, может работать или не работать с версией, предоставленной в JAXP используемого вами JDK. Кроме того, у вас есть контейнеры Xerces, отправленные в ваш контейнер сервлетов для борьбы. Это оставляет вам несколько вариантов: удаляете ли вы версию сервлета и надеетесь, что ваш контейнер работает на версии JAXP? Лучше ли оставить версию сервлета и надеяться, что фреймворки ваших приложений будут работать на версии сервлета? Если одному или двум из неразрешенных конфликтов, описанных выше, удается проникнуть в ваш продукт (это легко случается в большой организации), вы быстро попадаете в ад загрузчика классов, задаваясь вопросом, какую версию Xerces выбирает загрузчик классов во время выполнения и действительно ли она выберет одну и ту же банку в Windows и Linux (вероятно, нет).
Решения?
Мы попытались пометить все зависимости Xerces Maven как <provided>
или как <exclusion>
, но это трудно реализовать (особенно в большой команде), учитывая, что у артефактов очень много псевдонимов (xml-apis
, xerces
, xercesImpl
, xmlParserAPIs
и т.д.). Кроме того, наши сторонние библиотеки libs/frameworks могут не работать на версии JAXP или версии, предоставляемой контейнером сервлета.
Как мы можем лучше всего решить эту проблему с Maven? Должны ли мы осуществлять такой детальный контроль над нашими зависимостями, а затем полагаться на многоуровневую загрузку классов? Есть ли способ глобально исключить все зависимости Xerces и заставить все наши фреймворки/библиотеки использовать версию JAXP?
ОБНОВЛЕНИЕ: Джошуа Спивак загрузил исправленную версию сценариев сборки Xerces в XERCESJ-1454, которая позволяет загружать их в Maven Central. Проголосуйте/посмотрите/внесите свой вклад в решение этой проблемы и дайте решить эту проблему раз и навсегда.