No meu escritório, a simples menção da palavra Xerces é suficiente para incitar a raiva assassina dos desenvolvedores. Uma rápida olhada nas outras questões do Xerces no SO parece indicar que quase todos os usuários do Maven estão "tocados" por esse problema em algum momento. Infelizmente, entender o problema requer um pouco de conhecimento sobre a história do Xerces ...
História
O Xerces é o analisador XML mais utilizado no ecossistema Java. Quase todas as bibliotecas ou estruturas escritas em Java usam o Xerces em alguma capacidade (transitivamente, se não diretamente).
Os frascos Xerces incluídos nos binários oficiais são, até hoje, sem versão. Por exemplo, o jar de implementação do Xerces 2.11.0 é nomeado
xercesImpl.jar
e nãoxercesImpl-2.11.0.jar
.A equipe do Xerces não usa o Maven , o que significa que eles não enviam um release oficial para o Maven Central .
O Xerces costumava ser lançado como um único jar (
xerces.jar
), mas era dividido em dois jars, um contendo a API (xml-apis.jar
) e outro contendo as implementações dessas APIs (xercesImpl.jar
). Muitos POMs Maven mais antigos ainda declaram dependênciaxerces.jar
. Em algum momento no passado, o Xerces também foi lançado comoxmlParserAPIs.jar
, do qual alguns POMs mais antigos também dependem.As versões atribuídas aos jars xml-apis e xercesImpl por aqueles que implantam seus jars nos repositórios Maven geralmente são diferentes. Por exemplo, o xml-apis pode receber a versão 1.3.03 e o xercesImpl a versão 2.8.0, mesmo que ambos sejam do Xerces 2.8.0. Isso ocorre porque as pessoas frequentemente etiquetam o jar xml-apis com a versão das especificações implementadas. Existe uma discriminação muito boa, mas incompleta, aqui .
Para complicar, Xerces é o analisador XML usado na implementação de referência da API Java para XML Processing (JAXP), incluída no JRE. As classes de implementação são reembaladas no
com.sun.*
espaço para nome, o que torna perigoso acessá-las diretamente, pois elas podem não estar disponíveis em alguns JREs. No entanto, nem toda a funcionalidade do Xerces é exposta pelas APIsjava.*
ejavax.*
; por exemplo, não há API que exponha a serialização do Xerces.Além da confusão, quase todos os contêineres de servlets (JBoss, Jetty, Glassfish, Tomcat etc.) são enviados com o Xerces em uma ou mais de suas
/lib
pastas.
Problemas
Resolução de Conflitos
Por alguns - ou talvez por todos os motivos acima, muitas organizações publicam e consomem construções personalizadas do Xerces em seus POMs. Isso não é realmente um problema se você tiver um aplicativo pequeno e estiver usando apenas o Maven Central, mas rapidamente se tornará um problema para o software corporativo em que o Artifactory ou o Nexus estão fazendo proxy de vários repositórios (JBoss, Hibernate etc.):
Por exemplo, a organização A pode publicar xml-apis
como:
<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>
Enquanto isso, a organização B pode publicar o mesmo jar
que:
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
Embora B jar
seja uma versão inferior a A jar
, Maven não sabe que eles são o mesmo artefato porque possuem groupId
s diferentes
. Portanto, ele não pode executar a resolução de conflitos e os dois
jar
s serão incluídos como dependências resolvidas:
Classloader Hell
Como mencionado acima, o JRE é enviado com o Xerces no JAXP RI. Embora seja bom marcar todas as dependências do Xerces Maven como <exclusion>
s ou como<provided>
, o código de terceiros do qual você depende pode ou não funcionar com a versão fornecida no JAXP do JDK que você está usando. Além disso, você tem os frascos Xerces enviados no contêiner do servlet para lidar. Isso deixa você com várias opções: Você exclui a versão do servlet e espera que seu contêiner seja executado na versão JAXP? É melhor deixar a versão do servlet e esperar que suas estruturas de aplicativos sejam executadas na versão do servlet? Se um ou dois dos conflitos não resolvidos descritos acima conseguirem entrar no seu produto (fácil de acontecer em uma organização grande), você se encontrará rapidamente no inferno do carregador de classes, imaginando qual versão do Xerces o carregador de classe está escolhendo no tempo de execução e se é ou não vai escolher o mesmo jar no Windows e Linux (provavelmente não).
Soluções?
Nós tentamos marcar todas as dependências Xerces Maven como <provided>
ou como <exclusion>
, mas isso é difícil de aplicar (especialmente com uma grande equipe) dado que os artefatos têm tantos aliases ( xml-apis
, xerces
, xercesImpl
, xmlParserAPIs
, etc.). Além disso, nossas bibliotecas / estruturas de terceiros podem não ser executadas na versão JAXP ou na versão fornecida por um contêiner de servlet.
Como podemos resolver melhor esse problema com o Maven? Temos que exercer um controle tão refinado sobre nossas dependências e depois confiar no carregamento de classes em camadas? Existe alguma maneira de excluir globalmente todas as dependências do Xerces e forçar todas as nossas estruturas / bibliotecas a usar a versão JAXP?
ATUALIZAÇÃO : Joshua Spiewak enviou uma versão corrigida dos scripts de construção do Xerces para o XERCESJ-1454 que permite o upload para o Maven Central. Vote / assista / contribua para esse problema e vamos corrigir esse problema de uma vez por todas.