Nel mio ufficio, la sola menzione della parola Xerces è sufficiente per incitare alla rabbia omicida degli sviluppatori. Una rapida occhiata alle altre domande di Xerces su SO sembra indicare che quasi tutti gli utenti Maven sono "toccati" da questo problema ad un certo punto. Sfortunatamente, comprendere il problema richiede un po 'di conoscenza sulla storia di Xerces ...
Storia
Xerces è il parser XML più utilizzato nell'ecosistema Java. Quasi tutte le librerie o framework scritti in Java utilizzano Xerces in qualche modo (transitivamente, se non direttamente).
I barattoli Xerces inclusi nei binari ufficiali non sono, fino ad oggi, versioni. Ad esempio, il vaso di implementazione di Xerces 2.11.0 è denominato
xercesImpl.jar
e nonxercesImpl-2.11.0.jar
.Il team di Xerces non utilizza Maven , il che significa che non caricano una versione ufficiale su Maven Central .
Xerces veniva rilasciato come un singolo jar (
xerces.jar
), ma era diviso in due vasetti, uno contenente l'API (xml-apis.jar
) e uno contenente le implementazioni di tali API (xercesImpl.jar
). Molti vecchi POM Maven dichiarano ancora una dipendenzaxerces.jar
. Ad un certo punto in passato, è stato rilasciato anche XercesxmlParserAPIs.jar
, da cui dipendono anche alcuni vecchi POM.Le versioni assegnate ai vasetti xml-apis e xercesImpl da parte di coloro che distribuiscono i loro vasetti nei repository Maven sono spesso diverse. Ad esempio, xml-apis potrebbe avere la versione 1.3.03 e xercesImpl potrebbe avere la versione 2.8.0, anche se entrambi provengono da Xerces 2.8.0. Questo perché le persone spesso taggano il vaso xml-apis con la versione delle specifiche che implementa. C'è una ripartizione molto bella, ma incompleta di questo qui .
A complicare le cose, Xerces è il parser XML utilizzato nell'implementazione di riferimento dell'API Java per l'elaborazione XML (JAXP), incluso in JRE. Le classi di implementazione sono riconfezionate nello
com.sun.*
spazio dei nomi, il che rende pericoloso accedervi direttamente, poiché potrebbero non essere disponibili in alcuni JRE. Tuttavia, non tutte le funzionalità di Xerces sono esposte tramite le APIjava.*
ejavax.*
; ad esempio, non esiste un'API che espone la serializzazione di Xerces.Aggiungendo al disordine confuso, quasi tutti i contenitori servlet (JBoss, Jetty, Glassfish, Tomcat, ecc.), Vengono spediti con Xerces in una o più delle loro
/lib
cartelle.
I problemi
Risoluzione del conflitto
Per alcuni - o forse tutti - dei motivi sopra, molte organizzazioni pubblicano e consumano build personalizzate di Xerces nei loro POM. Questo non è davvero un problema se si dispone di una piccola applicazione e si utilizza solo Maven Central, ma diventa rapidamente un problema per il software aziendale in cui Artifactory o Nexus sta eseguendo il proxy di più repository (JBoss, Hibernate, ecc.):
Ad esempio, l'organizzazione A potrebbe pubblicare xml-apis
come:
<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>
Nel frattempo, l'organizzazione B potrebbe pubblicare lo stesso jar
di:
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
Sebbene B jar
sia una versione inferiore di A jar
, Maven non sa che sono lo stesso artefatto perché hanno groupId
s diversi
. Pertanto, non è in grado di eseguire la risoluzione dei conflitti ed entrambi
jar
saranno inclusi come dipendenze risolte:
Classloader Hell
Come accennato in precedenza, il JRE viene fornito con Xerces nel RI JAXP. Mentre sarebbe bello contrassegnare tutte le dipendenze di Xerces Maven come <exclusion>
s o as<provided>
, il codice di terze parti da cui dipendi potrebbe non funzionare con la versione fornita in JAXP del JDK che stai utilizzando. Inoltre, hai i barattoli Xerces spediti nel tuo contenitore servlet con cui lottare. Questo ti lascia con una serie di scelte: elimini la versione servlet e speri che il tuo contenitore funzioni sulla versione JAXP? È meglio lasciare la versione servlet e sperare che i framework delle applicazioni vengano eseguiti sulla versione servlet? Se uno o due dei conflitti non risolti sopra descritti riescono a scivolare nel tuo prodotto (facile accadere in una grande organizzazione), ti ritrovi rapidamente all'inferno del classloader, chiedendoti quale versione di Xerces il classloader sta selezionando in fase di esecuzione e se no sceglierà lo stesso vaso in Windows e Linux (probabilmente no).
Soluzioni?
Abbiamo provato la marcatura di tutte le dipendenze Xerces Maven come <provided>
o come <exclusion>
, ma questo è difficile da applicare (in particolare con una grande squadra), dato che i manufatti hanno tanti pseudonimi ( xml-apis
, xerces
, xercesImpl
, xmlParserAPIs
, ecc). Inoltre, le nostre librerie / librerie di terze parti potrebbero non essere eseguite sulla versione JAXP o sulla versione fornita da un contenitore servlet.
Come possiamo affrontare al meglio questo problema con Maven? Dobbiamo esercitare un controllo così preciso sulle nostre dipendenze e quindi fare affidamento sul caricamento di classe a più livelli? C'è un modo per escludere globalmente tutte le dipendenze di Xerces e forzare tutti i nostri framework / librerie a usare la versione JAXP?
AGGIORNAMENTO : Joshua Spiewak ha caricato una versione patchata degli script di build di Xerces su XERCESJ-1454 che consente il caricamento su Maven Central. Vota / guarda / contribuisci a questo problema e risolviamo il problema una volta per tutte.