Version de bibliothèque contradictoire dans un projet java maven

Lors de la création d’un projet Maven comportant de nombreuses dépendances, certaines de ces dépendances dépendent de la même bibliothèque mais utilisent une version différente qui provoque des erreurs lors de l’exécution d’une application.

Par exemple, si j’ajoute deux dépendances de projet différentes, A et B qui dépendent tous deux du client http apache commons mais chacune sur une version différente, une fois que le chargeur de classe charge les classes client http d’Apache commons, B essaiera de les utiliser ils sont déjà chargés par le chargeur de classes.

Mais le bytecode de B dépend d’une version différente des classes chargées causant plusieurs problèmes lors de l’exécution de l’application. Une exception commune est methodnotfound exception (puisque la version de http du client http n’utilise plus une méthode spécifique).

Quelle est la stratégie générale à suivre pour éviter de tels conflits? Doit-on vérifier manuellement l’arbre de dépendance pour savoir quelles bibliothèques communes se côtoient?

Bienvenue dans l’ enfer de la dépendance , comme on le dit si bien. C’est un problème assez courant à mesure que les projets se développent et que davantage de dépendances externes sont introduites.

Outre Apache Commons (mentionné dans votre question initiale), les frameworks de journalisation (log4j, slf4j) sont un autre coupable fréquent.

Je suis d’accord avec les conseils donnés par “matts” sur la façon de résoudre les conflits une fois qu’ils sont identifiés. En ce qui concerne la capture précoce de ces conflits de version, vous pouvez également utiliser le plugin maven “contrainte”. Reportez-vous à la configuration “dependencyConvergence” . Voir aussi ce post SO .

L’utilisation du plug-in tube ne fonctionnera pas immédiatement lors du conflit de version, ce qui vous évitera les vérifications manuelles. Ceci est une stratégie agressive, mais empêche le type de problèmes d’exécution qui ont incité votre question / publication. Comme tout le rest, le plug-in d’éclairage possède des avantages et des inconvénients. Nous avons commencé à l’utiliser au cours de la dernière année, mais nous avons découvert que cela pouvait être une bénédiction et une malédiction. De nombreuses versions de libs / frameworks sont rétrocompatibles, de sorte que dépendre (directement ou indirectement) des versions 1.2.3 et 1.2.4 est souvent correct à la fois à la compilation et à l’exécution. Toutefois, le plug-in superviser signalera ce conflit et vous demandera de déclarer exactement la version que vous souhaitez. En supposant que le nombre de conflits de dépendance est faible, cela ne nécessite pas beaucoup de travail. Cependant, une fois que vous introduisez un grand framework (par exemple, Spring MVC), il peut devenir désagréable.

J’espère que c’est une information utile.

Vous pouvez utiliser l’ objective de l’ tree du plug-in de dépendance Maven pour afficher toutes les dépendances transitives dans votre projet et rechercher les dépendances qui disent «omis pour les conflits». 1

 mvn dependency:tree -Dverbose mvn dependency:tree -Dverbose | grep 'omitted for conflict' 

Une fois que vous savez quelle dépendance a des conflits de version, vous pouvez utiliser le paramètre includes pour afficher uniquement les dépendances qui conduisent à celle-ci pour voir comment une dépendance particulière est extraite. Par exemple, un projet où différentes versions de C sont extraites par A et B:

 mvn dependency:tree -Dverbose -Dincludes=project-c [INFO] com.my-company:my-project:jar:1.0-SNAPSHOT [INFO] +- project-a:project-a:jar:0.1:comstack [INFO] | \- project-c:project-c:jar:1.0:comstack [INFO] \- project-b:project-b:jar:0.2:comstack [INFO] \- project-x:project-x:jar:0.1:comstack [INFO] \- (project-c:project-c:jar:2.0:comstack - omitted for conflict) 

Pour résoudre le conflit, il est parfois possible de trouver une version de la dépendance transitive avec laquelle vos deux dépendances principales fonctionneront. Ajoutez la dépendance transitive à la section dependencyManagement de votre pom et essayez de changer la version jusqu’à ce que l’une fonctionne.

Cependant, dans d’autres cas, il peut ne pas être possible de trouver une version de la dépendance qui fonctionne pour tout le monde. Dans ces cas, vous devrez peut-être revenir en arrière sur l’une des dépendances principales afin de lui faire utiliser une version de la dépendance transitive qui fonctionne pour tout le monde. Par exemple, dans l’exemple ci-dessus, A 0.1 utilise C 1.0 et B 0.2 utilise C 2.0. Supposons que C 1.0 et 2.0 sont complètement incompatibles. Mais peut-être est-il possible que votre projet utilise plutôt B 0.1, qui dépend de C 1.5, compatible avec C 1.0.

Bien sûr, ces deux stratégies ne fonctionneront pas toujours, mais j’ai déjà eu du succès avec elles. D’autres options plus radicales incluent la création de votre propre version de la dépendance qui corrige l’incompatibilité ou tente d’isoler les deux dépendances dans des chargeurs de classes distincts.

Vous pouvez utiliser le plugin maven-enforcer dans votre pom pour forcer des versions spécifiques des dépendances transitives. Cela vous aidera à éviter les omissions de la configuration pom en cas de conflit.

C’est ce qui a fonctionné pour moi, et j’ai pu modifier les versions pour les faire correspondre. Si vous ne pouvez pas changer de version, cela ne sera pas très utile.

Convergence des dépendances

  ...   ...  org.apache.maven.plugins maven-enforcer-plugin 1.4   enforce       enforce     ...   ...  

Forcer une version sur la dépendance à l’aide de crochets:

  org.slf4j slf4j-api comstack [1.0.0]  

Je voudrais étendre les réponses de Todd’s et Matts au fait que vous pouvez:

  • mvn dependency:tree -Dverbose -Dincludes=project-c

  • Ajoutez une pour toutes vos dépendances qui ont une dépendance transitive de project-c .

  • Ou bien, dans votre projet, définissez explicitement project-c comme une dépendance afin de remplacer les transitives et d’éviter les conflits. (Cela apparaîtra toujours dans votre arbre lorsque vous utilisez `-Dverbose).

Alternativement, si ces projets sont sous votre contrôle, vous pouvez simplement mettre à niveau la version de project-c .