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.
źródło
Odpowiedzi:
Od 20 lutego 2013 r. W Maven Central dostępnych jest 2.11.0 plików JAR (i źródłowe pliki JAR !) Xerces! Zobacz Xerces w Maven Central . Zastanawiam się, dlaczego nie rozwiązali https://issues.apache.org/jira/browse/XERCESJ-1454 ...
Użyłem:
i wszystkie zależności rozwiązały się dobrze - nawet poprawnie
xml-apis-1.4.01
!I co najważniejsze (a co nie było oczywiste w przeszłości) - JAR w Maven Central jest tym samym JAR, co w oficjalnej
Xerces-J-bin.2.11.0.zip
dystrybucji .Nie mogłem jednak znaleźć
xml-schema-1.1-beta
wersji - nie może to byćclassifier
wersja Maven z powodu dodatkowych zależności.źródło
xml-apis:xml-apis:1.4.01
jest nowszy niżxml-apis:xml-apis:2.0.2
? patrz search.maven.org/…Szczerze mówiąc, prawie wszystko, co mamy napotkał działa dobrze w / w wersji JAXP, więc my zawsze wyłączyć
xml-apis
ixercesImpl
.źródło
java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal
w czasie wykonywania.Możesz użyć wtyczki maven enforcer z zakazaną regułą zależności. Pozwoliłoby to zablokować wszystkie aliasy, których nie chcesz, i zezwolić tylko na ten, którego chcesz. Reguły te zawiodą kompilację maven twojego projektu, gdy zostaną naruszone. Ponadto, jeśli ta reguła dotyczy wszystkich projektów w przedsiębiorstwie, można umieścić konfigurację wtyczki w korporacyjnym pom-pom.
widzieć:
źródło
Wiem, że to nie odpowiada dokładnie na pytanie, ale dla ppl przychodzących z Google, które akurat używają Gradle do zarządzania zależnościami:
Udało mi się pozbyć wszystkich problemów Xerces / Java8 z Gradle w następujący sposób:
źródło
Sądzę, że musisz odpowiedzieć na jedno pytanie:
Czy istnieje xerces * .jar, z którym wszystko w twojej aplikacji może żyć?
Jeśli nie, jesteś po prostu wkręcony i musiałbyś użyć czegoś takiego jak OSGI, co pozwala na jednoczesne ładowanie różnych wersji biblioteki. Ostrzegamy, że w zasadzie zastępuje problemy z wersją jar problemami z modułem ładującym klasy ...
Jeśli istnieje taka wersja, możesz sprawić, że repozytorium zwróci tę wersję dla wszystkich rodzajów zależności. Jest to brzydki hack i skończyłby się z tą samą implementacją xerces w ścieżce klasy wiele razy, ale lepiej niż posiadanie wielu różnych wersji xerces.
Możesz wykluczyć każdą zależność od kserokopii i dodać ją do wersji, której chcesz użyć.
Zastanawiam się, czy możesz napisać strategię rozwiązywania wersji jako wtyczkę do maven. To prawdopodobnie najpiękniejsze rozwiązanie, ale jeśli w ogóle wykonalne wymaga pewnych badań i kodowania.
W przypadku wersji zawartej w środowisku wykonawczym musisz upewnić się, że zostanie ona usunięta ze ścieżki klas aplikacji lub słoiki aplikacji zostaną wzięte pod uwagę jako pierwsze podczas ładowania klas, zanim folder lib serwera zostanie wzięty pod uwagę.
Podsumowując: bałagan i to się nie zmieni.
źródło
Jest jeszcze jedna opcja, która nie została tutaj zbadana: zadeklarowanie zależności Xerces w Maven jako opcjonalne :
Zasadniczo polega to na zmuszeniu wszystkich osób zależnych do zadeklarowania swojej wersji Xerces, w przeciwnym razie ich projekt nie zostanie skompilowany. Jeśli chcą zastąpić tę zależność, mogą to zrobić, ale będą właścicielami potencjalnego problemu.
Stwarza to silną zachętę dla projektów końcowych do:
Nie wszyscy programiści śledzą nowo wprowadzone zależności (np. Z
mvn dependency:tree
). Takie podejście natychmiast zwróci ich uwagę.Działa całkiem dobrze w naszej organizacji. Przed jego wprowadzeniem mieszkaliśmy w tym samym piekle, które opisuje OP.
źródło
Każdy projekt maven powinien zakończyć się w zależności od kserokopii, prawdopodobnie tak naprawdę nie jest. Interfejsy API XML i Impl są częścią Java od 1.4. Nie ma potrzeby polegać na xerces lub interfejsach API XML, to tak, jakby powiedzieć, że zależy się od Java lub Swing. To jest dorozumiane.
Gdybym był szefem repozytorium maven, napisałbym skrypt, aby rekurencyjnie usuwać zależności xerces i napisał mi przeczytaną informację, że to repo wymaga Java 1.4.
Wszystko, co faktycznie psuje się, ponieważ odwołuje się do Xerces bezpośrednio za pośrednictwem importu org.apache, wymaga poprawki kodu, aby doprowadzić ją do poziomu Java 1.4 (i zrobiło to od 2002 r.) Lub rozwiązania na poziomie JVM poprzez zatwierdzone biblioteki lib, nie w maven.
źródło
Najpierw powinieneś debugować, aby zidentyfikować swój poziom piekła XML. Moim zdaniem pierwszym krokiem jest dodanie
do wiersza poleceń. Jeśli to zadziała, zacznij wykluczać biblioteki. Jeśli nie, dodaj
do wiersza poleceń.
źródło
Pomogłoby, oprócz wykluczenia, zależności modułowe.
Z jednym płaskim ładowaniem klas (samodzielna aplikacja) lub półhierarchicznym (JBoss AS / EAP 5.x) był to problem.
Ale dzięki modułowym frameworkom, takim jak OSGi i JBoss Modules , nie jest to już tak bardzo bolesne. Biblioteki mogą korzystać z dowolnej biblioteki niezależnie.
Oczywiście nadal najlepiej jest trzymać się tylko jednej implementacji i wersji, ale jeśli nie ma innego sposobu (użycie dodatkowych funkcji z większej liczby bibliotek), modularyzacja może cię uratować.
Dobrym przykładem działających modułów JBoss jest oczywiście JBoss AS 7 / EAP 6 / WildFly 8 , dla którego został pierwotnie opracowany.
Przykładowa definicja modułu:
W porównaniu z OSGi, moduły JBoss są prostsze i szybsze. Brakuje niektórych funkcji, ale wystarcza dla większości projektów, które (głównie) są kontrolowane przez jednego dostawcę i umożliwiają oszałamiające szybkie uruchamianie (ze względu na rozwiązywanie równoległych zależności).
Zauważ, że trwają prace nad modularyzacją Java 8 , ale AFAIK ma przede wszystkim na celu modularyzację samego środowiska JRE, nie jestem pewien, czy będzie on miał zastosowanie do aplikacji.
źródło
Najwyraźniej
xerces:xml-apis:1.4.01
nie jest już w centrach maven, co jednak jestxerces:xercesImpl:2.11.0
odniesieniem.To działa dla mnie:
źródło
Mój przyjacielu, to bardzo proste, oto przykład:
A jeśli chcesz sprawdzić w terminalu (w tym przykładzie konsolę Windows), czy twoje drzewo maven nie ma problemów:
źródło