В моем офисе простого упоминания слова 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
. В какой-то момент в прошлом был также выпущен XercesxmlParserAPIs.jar
, от которого также зависят некоторые старые POM.Версии, назначаемые банкам xml-apis и xercesImpl теми, кто развертывает свои банки в репозиториях Maven, часто отличаются. Например, xml-apis может иметь версию 1.3.03, а xercesImpl - версию 2.8.0, даже если обе версии Xerces 2.8.0. Это связано с тем, что люди часто помечают банку xml-apis версией спецификаций, которые он реализует. Существует очень хороший, но неполный пробой этого здесь .
Чтобы усложнить ситуацию, Xerces - это анализатор XML, используемый в эталонной реализации Java API для обработки XML (JAXP), включенной в JRE. Классы реализации переупаковываются в
com.sun.*
пространстве имен, что делает опасным прямой доступ к ним, поскольку они могут быть недоступны в некоторых JRE. Однако не все функциональные возможности Xerces предоставляются через APIjava.*
иjavax.*
API; например, нет API, который предоставляет сериализацию Xerces.Помимо этого запутанного беспорядка, почти все контейнеры сервлетов (JBoss, Jetty, Glassfish, Tomcat и т. Д.) Поставляются с Xerces в одной или нескольких
/lib
папках.
Проблемы
Решение конфликта
По некоторым - или, возможно, по всем - причинам, изложенным выше, многие организации публикуют и используют пользовательские сборки Xerces в своих POM. На самом деле это не проблема, если у вас небольшое приложение и вы используете только Maven Central, но это быстро становится проблемой для корпоративного программного обеспечения, где Artifactory или Nexus проксирует несколько репозиториев (JBoss, Hibernate и т. Д.):
Например, организация А может опубликовать 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
s. Таким образом, он не может выполнять разрешение конфликтов, и оба
jar
будут включены как разрешенные зависимости:
Classloader Hell
Как упоминалось выше, JRE поставляется с Xerces в JAXP RI. Хотя было бы неплохо отметить все зависимости Xerces Maven как <exclusion>
s или как<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. Проголосуйте / посмотрите / внесите свой вклад в эту проблему, и давайте решим эту проблему раз и навсегда.