Работа с «Xerces hell» в Java / Maven?

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

история

  • Xerces является наиболее широко используемым парсером XML в экосистеме Java. Почти каждая библиотека или структура, написанная на Java, использует Xerces в некоторой емкости (транзитно, если не напрямую).

  • Банки Xerces, включенные в официальные бинарные файлы , по сей день не версируются. Например, баннер реализации Xerces 2.11.0 называется xercesImpl.jar а не xercesImpl-2.11.0.jar .

  • Команда Xerces не использует Maven , а это означает, что они не загружают официальный релиз в Maven Central .

  • Раньше Xerces выпускался как единый xerces.jar ( xerces.jar ), но был разделен на две банки, один из которых содержал API ( xml-apis.jar ) и один, содержащий реализации этих API ( xercesImpl.jar ). Многие более старые Maven POM все еще заявляют о зависимости от xerces.jar . В какой-то момент в прошлом Xerces также был выпущен как xmlParserAPIs.jar , от которого также зависят некоторые более старые POM.

  • Версии, назначенные банкам xml-apis и xercesImpl теми, кто развертывает свои банки в репозиториях Maven, часто различны. Например, xml-apis может быть предоставлена ​​версия 1.3.03, а xercesImpl может быть предоставлена ​​версия 2.8.0, хотя оба из Xerces 2.8.0. Это происходит потому, что люди часто помещают jml-apis jar с версией спецификаций, которые она реализует. Здесь очень приятная, но неполная разбивка.

  • Чтобы усложнить ситуацию, Xerces является парсером XML, используемым в эталонной реализации Java API для обработки XML (JAXP), включенной в JRE. Классы реализации переупаковываются в пространстве имен com.sun.* , Что делает опасным доступ к ним напрямую, поскольку они могут быть недоступны в некоторых JRE. Однако не все функциональные возможности Xerces доступны через API java.* И javax.* ; например, нет API, который предоставляет серизацию Xerces.

  • Добавляя к запутанному беспорядку, почти все контейнеры сервлетов (JBoss, Jetty, Glassfish, Tomcat и т. Д.) Поставляются с Xerces в одной или нескольких папках с их /lib .

Проблемы

Решение конфликта

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

xml-apis, проксированный Artifactory

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

org.apache.xerces
xml-apis
2.9.1

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

xml-apis
xml-apis
1.3.04

Хотя банда B является более низкой версией, чем jar A, Maven не знает, что они являются одним и тем же артефактом, потому что у них разные groupId . Таким образом, он не может выполнять разрешение конфликтов, и оба jar s будут включены как разрешенные зависимости:

разрешенные зависимости с несколькими xml-apis

Классный ад

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

Решения?

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

Как мы можем лучше всего решить эту проблему с Maven? Нужно ли нам осуществлять такой мелкомасштабный контроль над нашими зависимостями, а затем полагаться на многоуровневую загрузку classов? Есть ли способ глобально исключить все зависимости Xerces и заставить все наши фреймворки / библиотеки использовать версию JAXP?


