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.
fonte
Respostas:
Existem 2.11.0 JARs (e JARs de origem!) Do Xerces no Maven Central desde 20 de fevereiro de 2013! Veja Xerces no Maven Central . Gostaria de saber por que eles não resolveram https://issues.apache.org/jira/browse/XERCESJ-1454 ...
Eu usei:
e todas as dependências foram bem resolvidas - até adequadas
xml-apis-1.4.01
!E o que é mais importante (e o que não era óbvio no passado) - o JAR no Maven Central é o mesmo JAR da
Xerces-J-bin.2.11.0.zip
distribuição oficial .No entanto, não consegui encontrar a
xml-schema-1.1-beta
versão - não pode ser umaclassifier
versão do Maven por causa de dependências adicionais.fonte
xml-apis:xml-apis:1.4.01
seja mais recente quexml-apis:xml-apis:2.0.2
?? veja search.maven.org/…Francamente, praticamente tudo que nós encontramos funciona muito bem w / a versão JAXP, então nós sempre excluir
xml-apis
exercesImpl
.fonte
java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal
em tempo de execução.Você pode usar o plug-in maven enforcer com a regra de dependência banida. Isso permitiria banir todos os aliases que você não deseja e permitir apenas o que você deseja. Essas regras falharão na compilação do seu projeto quando violadas. Além disso, se esta regra se aplicar a todos os projetos em uma empresa, você poderá colocar a configuração do plug-in em um pom pai corporativo.
Vejo:
fonte
Eu sei que isso não responde à pergunta exatamente, mas para pessoas vindas do google que usam Gradle para o gerenciamento de dependências:
Eu consegui me livrar de todos os problemas do xerces / Java8 com o Gradle assim:
fonte
Eu acho que há uma pergunta que você precisa responder:
Existe um xerces * .jar com o qual tudo em seu aplicativo pode conviver?
Caso contrário, você está basicamente ferrado e precisaria usar algo como OSGI, que permite que você tenha versões diferentes de uma biblioteca carregadas ao mesmo tempo. Esteja avisado de que basicamente substitui os problemas da versão jar pelos problemas do carregador de classe ...
Se existir essa versão, você poderá fazer com que seu repositório retorne essa versão para todos os tipos de dependências. É um truque feio e acabaria com a mesma implementação de xerces em seu caminho de classe várias vezes, mas melhor do que ter várias versões diferentes de xerces.
Você pode excluir todas as dependências do xerces e adicionar uma à versão que deseja usar.
Gostaria de saber se você pode escrever algum tipo de estratégia de resolução de versão como um plugin para o maven. Essa provavelmente seria a melhor solução, mas, se possível, precisa de alguma pesquisa e codificação.
Para a versão contida no seu ambiente de tempo de execução, você deve ter certeza de que ele é removido do caminho de classe do aplicativo ou se os jars do aplicativo são considerados primeiro para carregamento de classe antes que a pasta lib do servidor seja considerada.
Então, para encerrar: é uma bagunça e isso não vai mudar.
fonte
Há outra opção que não foi explorada aqui: declarar dependências do Xerces no Maven como opcional :
Basicamente, o que isso faz é forçar todos os dependentes a declarar sua versão do Xerces ou seu projeto não será compilado. Se eles desejam substituir essa dependência, podem fazê-lo, mas serão os donos do problema em potencial.
Isso cria um forte incentivo para os projetos downstream:
Nem todos os desenvolvedores acompanham as novas dependências introduzidas (por exemplo, com
mvn dependency:tree
). Essa abordagem trará imediatamente o assunto à atenção deles.Funciona muito bem em nossa organização. Antes de sua introdução, vivíamos no mesmo inferno que o OP está descrevendo.
fonte
Todo projeto de maven deve parar de depender de xerces, provavelmente não. APIs XML e um Impl fazem parte do Java desde a versão 1.4. Não há necessidade de depender de xerces ou APIs XML, é como dizer que você depende de Java ou Swing. Isso está implícito.
Se eu fosse o chefe de um repo maven, escreveria um script para remover recursivamente as dependências do xerces e escreveria uma leitura para mim dizendo que esse repo requer o Java 1.4.
Qualquer coisa que realmente quebre, porque faz referência ao Xerces diretamente por meio de importações do org.apache, precisa de uma correção de código para elevá-lo ao nível Java 1.4 (e já foi feito desde 2002) ou solução no nível da JVM por meio de bibliotecas endossadas, não em tom de mal-intencionado.
fonte
Você deve depurar primeiro, para ajudar a identificar seu nível de inferno XML. Na minha opinião, o primeiro passo é adicionar
para a linha de comando. Se isso funcionar, comece a excluir as bibliotecas. Caso contrário, adicione
para a linha de comando.
fonte
O que ajudaria, exceto a exclusão, são dependências modulares.
Com um carregamento de classe simples (aplicativo independente) ou semi-hierárquico (JBoss AS / EAP 5.x), isso era um problema.
Mas com estruturas modulares como OSGi e JBoss Modules , isso não é mais tão trabalhoso. As bibliotecas podem usar a biblioteca que desejarem, independentemente.
Obviamente, ainda é mais recomendável manter apenas uma única implementação e versão, mas se não houver outra maneira (usando recursos extras de mais bibliotecas), a modularização poderá salvá-lo.
Um bom exemplo de JBoss Modules em ação é, naturalmente, o JBoss AS 7 / EAP 6 / WildFly 8 , para o qual foi desenvolvido principalmente.
Exemplo de definição de módulo:
Em comparação com o OSGi, o JBoss Modules é mais simples e rápido. Embora falte a certos recursos, é suficiente para a maioria dos projetos que estão (principalmente) sob controle de um fornecedor e permite uma inicialização rápida impressionante (devido à resolução de dependências paralelizadas).
Observe que há um esforço de modularização em andamento no Java 8 , mas o AFAIK é principalmente para modularizar o próprio JRE, sem ter certeza se ele será aplicável aos aplicativos.
fonte
Aparentemente,
xerces:xml-apis:1.4.01
não está mais no maven central, que é, no entanto, o que fazxerces:xercesImpl:2.11.0
referência.Isso funciona para mim:
fonte
Meu amigo, isso é muito simples, aqui está um exemplo:
E se você quiser verificar no terminal (console do Windows para este exemplo) que sua árvore maven não tem problemas:
fonte