Partager via


Résoudre les conflits de versions de dépendance

Cet article décrit les conflits de versions de dépendance 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 :

Un grand nombre d’applications et de frameworks Java utilisent ces bibliothèques de manière directe ou transitive, ce qui entraîne des conflits de versions. Les gestionnaires de dépendances, tels que Maven et Gradle, résolvent toutes les dépendances afin d’obtenir une seule et même 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 Introduction to the Dependency Mechanism dans la documentation de Maven et Understanding dependency resolution dans la documentation de Gradle.

L’incompatibilité au niveau 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 de différence de version

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

Utiliser l’outil de génération 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 des dépendances

Exécutez mvn dependency:tree ou gradle dependencies --scan pour afficher toute l’arborescence des dépendances de votre application, avec les 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 demanded une configuration supplémentaire pour les dépendances personnalisées. Ils peuvent également apporter leurs propres versions des bibliothèques de client Azure ou des composants communs. Pour plus d’informations, consultez les articles suivants :

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

Configurer Azure Functions

La version de dépendance interne sur des fonctions Azure (exécutant Java 8 uniquement) est prioritaire sur une version fournie par l’utilisateur. Cette dépendance provoque des conflits de versions, 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 sur 1. Veillez à mettre à jour Azure Function Tools (v2 ou v3) avec la dernière version.

Remarque

Cette configuration s’applique aux fonctions Azure exécutant Java 8 uniquement, les fonctions exécutant Java 11 n’ayant 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 (une version compatible avec Spark). Pour plus d’informations, consultez la section Prise en charge de 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é une détection d’exécution et de meilleurs diagnostics de la version d’exécution de Jackson.

Si vous voyez LinkageError (ou l’une de ses sous-classes) pour l’API Jackson, vérifiez le message de l’exception concernant les informations de version d’exécution. 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

Recherchez les journaux d’avertissement et d’erreur à partir de JacksonVersion. Pour plus d’informations, consultez Configurer la journalisation dans le 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 de différence de version

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

Utiliser la nomenclature du SDK Azure

Utilisez la dernière version stable de la nomenclature du SDK Azure et ne spécifiez pas les versions des dépendances et du SDK Azure dans votre fichier POM. Le cas échéant, utilisez la nomenclature Azure Spring Boot.

Les dépendances listées dans la nomenclature du SDK Azure sont rigoureusement testées 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 les mêmes fonctionnalités. Ces dépendances inutiles exposent les applications à des failles de sécurité, des conflits de versions et des coûts de maintenance et de support.

Mettre à jour les versions de dépendance

Si vous passez au dernier boM du KIT de développement logiciel (SDK) Azure, identifiez les bibliothèques qui provoquent des conflits et les composants qui les utilisent. (Pour plus d’informations, consultez le Afficher une section d’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 passer à une version antérieure du SDK Azure parce que cela peut exposer votre application à des vulnérabilités et des problèmes connus.

Ombrer les bibliothèques

Parfois, il n’existe aucune combinaison de bibliothèques qui fonctionnent ensemble et l’ombrage (« shading ») vient en 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. Utilisez-le seulement si vous avez épuisé les autres options.

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 Diamond n’est plus un problème parce qu’il existe deux copies différentes d’une dépendance. Vous pouvez ombrer une bibliothèque qui a une dépendance transitive en conflit ou une dépendance applicative 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 nuancer et déplacer Jackson 2.9 dans un nouveau module avec des classes Jackson déplacées à la place.

Remarque

La création d’un gros fichier JAR avec des classes Jackson déplacées ne résout pas un conflit de versions dans ces exemples, cela ne fait qu’appliquer une seule version ombrée de Jackson.

Créer un gros fichier JAR

Les environnements comme Databricks ou Apache Spark ont une gestion des dépendances personnalisée et fournissent des bibliothèques communes comme Jackson. Pour éviter les conflits avec les bibliothèques fournies, vous souhaiterez peut-être créer un gros fichier JAR contenant toutes les dépendances. Pour plus d’informations, consultez Apache Maven Shade Plugin. Dans de nombreux cas, le déplacement des classes Jackson (com.fasterxml.jackson) atténue le problème. Parfois, comme ces environnements apportent aussi leur propre version des kits SDK Azure, vous pourrez être amené à déplacer l’espace de noms com.azure pour contourner les conflits de versions.

Comprendre les versions de dépendances compatibles

Pour plus d’informations sur azure-coreles dépendances spécifiques et leurs versions, consultez azure-core dans le référentiel central Maven. Le tableau suivant présente quelques considérations générales :

Dépendance Versions prises en charge
Jackson La version 2.10.0 et les versions mineures ultérieures 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.*
reactor-core 3.X.* - Les numéros de version majeure et mineure doivent correspondre exactement à ceux dont dépend votre version azure-core. Pour plus d’informations, consultez la politique Project Reactor sur les dépréciations.

Prise en charge de plusieurs versions 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 antérieures de azure-core celles-ci ne dépendent azure-jsonpas encore. 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 versions de dépendance et leur résolution, consultez Gestion des dépendances pour Java pour plus d’informations sur le meilleur moyen de les éviter.