UPDATE : Joshua Spiewak загрузил исправленную версию скриптов сборки Xerces в XERCESJ-1454, что позволяет загружать в Maven Central. Голосовать / смотреть / вносить свой вклад в эту проблему, и давайте исправим эту проблему раз и навсегда.

    С 20 февраля 2013 года в Maven Central есть 2.11.0 JAR (и исходные JAR!) Ксероксов! См. Xerces в Maven Central . Интересно, почему они не решили https://issues.apache.org/jira/browse/XERCESJ-1454

    Я использовал:

      xerces xercesImpl 2.11.0  

    и все зависимости разрешили мелкие – даже правильные xml-apis-1.4.01 !

    И что самое главное (и то, что не было очевидно в прошлом) – JAR в Maven Central – это тот же JAR, что и в официальном дистрибутиве Xerces-J-bin.2.11.0.zip .

    Однако я не мог найти версию xml-schema-1.1-beta – она ​​не может быть версией Maven- classifier из-за дополнительных зависимостей.

    Честно говоря, почти все, с чем мы столкнулись, отлично работает с версией JAXP, поэтому мы всегда исключаем xml-apis и xercesImpl .

    Вы можете использовать плагин maven securityer с запрещенным правилом зависимости. Это позволит вам запретить все псевдонимы, которые вы не хотите, и разрешить только тот, который вам нужен. Эти правила будут нарушать работу maven вашего проекта при нарушении. Кроме того, если это правило применяется ко всем проектам на предприятии, вы можете поместить конфигурацию плагина в корпоративную родительскую помню.

    видеть:

    Я знаю, что это точно не отвечает на вопрос, но для входа в Google из Google, который использует Gradle для управления зависимостями:

    Мне удалось избавиться от всех проблем xerces / Java8 с Gradle следующим образом:

     configurations { all*.exclude group: 'xml-apis' all*.exclude group: 'xerces' } 

    Я думаю, есть один вопрос, на который вам нужно ответить:

    Существует ли xerces * .jar, с которым может работать все в вашем приложении?

    Если нет, вы в основном ввернуты и должны использовать что-то вроде OSGI, которое позволяет одновременно загружать разные версии библиотеки. Будьте предупреждены, что он в основном заменяет проблемы с jar-версией проблемами с загрузкой classов …

    Если такая версия существует, вы можете заставить ваш repository возвратить эту версию для всех видов зависимостей. Это уродливый взломать и в конечном итоге приведет к той же реализации xerces в вашем пути к classам несколько раз, но лучше, чем наличие нескольких разных версий xerces.

    Вы можете исключить каждую зависимость от ксерок и добавить ее в версию, которую хотите использовать.

    Интересно, можете ли вы написать какую-то страtagsю разрешения версий в качестве плагина для maven. Это, вероятно, самое приятное решение, но если вообще возможно, потребуются некоторые исследования и кодирование.

    Для версии, содержащейся в вашей среде выполнения, вам нужно будет убедиться, что она либо удаляется из пути к classу приложений, либо банки приложений считаются первыми для загрузки classов до того, как будет рассмотрена папка lib сервера.

    Поэтому, чтобы обернуть это: это беспорядок, и это не изменится.

    Существует еще один вариант, который не был изучен здесь: объявление зависимостей Xerces в Maven как необязательное :

      xerces xercesImpl ... true  

    В основном это означает заставить всех иждивенцев объявить свою версию Xerces или их проект не будет компилироваться. Если они хотят переопределить эту зависимость, они могут это сделать, но тогда у них будет потенциальная проблема.

    Это создает сильный стимул для последующих проектов:

    • Примите активное решение. Они идут с той же версией Xerces или используют что-то еще?
    • Собственно проверяйте их parsing (например, через модульное тестирование) и загрузку classов, а также не загромождать их путь к classам.

    Не все разработчики отслеживают недавно введенные зависимости (например, с mvn dependency:tree ). Этот подход сразу же привлечет внимание к этому вопросу.

    Это хорошо работает в нашей организации. До его введения мы жили в том же ад, о котором описывает ОП.

    Сначала вы должны отлаживать, чтобы определить уровень адского XML-ада. На мой взгляд, первым шагом является добавление

     -Djavax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl -Djavax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl -Djavax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl 

    в командной строке. Если это сработает, начните исключать библиотеки. Если нет, добавьте

     -Djaxp.debug=1 

    в командной строке.

    Что помогло бы, за исключением исключения, модульные зависимости.

    С одной плоской загрузкой classов (автономное приложение) или полу-иерархическим (JBoss AS / EAP 5.x) это было проблемой.

    Но с модульными структурами, такими как OSGi и JBoss Modules , это уже не столько боль. Библиотеки могут использовать любую библиотеку, которую они хотят, независимо.

    Конечно, по-прежнему наиболее рекомендуется придерживаться только одной версии и версии, но если нет другого пути (используя дополнительные функции из большего количества библиотек), то модуляция может спасти вас.

    Хорошим примером JBoss Modules в действии, естественно, является JBoss AS 7 / EAP 6 / WildFly 8 , для которого он был разработан в первую очередь.

    Пример определения модуля:

                       

    По сравнению с OSGi, модули JBoss проще и быстрее. Несмотря на отсутствие определенных функций, этого достаточно для большинства проектов, которые (в основном) находятся под контролем одного поставщика и позволяют ошеломляющую быструю загрузку (из-за разрешения парализованных зависимостей).

    Обратите внимание на то, что для Java 8 прилагаются усилия по модулизации , но AFAIK, в первую очередь, для модуляции самой JRE, не уверен, будет ли она применима к приложениям.

    Каждый проект maven должен останавливаться в зависимости от ксерок, но, вероятно, это не так. XML API и Impl были частью Java с 1.4. Не нужно зависеть от xerces или XML API, это похоже на то, что вы зависите от Java или Swing. Это неявно.

    Если бы я был боссом maven repo, я бы написал сценарий для рекурсивного удаления зависимостей xerces и записи прочитанного мной, в котором говорится, что для этого репо требуется Java 1.4.

    Все, что действительно ломается, потому что оно ссылается на Xerces напрямую через импорт org.apache, требуется исправление кода, чтобы довести его до уровня Java 1.4 (и сделано с 2002 года) или решение на уровне JVM через поддерживаемые библиотеки, а не в maven.

    По-видимому, xerces:xml-apis:1.4.01 больше не находится в центре maven, но, тем не менее, имеет значение xerces:xercesImpl:2.11.0 .

    Это работает для меня:

      xerces xercesImpl 2.11.0   xerces xml-apis     xml-apis xml-apis 1.4.01  

    Мой друг очень прост, вот пример:

      xalan xalan 2.7.2 ${my-scope}   xml-apis xml-apis    

    И если вы хотите проверить терминал (консоль Windows для этого примера), что ваше дерево maven не имеет проблем:

     mvn dependency:tree -Dverbose | grep --color=always '(.* conflict\|^' | less -r 
    Давайте будем гением компьютера.