web-dev-qa-db-fra.com

Résolution des dépendances Maven (en conflit)

Disons que j'ai quatre projets:

  • Projet A (dépend de B et D)
  • Projet B (a une dépendance sur D)
  • Projet C (a une dépendance sur D)
  • Projet D

Dans ce scénario, si j'exécute le projet A, Maven résoudra correctement la dépendance en D. Si je comprends bien, Maven prend toujours la dépendance avec le chemin le plus court. Puisque D est une dépendance directe de A, il sera plutôt utilisé, le D qui est spécifié dans B.

Mais assumons maintenant cette structure:

  • Projet A (dépend de B et C)
  • Projet B (a une dépendance sur D)
  • Projet C (a une dépendance sur D)
  • Projet D

Dans ce cas, les chemins de résolution de D ont la même profondeur. Ce qui se passe, c'est que Maven aura un conflit. Je sais qu'il est possible de dire à Maven qu'il devrait exclure les dépendances. Mais ma question est de savoir comment résoudre ce genre de problèmes. Je veux dire que dans une application réelle, vous avez beaucoup de dépendances et peut-être aussi beaucoup de conflits.

La meilleure pratique est-elle vraiment d'exclure des éléments ou existe-t-il d'autres solutions possibles? Je trouve cela très difficile à gérer lorsque j'obtiens soudain une exception ClassNotFound car certaines versions ont changé, ce qui a amené Maven à prendre une dépendance différente. En effet, le fait de savoir ce fait permet de deviner un peu plus facilement que le problème est un conflit de dépendance.

J'utilise maven 2.1-SNAPSHOT.

65
kukudas

La manière la plus simple de résoudre des situations comme celle-ci consiste à inclure un <dependencyManagement> section dans le pom racine de votre projet, où vous spécifiez quelle version de quelle bibliothèque sera utilisée.

MODIFIER:

<dependencyManagement>
  <dependencies>
    <dependency>
        <groupId>foo</groupId>
        <artifactId>bar</artifactId>
        <version>1.2.3</version>
    </dependency>
   </dependencies>
</dependencyManagement>

Quelle que soit la version de la bibliothèque foo: bar demandée par une dépendance, la version 1.2.3 sera toujours utilisée pour ce projet et tous les sous-projets.

Référence:

76
Sean Patrick Floyd

Maven peut gérer les deux situations sans aucun conflit. Des conflits existent lorsque deux versions d'une dépendance transitive sont requises. Le ClassNotFoundException que vous décrivez résulte de l'application (ou d'une dépendance) qui tente d'utiliser une classe non disponible dans la version de la dépendance en conflit qui est réellement utilisée. Il existe plusieurs façons de résoudre le problème.

  1. Mettez à jour les versions des bibliothèques que vous utilisez qui dépendent de la dépendance en conflit, afin qu'elles dépendent toutes de la même version de version de cette dépendance
  2. Déclarez la dépendance en conflit comme une dépendance directe de votre projet avec la version que vous souhaitez inclure (dans l'exemple, celle avec la classe manquante incluse)
  3. Spécifiez la version de la dépendance en conflit que les dépendances transitives doivent utiliser, via le <dependencyManagement> section du POM
  4. Exclure explicitement les versions indésirables de la dépendance en conflit d'être incluses avec les dépendances qui dépendent d'elles à l'aide d'un <exclusion>
26
Daniel

Ce n'est fondamentalement pas un problème maven, mais un problème Java. Si le projet B et le projet C ont besoin de deux versions incompatibles du projet D, vous ne pouvez pas les utiliser tous les deux dans le projet A.

La manière Maven de résoudre des conflits comme ceux-ci est malheureusement, comme vous le savez déjà, de choisir ceux à exclure.

En utilisant mvn dependency:analyze et mvn dependency:tree aide à trouver les conflits que vous avez.

17
Buhb

Vous pouvez appliquer des dépendances cohérentes dans l'ensemble du projet avec la règle Convergence des dépendances .

 <plugin>
     <groupId>org.Apache.maven.plugins</groupId>
     <artifactId>maven-enforcer-plugin</artifactId>
     <version>1.3.1</version>
     <executions>
        <execution>
           <id>enforce</id>
           <configuration>
              <rules>
                 <DependencyConvergence/>
              </rules>
           </configuration>
           <goals>
              <goal>enforce</goal>
           </goals>
        </execution>
     </executions>
  </plugin>
13
MariuszS

Une stratégie possible consiste à spécifier pour le projet principal, quelle version de D utiliser (la plus récente f.g.). Cependant, si la bibliothèque D n'est pas rétrocompatible, vous avez un problème comme indiqué par kukudas - il est impossible d'utiliser les deux bibliothèques dans votre projet.

Dans une telle situation, il peut être nécessaire d'utiliser B ou C dans une ancienne version, de sorte que les deux dépendent des versions compatibles de D.

5
Stepan Vihor