W moim biurze sama wzmianka o słowie Xerces wystarczy, aby wywołać morderczą furię ze strony deweloperów. Pobieżne spojrzenie na inne pytania Xerces dotyczące SO wydaje się wskazywać, że prawie wszyscy użytkownicy Maven są „dotknięci” tym problemem w pewnym momencie. Niestety zrozumienie problemu wymaga trochę wiedzy na temat historii Xerces ...
Historia
Xerces to najczęściej używany parser XML w ekosystemie Java. Prawie każda biblioteka lub środowisko napisane w Javie wykorzystuje Xerces w pewnym stopniu (przejściowo, jeśli nie bezpośrednio).
Słoiki Xerces zawarte w oficjalnych plikach binarnych nie są do tej pory wersjonowane. Na przykład jar implementacji Xerces 2.11.0 ma nazwę,
xercesImpl.jar
a nie nazwęxercesImpl-2.11.0.jar
.Zespół Xerces nie korzysta z Maven , co oznacza, że nie przesyłają oficjalnej wersji do Maven Central .
Xerces był kiedyś wydawany jako pojedynczy jar (
xerces.jar
), ale został podzielony na dwa słoiki, jeden zawierający API (xml-apis.jar
) i drugi zawierający implementacje tych API (xercesImpl.jar
). Wiele starszych POM Maven nadal deklaruje zależnośćxerces.jar
. W pewnym momencie w przeszłości wydano także Xerces asxmlParserAPIs.jar
, od którego zależą również niektóre starsze POM.Wersje przypisane do słoików xml-apis i xercesImpl przez tych, którzy wdrażają swoje słoiki w repozytoriach Maven, są często różne. Na przykład xml-apis może otrzymać wersję 1.3.03, a xercesImpl może otrzymać wersję 2.8.0, mimo że oba pochodzą z Xerces 2.8.0. Wynika to z faktu, że ludzie często oznaczają słoik xml-apis wersją specyfikacji, które implementuje. Jest bardzo ładny, ale niepełny podział ten tutaj .
Aby komplikować sprawy, Xerces to parser XML używany w referencyjnej implementacji Java API for XML Processing (JAXP), zawartej w JRE. Klasy implementacji są ponownie pakowane w
com.sun.*
przestrzeni nazw, co sprawia, że dostęp do nich jest niebezpieczny, ponieważ mogą nie być dostępne w niektórych środowiskach JRE. Jednak nie wszystkie funkcje Xerces są udostępniane za pośrednictwem interfejsów APIjava.*
ijavax.*
; na przykład nie ma interfejsu API, który ujawniałby serializację Xerces.Dodając do mylącego bałaganu, prawie wszystkie pojemniki serwletów (JBoss, Jetty, Glassfish, Tomcat itp.) Są dostarczane z Xerces w jednym lub kilku
/lib
folderach.
Problemy
Rozwiązanie konfliktu
Z niektórych - a może wszystkich - z powyższych powodów, wiele organizacji publikuje i konsumuje niestandardowe wersje Xerces w swoich POM. Nie jest to tak naprawdę problemem, jeśli masz małą aplikację i używasz tylko Maven Central, ale szybko staje się to problemem dla oprogramowania korporacyjnego, w którym Artifactory lub Nexus pośredniczy w wielu repozytoriach (JBoss, Hibernacja itp.):
Na przykład organizacja A może publikować xml-apis
jako:
<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>
Tymczasem organizacja B może opublikować to samo, jar
co:
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
Chociaż B's jar
jest niższą wersją niż A jar
, Maven nie wie, że są tym samym artefaktem, ponieważ mają różne
groupId
s. W związku z tym nie może wykonać rozwiązania konfliktu i oba
jar
zostaną uwzględnione jako rozwiązane zależności:
Classloader Hell
Jak wspomniano powyżej, środowisko JRE jest dostarczane z Xerces w JAXP RI. Przydałoby się zaznaczyć wszystkie zależności Xerces Maven jako <exclusion>
s lub as<provided>
, kod innej firmy, od którego zależy, może, ale nie musi, współpracować z wersją podaną w JAXP używanego JDK. Ponadto masz słoiki Xerces wysłane w pojemniku serwletu, z którymi możesz się zmagać. To pozostawia wiele możliwości: Czy usuwasz wersję serwletu i masz nadzieję, że Twój kontener działa w wersji JAXP? Czy lepiej opuścić wersję serwletu i mieć nadzieję, że ramy aplikacji będą działać w wersji serwletu? Jeśli jeden lub dwa z opisanych powyżej nierozwiązanych konfliktów zdołają wślizgnąć się do twojego produktu (łatwo zdarzyć się w dużej organizacji), szybko znajdujesz się w piekle Classloadera, zastanawiając się, którą wersję Xerces wybiera moduł ładujący w czasie wykonywania i czy nie wybierze ten sam słoik w systemie Windows i Linux (prawdopodobnie nie).
Rozwiązania?
Staraliśmy oznakowanie wszystkich zależności Xerces Maven jako <provided>
lub jako <exclusion>
, ale to jest trudne do wyegzekwowania (zwłaszcza z dużym zespołem), zważywszy, że artefakty mają tak wiele aliasów ( xml-apis
, xerces
, xercesImpl
, xmlParserAPIs
, itd.) Ponadto nasze biblioteki / frameworki innych firm mogą nie działać w wersji JAXP lub wersji dostarczanej przez kontener serwletu.
Jak najlepiej rozwiązać ten problem za pomocą Maven? Czy musimy sprawować tak drobiazgową kontrolę nad naszymi zależnościami, a następnie polegać na wielopoziomowym obciążeniu klas? Czy jest jakiś sposób, aby globalnie wykluczyć wszystkie zależności Xerces i zmusić wszystkie nasze frameworki / biblioteki do korzystania z wersji JAXP?
AKTUALIZACJA : Joshua Spiewak przesłał poprawioną wersję skryptów kompilacji Xerces do XERCESJ-1454, która pozwala na przesłanie do Maven Central. Głosuj / oglądaj / przyczyniaj się do tego problemu i naprawmy ten problem raz na zawsze.