この記事では、依存関係バージョンの競合とそのトラブルシューティング方法について説明します。
Java 用 Azure クライアント ライブラリは、次のような一般的なサード パーティ製ライブラリに依存しています。
多くの Java アプリケーションとフレームワークでは、これらのライブラリが直接または推移的に使用されるため、 バージョンの競合が発生します。 Maven や Gradle などの依存関係マネージャーは、すべての依存関係を解決して、クラスパスに対する各依存関係のバージョンが 1 つだけになるようにします。 ただし、解決された依存関係バージョンが、アプリケーション内のその依存関係のすべてのコンシューマーと互換性があるとは限りません。 詳細については、Maven ドキュメント の依存関係メカニズムの概要 と Gradle ドキュメントの 依存関係解決 についてを参照してください。
直接依存関係の API の非互換性により、コンパイル エラーが発生します。 通常、ダイヤモンドの依存関係 の非互換性により、 NoClassDefFoundError、 NoSuchMethodError、その他 のリンケージ エラーなどの実行時エラーが発生します。 すべてのライブラリが セマンティック バージョン管理に厳密に従っているわけではありません。また、破壊的変更が同じメジャー バージョン内で発生する場合があります。
バージョンの不一致の問題を診断する
以降のセクションでは、バージョンの不一致の問題を診断する方法について説明します。
Azure SDK for Java ビルド ツールを使用する
「Azure SDK と Apache Maven の概要」で導入された Azure SDK for Java ビルド ツールは、一般的に発生する問題を特定するのに役立ちます。 このビルド ツールをプロジェクトに追加し、通常のビルド プロセスに azure:run
Maven ターゲットを追加して実行することをお勧めします。 適切な構成を使用すると、実行時に問題になる前に、依存関係の競合をより積極的に特定して解決できます。
依存関係ツリーを表示する
mvn dependency:tree
またはgradle dependencies --scan
を実行して、アプリケーションの完全な依存関係ツリーとバージョン番号を表示します。
mvn dependency:tree -Dverbose
は、より多くの情報を提供しますが、誤解を招く可能性があります。 詳細については、Maven ドキュメントの Apache Maven 依存関係ツリー を参照してください。 バージョンの競合が疑われるライブラリごとに、そのバージョン番号を書き留めて、どのコンポーネントがそれに依存するかを判断します。
開発環境と運用環境での依存関係の解決は、動作が異なる場合があります。 Apache Spark、 Apache Flink、 Databricks、IDE プラグインには、カスタム依存関係用の追加の構成が必要です。 また、独自のバージョンの Azure クライアント ライブラリまたは共通コンポーネントを使用することもできます。 詳細については、次の記事を参照してください。
- Apache Spark 用アプリケーションの依存関係のバンドル
- Apache Flink のプロジェクト構成
- Databricks for Databricks で Maven ライブラリを正しく更新する方法
このような環境での競合解決の詳細については、この記事で後述する 「Fat JAR の作成 」セクションを参照してください。
Azure Functions の構成
Azure Functions の内部依存関係バージョン (Java 8 のみを実行) は、ユーザーが指定したバージョンよりも優先されます。 この依存関係により、バージョンの競合 (特に Jackson、Netty、Reactor) が発生します。
この問題を解決するには、 FUNCTIONS_WORKER_JAVA_LOAD_APP_LIBS
環境変数を true
または 1
に設定します。 Azure Function Tools (v2 または v3) を最新バージョンに更新してください。
注
この構成は、Java 8 を実行する Azure Functions にのみ適用されます。Java 11 を実行する関数には特別な構成は必要ありません。
Apache Spark を構成する
Azure SDK for Java では複数のバージョンの Jackson がサポートされていますが、ビルド ツールとその依存関係解決の順序によっては問題が発生する場合があります。 この問題の良い例は、Apache Spark バージョン 3.0.0 以降であり、Jackson 2.10 に依存しています。 Azure SDK for Java と互換性がありますが、開発者は多くの場合、より新しいバージョンの Jackson が代わりに使用されていることに気が付き、結果として非互換性が生じます。 この問題を軽減するには、特定のバージョンの Jackson (Spark と互換性のあるバージョン) をピン留めする必要があります。 詳細については、この記事の 「複数の Jackson バージョンのサポート 」セクションを参照してください。
以前のバージョンの Spark を使用している場合、または使用する別のライブラリで、Azure SDK for Java でサポートされていないより前のバージョンの Jackson が必要な場合は、この記事を引き続き読んで軽減手順を確認してください。
Jackson ランタイム バージョンの検出
Azure Core 1.21.0 では、Jackson ランタイム バージョンのランタイム検出と診断の改善が追加されました。
Jackson API に関連する LinkageError
(またはそのサブクラスのいずれか) が表示される場合は、例外のメッセージでランタイム バージョン情報を確認してください。 例: 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
JacksonVersion
から警告ログとエラー ログを探します。 詳細については、「 Azure SDK for Java でのログ記録の構成」を参照してください。 例: [main] ERROR com.azure.core.implementation.jackson.JacksonVersion - Version '2.9.0' of package 'jackson-core' is not supported (too old), please upgrade.
注
すべての Jackson パッケージのバージョンが同じであることを確認します。
Azure SDK で使用されるパッケージとサポートされている Jackson バージョンの一覧については、「 複数の Jackson バージョンのサポート 」セクションを参照してください。
バージョンの不一致の問題を軽減する
以降のセクションでは、バージョンの不一致の問題を軽減する方法について説明します。
Azure SDK BOM を使用する
最新の安定した Azure SDK BOM を 使用し、POM ファイルに Azure SDK と依存関係のバージョンを指定しないでください。 該当する場合は、 Azure Spring Boot BOM を使用します。
Azure SDK BOM に記載されている依存関係は、依存関係の競合を回避するために厳密にテストされます。
不要な依存関係を回避する
可能であれば、依存関係を削除します。 アプリケーションが、基本的に同じ機能を提供する複数のライブラリに依存している場合があります。 このような不要な依存関係により、アプリケーションはセキュリティの脆弱性、バージョンの競合、サポートとメンテナンスのコストにさらされます。
依存関係のバージョンを更新する
最新の Azure SDK BOM に切り替えても問題が解決しない場合は、競合の原因となっているライブラリと、それらを使用するコンポーネントを特定します。 (詳細については、この記事の前の「 依存関係ツリーの表示 」セクションを参照してください)。セキュリティの脆弱性から保護し、多くの場合、新機能、パフォーマンスの向上、バグ修正を行う新しいバージョンに更新してみてください。
既知の脆弱性や問題にアプリケーションが公開される可能性があるため、Azure SDK バージョンのダウングレードは避けてください。
ライブラリのシェーディング
一緒に動作するライブラリの組み合わせが見つからない場合、最後の手段としてシャーディングを行うことがあります。
注
シェーディングには大きな欠点があります。これにより、クラスパスのパッケージ サイズとクラスの数が増え、コードのナビゲーションとデバッグが困難になり、JNI コードが再配置され、リフレクションが中断され、特にコード ライセンスに違反する可能性があります。 他のオプションが使い果たされた後にのみ使用する必要があります。
シェーディングを使用すると、ビルド時に JAR 内に依存関係を含め、パッケージの名前を変更し、網掛けされた場所でコードを使用するようにアプリケーション コードを更新できます。 依存関係には 2 つの異なるコピーがあるため、ひし形の依存関係の競合は問題ではなくなりました。 次の一覧で説明するように、競合する推移的な依存関係または直接のアプリケーションの依存関係を持つライブラリを網掛けすることができます。
-
推移的な依存関係の競合: たとえば、サードパーティ製のライブラリ
A
には Jackson 2.9 が必要です。これは、Azure SDK ではサポートされておらず、A
を更新することはできません。A
と、Jackson 2.9をシャーディング(再配置)し、必要に応じてA
のその他の依存関係を含む新しいモジュールを作成します。 - アプリケーションの依存関係の競合: アプリケーションは Jackson 2.9 を直接使用します。 コードの更新に取り組んでいる間に、Jackson 2.9 をシェーディングして新しいモジュールに再配置し、代わりに Jackson クラスを再配置することができます。
注
再配置された Jackson クラスを使用して Fat JAR を作成しても、これらの例ではバージョンの競合は解決されません。ジャクソンの単一のシェーディング バージョンのみが強制されます。
「ファット JAR(全ての依存関係を含む大きな JAR ファイル)を作成する」
Databricks や Apache Spark などの環境には、カスタム依存関係管理があり、Jackson などの一般的なライブラリが用意されています。 提供されているライブラリとの競合を回避するために、すべての依存関係を含む fat JAR を構築することをお勧めします。 詳細については、「 Apache Maven Shade Plugin」を参照してください。 多くの場合、Jackson クラス (com.fasterxml.jackson
) を再配置すると、問題が軽減されます。 このような環境では独自のバージョンの Azure SDK も使用される場合があるため、バージョンの競合を回避するために名前空間 com.azure
再配置する必要が生じることがあります。
互換性のある依存関係のバージョンについて
azure-core
固有の依存関係とそのバージョンについては、Maven Central リポジトリの azure-core を参照してください。 次の表は、一般的な考慮事項を示しています。
依存関係 | サポートされているバージョン |
---|---|
ジャクソン | 2.10.0 以降のマイナー バージョンには互換性があります。 詳細については、「 複数の Jackson バージョンのサポート 」セクションを参照してください。 |
SLF4J | 1.7.* |
netty-tcnative-boringssl-static | 2.0.* |
netty-common | 4.1.* |
炉心 | 3.X.* - メジャー バージョン番号とマイナー バージョン番号は、 azure-core バージョンが依存する番号と完全に一致している必要があります。 詳細については、廃止に関する Project Reactor ポリシーを参照してください。 |
複数の Jackson バージョンのサポート
Azure SDK for Java では、さまざまな Jackson バージョンの操作がサポートされています。 サポートされている最小バージョンは Jackson 2.10.0 です。 Azure SDK for Java クライアント ライブラリは、実行時に検出されるバージョンに応じて、構成と Jackson の使用状況を調整します。 この調整により、古いバージョンの Spring Framework、Apache Spark、およびその他の一般的な環境との互換性が向上します。 アプリケーションでは、Azure SDK for Java クライアント ライブラリを中断することなく、Jackson のバージョンを (2.10.0 以降に) ダウングレードできます。
注
以前のバージョンの Jackson を使用すると、アプリケーションが既知の脆弱性や問題にさらされる可能性があります。 詳細については、 Jackson ライブラリの既知の脆弱性の一覧を参照してください。
特定のバージョンの Jackson をピン留めする場合は、次の一覧に示すように、Azure SDK で使用されるすべてのモジュールに対して行ってください。
jackson-annotations
jackson-core
jackson-databind
jackson-dataformat-xml
jackson-datatype-jsr310
Jackson から azure-json への移行
Java 用 Azure クライアント ライブラリは、サード パーティのコンポーネントに依存しない azure-json への移行中であり、JSON 用の共有プリミティブ、抽象化、ヘルパーを提供しています。
Apache Spark、Apache Flink、Databricks などの環境では、azure-core
にまだ依存していない古いバージョンのazure-json
が提供される場合があります。 その結果、このような環境で新しいバージョンの Azure ライブラリを使用すると、 java.lang.NoClassDefFoundError: com/azure/json/JsonSerializable
のようなエラーが発生する可能性があります。 このエラーを軽減するには、 azure-json
に明示的な依存関係を追加します。
次のステップ
依存関係のバージョンの競合とそのトラブルシューティングの方法については、「Java の依存関係管理 」を参照して、それらを防ぐ最善の方法について説明します。