Maven: como substituir a dependência adicionada por uma biblioteca

116

Aqui está meu problema genérico:

Meu projeto P depende de A, que depende de B, que depende de C, que depende da versão 1.0.1 de D.

Há um problema com a versão 1.0.1 de D e desejo forçar o uso de outro módulo. Não sei como declarar isso nos POMs do meu projeto, pois não adicionei uma dependência em D diretamente. É C que declarou dependência de D.

Importante: Neste caso, não apenas a versão é alterada, mas também o grupo e o artefato. Portanto, não é apenas uma questão de substituir a versão da dependência, mas sim de excluir um módulo e incluir outro.

No caso concreto, D é StAX cujo 1.0.1 tem um bug . De acordo com as notas no bug, "os problemas foram resolvidos substituindo o stax-api-1.0.1 (maven GroupId = stax) por stax-api-1.0-2 (maven GroupId = javax.xml.stream)" então eu estou tentando exatamente isso.

Assim, D = stax: stax-api: jar: 1.0.1 e C = org.apache.xmlbeans: xmlbeans: jar: 2.3.0

Estou usando o maven 2.0.9 caso seja importante.

Saída da dependência mvn: árvore "

mvn dependency:tree
[..snip..]
[INFO] +- org.apache.poi:poi-ooxml:jar:3.6:compile
[INFO] |  +- org.apache.poi:poi-ooxml-schemas:jar:3.6:compile
[INFO] |  |  +- org.apache.xmlbeans:xmlbeans:jar:2.3.0:compile
[INFO] |  |  |  \- stax:stax-api:jar:1.0.1:compile

No POM do meu projeto, tenho a seguinte dependência de "A":

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.6</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.6</version>
</dependency>

Desde já, obrigado.

wishihadabettername
fonte

Respostas:

101

Basta especificar a versão em seu pom atual. A versão especificada aqui substituirá a outra.

Forçando uma versão
Uma versão sempre será honrada se for declarada no POM atual com uma versão particular - no entanto, deve-se notar que isso também afetará outros poms downstream se depender do uso de dependências transitivas.


Recursos :

Colin Hebert
fonte
5
não está claro como posso especificar a versão, uma vez que não declaro uma dependência de D. Além disso, o primeiro link que você forneceu tem "Este documento descreve o resto dos requisitos para gerenciamento de dependência que ainda NÃO foram implementados para Maven 2.0, especialmente com relação às dependências transitivas. " no topo.
wishihadabettername
@wishihadabettername, Como disse no outro documento: "Você poderia adicionar explicitamente uma dependência a D 2.0 em A para forçar o uso de D 2.0"
Colin Hebert
1
Na verdade, você duplica a mesma entrada <dependency> em seu próprio pom. Em sua dependência, especifique uma <versão> que você deseja. Isso substituirá qualquer versão usada por dependências "mais profundas".
Keith Tyler
27

Como alternativa, você pode simplesmente excluir a dependência que não deseja. STAX está incluído no JDK 1.6, portanto, se você estiver usando o 1.6, pode simplesmente excluí-lo completamente.

Meu exemplo abaixo é um pouco errado para você - você só precisa de uma das duas exclusões, mas não tenho certeza de qual delas. Existem outras versões de Stax flutuando, no meu exemplo abaixo, eu estava importando A, que importou B, que importou C & D, em que cada um (por meio de dependências ainda mais transitivas) importou versões diferentes de Stax. Portanto, em minha dependência de 'A', excluí as duas versões do Stax.

<dependency>
  <groupId>a.group</groupId>
  <artifactId>a.artifact</artifactId>
  <version>a.version</version>
  <exclusions>
    <!--  STAX comes with Java 1.6 -->
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>javax.xml.stream</groupId>
    </exclusion>
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>stax</groupId>
    </exclusion>
  </exclusions>
<dependency>
escocês
fonte
1
É necessário observar que essa dependência transitiva pode ser usada e a exclusão pode causar uma falha de construção se for necessário.
Bernhard Colby
Se você estiver usando um JDK moderno (ou seja, 1.6+) e precisar da versão muito mais antiga do stax incluída por meio de uma dependência transitiva, provavelmente irá se deparar com todos os tipos de problemas terríveis do carregador de classes em tempo de execução. Meu conselho: use o do JDK. Se você receber uma "falha de construção", estará contando com uma API antiga de alguma forma que deve ser atualizada. Ou: reverta seu JDK para 1.5. Boa sorte com isso.
escocês
11

O que você colocar dentro da </dependencies>tag do pom raiz será incluído em todos os módulos filhos do pom raiz. Se todos os seus módulos usam essa dependência, este é o caminho a seguir.

No entanto, se apenas 3 de 10 dos seus módulos filhos usam alguma dependência, você não quer que essa dependência seja incluída em todos os seus módulos filhos. Nesse caso, você pode simplesmente colocar a dependência dentro do </dependencyManagement>. Isso garantirá que qualquer módulo filho que precise da dependência deve declará-la em seu próprio arquivo pom, mas eles usarão a mesma versão dessa dependência especificada em sua </dependencyManagement>tag.

Você também pode usar o </dependencyManagement>para modificar a versão usada nas dependências transitivas, porque a versão declarada no arquivo pom superior é a que será usada. Isso pode ser útil se seu projeto A inclui um projeto externo B v1.0 que inclui outro projeto externo C v1.0. Às vezes acontece que uma violação de segurança é encontrada no projeto C v1.0 que é corrigida na v1.1, mas os desenvolvedores de B demoram a atualizar seu projeto para usar a v1.1 de C. Nesse caso, você pode simplesmente declarar uma dependência de C v1.1 no pom raiz de seu projeto dentro de `, e tudo ficará bem (assumindo que B v1.0 ainda será capaz de compilar com C v1.1).

Kent Munthe Caspersen
fonte
10

Eu também tive problemas para ignorar uma dependência em uma biblioteca de terceiros. Usei a abordagem do scot com a exclusão, mas também adicionei a dependência com a versão mais recente no pom. (Eu usei o Maven 3.3.3)

Portanto, para o exemplo stAX, seria assim:

<dependency>
  <groupId>a.group</groupId>
  <artifactId>a.artifact</artifactId>
  <version>a.version</version>
  <exclusions>
    <!--  STAX comes with Java 1.6 -->
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>javax.xml.stream</groupId>
    </exclusion>
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>stax</groupId>
    </exclusion>
  </exclusions>
<dependency>

<dependency>
    <groupId>javax.xml.stream</groupId>
    <artifactId>stax-api</artifactId>
    <version>1.0-2</version>
</dependency>
Patrick Koorevaar
fonte
1

A resposta aceita está correta, mas gostaria de acrescentar meus dois centavos. Tive um problema em que tinha um projeto A que tinha um projeto B como dependência. Ambos os projetos usam slf4j, mas o projeto B usa log4j enquanto o projeto A usa logback. O projeto B usa slf4j 1.6.1, enquanto o projeto A usa slf4j 1.7.5 (devido à dependência logback 1.2.3 já incluída).

O problema: o projeto A não conseguiu encontrar uma função existente no slf4j 1.7.5, após verificar a guia de hierarquia de dependências do eclipe, descobri que durante a compilação ele estava usando slf4j 1.6.1 do projeto B, em vez de usar o slf4j 1.7.5 do logback .

Resolvi o problema alterando a ordem das dependências no projeto A pom, quando movi a entrada do projeto B abaixo da entrada de logback, então o maven começou a construir o projeto usando slf4j 1.7.5.

Edit: Adicionar a dependência slf4j 1.7.5 antes da dependência do Projeto B funcionou também.

Fernando maia
fonte