Partager via


Résoudre les conflits de version des dépendances

Cet article décrit les conflits de version des dépendances et explique comment les résoudre.

Les bibliothèques clientes Azure pour Java dépendent de bibliothèques tierces populaires, telles que les bibliothèques suivantes :

De nombreuses applications et infrastructures Java utilisent ces bibliothèques directement ou transitivement, ce qui entraîne des conflits de version. Les gestionnaires de dépendances tels que Maven et Gradle résolvent toutes les dépendances afin qu’il n’existe qu’une seule version de chaque dépendance sur le classpath. Toutefois, il n’est pas garanti que la version de dépendance résolue soit compatible avec tous les consommateurs de cette dépendance dans votre application. Pour plus d’informations, consultez Présentation du mécanisme de dépendance dans la documentation Maven et Présentation de la résolution des dépendances dans la documentation Gradle.

L’incompatibilité de l’API des dépendances directes entraîne des erreurs de compilation. L’incompatibilité des dépendances Diamond aboutit généralement à des échecs d’exécution comme NoClassDefFoundError, NoSuchMethodError ou encore LinkageError. Les bibliothèques ne suivent pas toutes de façon stricte la gestion sémantique des versions, et des changements cassants se produisent parfois dans la même version principale.

Diagnostiquer les problèmes d’incompatibilité de version

Les sections suivantes décrivent les méthodes permettant de diagnostiquer les problèmes d’incompatibilité de version.

Utiliser l'outil de construction du kit de développement logiciel (SDK) Azure pour Java

L’outil de build Azure SDK pour Java, introduit dans Get started with Azure SDK et Apache Maven, permet d’identifier les problèmes couramment rencontrés. Nous vous recommandons d’ajouter cet outil de génération à votre projet et de l’exécuter en ajoutant la azure:run cible Maven à votre processus de génération standard. Avec la configuration appropriée, vous pouvez identifier et résoudre les conflits de dépendance de manière plus proactive avant qu’ils ne deviennent des problèmes au moment de l’exécution.

Afficher une arborescence de dépendances

Exécutez mvn dependency:tree ou gradle dependencies --scan pour afficher l’arborescence de dépendances complète de votre application, avec des numéros de version. mvn dependency:tree -Dverbose donne plus d’informations, mais peut être trompeuse. Pour plus d’informations, consultez l’arborescence des dépendances Apache Maven dans la documentation Maven. Pour chaque bibliothèque que vous pensez avoir un conflit de version, notez son numéro de version et déterminez les composants qui en dépendent.

La résolution des dépendances dans les environnements de développement et de production peut fonctionner différemment. Les plug-ins Apache Spark, Apache Flink, Databricks et IDE nécessitent une configuration supplémentaire pour les dépendances personnalisées. Ils peuvent également apporter leurs propres versions des bibliothèques clientes Azure ou des composants communs. Pour plus d’informations, consultez les articles suivants :

Pour plus d’informations sur la résolution des conflits dans ces environnements, consultez la section Créer un fichier JAR gras plus loin dans cet article.

Configurer Azure Functions

La version de dépendance interne sur Azure Functions (exécutant Java 8 uniquement) est prioritaire sur une version fournie par l’utilisateur. Cette dépendance provoque des conflits de version, en particulier avec Jackson, Netty et Reactor.

Pour résoudre ce problème, définissez la variable d’environnement FUNCTIONS_WORKER_JAVA_LOAD_APP_LIBS sur true ou 1. Veillez à mettre à jour azure Function Tools (v2 ou v3) vers la dernière version.

Remarque

Cette configuration s’applique à Azure Functions exécutant Java 8 uniquement, les fonctions exécutant Java 11 n’ont pas besoin d’une configuration spéciale.

Configurer Apache Spark

Le Kit de développement logiciel (SDK) Azure pour Java prend en charge plusieurs versions de Jackson, mais les problèmes peuvent parfois survenir en fonction de vos outils de génération et de son ordre de résolution des dépendances. Un bon exemple de ce problème est lié à Apache Spark, version 3.0.0 et ultérieure, qui dépend de Jackson 2.10. Bien qu’il soit compatible avec le Kit de développement logiciel (SDK) Azure pour Java, les développeurs découvrent souvent qu’une version plus récente de Jackson est utilisée à la place, ce qui entraîne des incompatibilités. Pour atténuer ce problème, vous devez épingler une version spécifique de Jackson (compatible avec Spark). Pour plus d'informations, consultez la section Soutien pour plusieurs versions de Jackson dans cet article.

