Existe uma maneira de excluir uma dependência Maven globalmente?

93

Estou tentando encontrar uma maneira “genérica” de excluir uma dependência transitiva de ser incluída sem ter que excluí-la de todas as dependências que dependem dela. Por exemplo, se eu quiser excluir slf4j, faço o seguinte:

  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-jmx</artifactId>
    <version>3.3.2.GA</version>
    <exclusions>
      <exclusion>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>3.4.0.GA</version>
    <type>jar</type>
    <exclusions>
      <exclusion>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
      </exclusion>
    </exclusions>
  </dependency>

Isso é parcialmente para limpar o arquivo pom, parcialmente para evitar problemas no futuro com pessoas adicionando dependências que dependem dessa dependência excluída - e esquecendo-se de excluí-la.

Há algum caminho?

Sébastien Le Callonnec
fonte
2
Não resolve o problema, mas maven-enforcer-plugin tem um recurso de dependências banidas que irá falhar a compilação se dependências indesejadas entrarem sorrateiramente. Você ainda tem que excluí-las manualmente, entretanto: - /
dnault
Uma resposta alternativa está disponível aqui: stackoverflow.com/a/39979760/363573
Stephan

Respostas:

69

Isso ajuda? http://jlorenzen.blogspot.com/2009/06/maven-global-excludes.html

"Supondo que eu queira excluir o framework avalon do meu WAR, eu adicionaria o seguinte aos meus projetos POM com um escopo fornecido. Isso funciona em todas as dependências transitivas e permite que você especifique uma vez.

<dependencies>
  <dependency>
      <artifactId>avalon-framework</artifactId>
      <groupId>avalon-framework</groupId>
      <version>4.1.3</version>
      <scope>provided</scope>
  </dependency>
</dependencies>

Isso funciona até mesmo ao especificá-lo no POM pai, o que evitaria que os projetos precisassem declarar isso em todos os POMs filhos. "

Joffer
fonte
49
Ainda é apenas um hack parcial - a dependência não terminará dentro do artefato de construção, mas ainda estará disponível durante os testes.
Tuukka Mustonen
@TuukkaMustonen E quanto ao runtimeescopo em vez do providedescopo?
Stephan,
O que acontecerá se avalon-framework 4.1.3+ for incluído em outra parte do projeto? Veja uma resposta aqui: stackoverflow.com/a/39979760/363573
Stephan
Não uso mais o Maven, então não estou em posição de testar as outras respostas, mas encorajo as pessoas a considerá-las caso haja uma que não seja um hack parcial, conforme @TuukkaMustonen
Joffer
18

Eu criei um jar vazio e criei esta dependência:

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <scope>system</scope>
    <systemPath>${basedir}/src/lib/empty.jar</systemPath>
    <version>0</version>
</dependency>

Não é perfeito porque a partir de agora você tem um jar vazio em seu caminho de compilação / teste. Mas isso é apenas cosmético.

2 rotações
fonte
3
systemescopo agora está obsoleto: maven.apache.org/guides/introduction/…
Jason Young
Para evitar o uso de systemescopo, consulte o repositório virtual Maven versão99.grons.nl (Aviso: apenas HTTP) ou (para commons-logging / log4j apenas) consulte a "alternativa 3) artefatos vazios" aqui: slf4j.org/faq.html#excludingJCL
seanf
16

Para expandir o comentário de dnault :

É possível usar a regra Banned Dependencies do plug-in Maven Enforcer para garantir que as dependências sejam excluídas. Ainda é preciso excluí-los manualmente, mas a construção falhará se alguém adicionar a dependência em outro lugar por engano.

<dependencies>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-jmx</artifactId>
    <version>3.3.2.GA</version>
    <exclusions>
      <exclusion>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
</dependencies>

<plugins>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>1.4.1</version>
    <executions>
      <execution>
        <goals>
          <goal>enforce</goal>
        </goals>
        <configuration>
          <rules>
            <bannedDependencies>
              <excludes>
                <exclude>org.slf4j:slf4j-api</exclude>
              </excludes>
            </bannedDependencies>
          </rules>
        </configuration>
      </execution>
    </executions>
  </plugin>
</plugins>

Também há uma solicitação de recurso aberta: MNG-1977 Global dependency exclusions

Arend v. Reinersdorff
fonte
2
Seguindo sua resposta e lendo a discussão no link que você forneceu, percebi que jars indesejados estão entrando em pote algumas vezes apenas porque a versão do maven usada no local e no servidor são diferentes, então a lógica de empacotamento pode adicionar versões bem diferentes de dependências se elas não forem estritamente aplicadas. Para resolver meu problema semelhante, usei spring-boot-maven-plugin configuration / excludes / exclude para <goal> repackage </goal>.
abril
10

Como um lembrete, aqui está a resposta da documentação oficial do Maven:

Por que as exclusões são feitas por dependência, em vez de no nível do POM

Isso é feito principalmente para garantir que o gráfico de dependência seja previsível e para evitar que os efeitos de herança excluam uma dependência que não deve ser excluída. Se você chegar ao método de último recurso e precisar incluir uma exclusão, deverá ter certeza absoluta de qual de suas dependências está trazendo essa dependência transitiva indesejada.

Se alguém quiser tornar uma construção mais robusta, um intervalo de versões pode ser usado. Isso garantiria que nenhuma versão mais recente da dependência possa interferir no projeto.

<dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>[1.4.2,)</version>
   <scope>provided</scope>
</dependency>

Qualquer versão slf4j-api> = 1.4.2 será considerada como oferecida (fornecida) em tempo de execução, seja de um classpath configurado ou um contêiner.

Referências

Stephan
fonte