Si vous utilisez des versions antérieures de Spark ou si une autre bibliothèque que vous utilisez nécessite une version même antérieure de Jackson que le Kit de développement logiciel (SDK) Azure pour Java ne prend pas en charge, poursuivez la lecture de cet article pour connaître les étapes d’atténuation possibles.

Détecter la version d’exécution de Jackson

Dans Azure Core 1.21.0, nous avons ajouté la détection du runtime et de meilleurs diagnostics de la version du runtime Jackson.

Si vous voyez LinkageError (ou l’une de ses sous-classes) liées à l’API Jackson, vérifiez le message de l’exception pour obtenir des informations sur la version du runtime. Par exemple : com.azure.core.implementation.jackson.JacksonVersionMismatchError: com/fasterxml/jackson/databind/cfg/MapperBuilder Package versions: jackson-annotations=2.9.0, jackson-core=2.9.0, jackson-databind=2.9.0, jackson-dataformat-xml=2.9.0, jackson-datatype-jsr310=2.9.0, azure-core=1.19.0-beta.2

Rechercher les journaux d’avertissement et d'erreur dans JacksonVersion. Pour plus d’informations, consultez Configurer la journalisation dans le Kit de développement logiciel (SDK) Azure pour Java. Par exemple : [main] ERROR com.azure.core.implementation.jackson.JacksonVersion - Version '2.9.0' of package 'jackson-core' is not supported (too old), please upgrade.

Remarque

Vérifiez que tous les packages Jackson ont la même version.

Pour obtenir la liste des packages utilisés par le Kit de développement logiciel (SDK) Azure et les versions de Jackson prises en charge, consultez la section Prise en charge de plusieurs versions de Jackson .

Atténuer les problèmes d’incompatibilité de version

Les sections suivantes décrivent comment atténuer les problèmes d’incompatibilité de version.

Utiliser le BOM du Kit de développement logiciel (SDK) Azure

Utilisez la dernière boM stable du KIT de développement logiciel (SDK) Azure et ne spécifiez pas les versions du Kit de développement logiciel (SDK) Azure et des versions de dépendance dans votre fichier POM. Le cas échéant, utilisez le BOM Azure Spring Boot.

Les dépendances répertoriées dans le boM du Kit de développement logiciel (SDK) Azure sont testées rigoureusement pour éviter les conflits de dépendances.

Éviter les dépendances inutiles

Supprimez les dépendances si vous le pouvez. Parfois, une application a des dépendances sur plusieurs bibliothèques qui fournissent essentiellement la même fonctionnalité. Ces dépendances inutiles exposent les applications aux vulnérabilités de sécurité, aux conflits de version et aux coûts de prise en charge et de maintenance.

Mettre à jour les versions des dépendances

Si le passage au dernier BOM du kit de développement logiciel (SDK) Azure ne résout pas le problème, identifiez les bibliothèques qui provoquent des conflits et les composants qui les utilisent. (Pour plus d’informations, consultez la section Afficher une arborescence de dépendances plus haut dans cet article.) Essayez de mettre à jour vers une version plus récente, qui protège contre les vulnérabilités de sécurité et apporte souvent de nouvelles fonctionnalités, améliorations des performances et correctifs de bogues.

Évitez de rétrograder la version du Kit de développement logiciel (SDK) Azure, car elle peut exposer votre application aux vulnérabilités et problèmes connus.

Bibliothèques de nuances

Parfois, il n’y a pas de combinaison de bibliothèques qui fonctionnent ensemble, et l’ombrage vient comme le dernier recours.

Remarque

L’ombrage présente des inconvénients significatifs : il augmente la taille du package et le nombre de classes sur le classpath, il rend la navigation et le débogage du code dur, ne déplace pas le code JNI, interrompt la réflexion et peut violer les licences de code entre autres. Elle ne doit être utilisée qu’une fois que d’autres options sont épuisées.

L’ombrage vous permet d’inclure des dépendances au sein d’un fichier JAR au moment de la génération, puis de renommer des packages et de mettre à jour le code d’application pour utiliser le code à l’emplacement ombré. Le conflit de dépendances de diamant n’est plus un problème, car il existe deux copies différentes d’une dépendance. Vous pouvez nuancer une bibliothèque qui a une dépendance transitive conflictuelle ou une dépendance d’application directe, comme décrit dans la liste suivante :

  • Conflit de dépendance transitif : par exemple, la bibliothèque A tierce nécessite Jackson 2.9, que les kits de développement logiciel (SDK) Azure ne prennent pas en charge et qu’il n’est pas possible de mettre à jour A. Créez un nouveau module, qui comprend A et ombre (déplace) Jackson 2.9 et éventuellement d’autres dépendances de A.
  • Conflit de dépendance d’application : votre application utilise Jackson 2.9 directement. Pendant que vous travaillez sur la mise à jour de votre code, vous pouvez utiliser le shading pour déplacer Jackson 2.9 dans un nouveau module avec des classes Jackson relocalisées.

Remarque

La création d'un JAR complet avec des classes Jackson relocalisées ne résout pas un conflit de version dans ces exemples : elle impose simplement une version unique et ombrée de Jackson.

Créer un gros fichier JAR

Les environnements tels que Databricks ou Apache Spark ont une gestion des dépendances personnalisée et fournissent des bibliothèques courantes comme Jackson. Pour éviter les conflits avec les bibliothèques fournies, vous pouvez créer un fichier JAR gras qui contient toutes les dépendances. Pour plus d’informations, consultez le plug-in Apache Maven Shade. Dans de nombreux cas, le déplacement des classes Jackson (com.fasterxml.jackson) atténue le problème. Parfois, ces environnements apportent également leur propre version des kits SDK Azure. Vous pouvez donc être obligé de déplacer com.azure l’espace de noms pour contourner les conflits de version.

Comprendre les versions de dépendance compatibles

Pour en savoir plus sur les dépendances spécifiques à azure-core et leurs versions, consultez azure-core dans le dépôt Maven Central. Le tableau suivant présente quelques considérations générales :

Dépendance Versions prises en charge
Jackson 2.10.0 et versions mineures plus récentes sont compatibles. Pour plus d’informations, consultez la section Prise en charge de plusieurs versions de Jackson.
SLF4J 1.7.*
netty-tcnative-boringssl-static 2.0.*
netty-common 4.1.*
cœur du réacteur 3.X.* : les numéros de version principale et mineure doivent correspondre exactement à ceux dont dépend votre azure-core version. Pour plus d’informations, consultez la politique Project Reactor sur les dépréciations.

Prise en charge de plusieurs versions de Jackson

Le Kit de développement logiciel (SDK) Azure pour Java prend en charge l’utilisation d’une gamme de versions de Jackson. La version la plus faible prise en charge est Jackson 2.10.0. Les bibliothèques clientes Azure SDK pour Java ajustent leur configuration et l’utilisation de Jackson en fonction de la version détectée lors de l’exécution. Cet ajustement permet une plus grande compatibilité avec les versions antérieures de l’infrastructure Spring, Apache Spark et d’autres environnements courants. Les applications peuvent rétrograder les versions jackson (vers la version 2.10.0 ou ultérieure) sans rompre le Kit de développement logiciel (SDK) Azure pour les bibliothèques clientes Java.

Remarque

L’utilisation d’anciennes versions de Jackson peut exposer des applications à des vulnérabilités et problèmes connus. Pour plus d’informations, consultez la liste des vulnérabilités connues pour les bibliothèques Jackson.

Lors de l’épinglage d’une version spécifique de Jackson, veillez à le faire pour tous les modules utilisés par le Kit de développement logiciel (SDK) Azure, qui sont présentés dans la liste suivante :

  • jackson-annotations
  • jackson-core
  • jackson-databind
  • jackson-dataformat-xml
  • jackson-datatype-jsr310

Migration de Jackson vers azure-json

Les bibliothèques clientes Azure pour Java sont en cours de migration vers azure-json, qui ne dépendent pas des composants tiers et propose des primitives partagées, des abstractions et des helpers pour JSON.

Les environnements comme Apache Spark, Apache Flink et Databricks peuvent apporter des versions plus anciennes de azure-core qui ne dépendent pas encore de azure-json. Par conséquent, lors de l’utilisation de versions plus récentes de bibliothèques Azure dans de tels environnements, vous pouvez obtenir des erreurs similaires à java.lang.NoClassDefFoundError: com/azure/json/JsonSerializable. Vous pouvez atténuer cette erreur en ajoutant une dépendance explicite sur azure-json.

Étapes suivantes

Maintenant que vous êtes familiarisé avec les conflits de version de dépendance et comment les résoudre, consultez Dependency Management pour Java pour plus d’informations sur la meilleure façon de les empêcher.