5

Java 8はこちら。Gradleはどんな方法でも地獄を解決できますか?

public class Widget { 
    private String meow; 

    // constructor, getters, setters, etc. 
} 

年パス:Mavenのは、そうのようにそれに定義されたクラスを有する、widgetmakers:widget:1.0.4座標と

セイwidget librayの古いバージョンがあります。このwidgetライブラリの保守担当者は、Widgetが決してmeowではなく、実際にはbarkであるべきであると判断します。 Mavenのはwidgetmakers:widget:2.0.0を調整し、Widgetでのように見えるとし、その新しいリリースが行われ、:

public class Widget { 
    private Bark bark; 

    // constructor, getters, setters, etc. 
} 

だから今、私は私のアプリ、myappを構築するために行きます。そして、すべて私の依存関係の最新の安定バージョンを使用したい、私は(build.gradleの内側に)そうように私の依存関係を宣言します。

dependencies { 
    compile (
     ,'org.slf4j:slf4j-api:1.7.20' 
     ,'org.slf4j:slf4j-simple:1.7.20' 
     ,'bupo:fizzbuzz:3.7.14' 
     ,'commons-cli:commons-cli:1.2' 
     ,'widgetmakers:widget:2.0.0' 
    ) 
} 

さて、この(架空の)fizzbuzzライブラリは常にが依存しているとしましょう1.xバージョンのwidgetライブラリです(Widgetmeow)。

だから今、私は私のコンパイルクラスパス上widgetの2つのバージョンを指定しています:

  1. widgetmakers:widget:1.0.4それの依存関係として、fizzbuzzライブラリによって引き込まれます。そして、私はWidgetのバージョンが最初のクラスロードを取得しますこれに応じて、だから、明らかに直接

を参照しています

  • widgetmakers:widget:2.0.0は、我々はどちらかWidget#meowまたはWidget#barkを持つことになります。

    ここで私を助けてくれる施設は何ですか?同じクラスの複数のバージョンをプルする方法はありますか?fizzbuzzクラスをコンフィグレーションしてWidgetの古いバージョンを使用し、新しいバージョンを使用するようにクラスを設定しますか?そうでない場合、私は考えることができる唯一の解決策は以下のとおりです。

    1. 私はmyapp/bin下shading-および/または多分私はパッケージとしてすべての私の依存関係にプルfatjarベースsoltuion、いくつかの種類を達成することができるかもしれないとそれらに異なるバージョン接頭辞を与えます。確かに私はここにはっきりした解決策は見当たりませんが、何かが実現可能であることは確かです(しかし、まったくハッキー/厄介です)。または...
    2. 私の依存グラフ全体を慎重に調べて、私の過渡的な依存関係が互いに矛盾しないように注意してください。この場合は、fizzbuzzのメンテナにプルリクエストを送信して最新のwidgetバージョンにアップグレードするか、残念ながらmyappをダウングレードしてより古いバージョンのwidgetを使用することを意味します。

    でも、私にとって、グラッド(これまで)は魔法でした。だから私は頼んでいます:ここで私を助けることができる任意のGradleの魔法はありますか?

  • +0

    私は、同じライブラリの2つの異なるバージョンを適切に使用することができる唯一の方法は、自分自身またはライブラリによって必要とされる各バージョンを参照することです。そうでない場合は、Gradleが提供するバージョンに依存する必要があります。また、間違ったバージョンのクラス/メソッドが見つからない場合、例外が発生します。 Gradleは、見つからない依存関係を見つけ出して引き出すことができますが、Gradleの依存関係解決メカニズムを2つのライブラリと混同して手作業で破壊することは、長期的にはうまくいくものではありません。 –

    +0

    ありがとう@WeareBorg(+1)。 **(1)**あなた自身が必要としている場所であれライブラリであれ*各バージョンを参照する*と言うときは、もう少し詳しく説明できますか?私は10年以上の間、JVM開発者であり、この戦略/アプローチに精通していません!あなたが意味するものの例を挙げることができますか?そして、**(2)**この状況でのGradleのデフォルト動作は何ですか?そのまま残すと、 'widget'ライブラリのどのバージョンが最終的に検索/解決されますか?再度、感謝します! – smeeb

    +1

    1)私は単純なものを意味していましたが、特定のバージョンで必要としないライブラリを除外できるmavenの構文を知っていますので、他のバージョンは自動的に引き出されます。2)クラスパスの追加のためにgradleの場合は、リストの最初のものになります。これはmavenにとっては最新のものになります。 –

    答えて

    5

    私はMavenの人物だから、Gradleの詳細は分かりませんが、これはもっと一般的です。あなたは基本的に2つのオプションを持っています(そして、両方ともハッキーです):

    1. ClassLoader magic。どうにかして、ビルドシステムにライブラリの2つのバージョンをロードするように説得する必要があります(それに幸いです)。そして、実行時に古いバージョンを使用するクラスを、古いバージョンを持つClassLoaderでロードします。私はこれをしましたが、それは痛みです。 (OSGIのようなツールは、この痛みを取り除くかもしれません)
    2. パッケージシェーディング。ライブラリBの古いバージョンを使用するライブラリAを再パッケージ化します。その結果、Bは実際にはAの中にありますが、B固有のパッケージ接頭辞が付いています。これは一般的な慣行である。春出荷はits own version of asmです。 Maven側ではmaven-shade-pluginがこれを実行しますが、おそらくGradle相当のものがあります。または、瓶の操作の800ポンドのゴリラProGuardを使用することができます。
    +0

    これらのパスをすべて使い果たした後は、OSGIが動作しない場合はまずシェードのアプローチを試してから、最後にマニュアルクラスローダーの魔法を残すことになります。 – biziclop

    +0

    @biziclopええ私はそれが最も苦痛な方法だと同意します –

    +0

    粘着性の問題に最適な答えのようです。 – cjstehno

    2

    Gradleは依存関係をクラスパスに設定するだけで、依存関係とその推移的依存関係をカプセル化する独自のランタイムは提供しません。実行時にアクティブなバージョンは、クラスを格納するクラスパスの順序の最初のjarと思われるクラスローディング規則に従います。 OSGIはこのような状況に対応できるランタイムを提供し、今後のモジュールシステムも提供します。

    EDIT:Bjornは異なるバージョンの競合を解決しようとしています。その戦略に基づいてクラスパスをコンパイルするので、依存関係をファイルに置く順序は関係ありません。しかし、クラス名ごとに1つのクラスしか得られないので、OPの問題は解決しません。

    +1

    これは間違っています。 Gradleは、選択された競合解決戦略に基づいて競合を解決します。デフォルトでは、別の方法でGradleを設定しない限り、要求されたすべてのバージョンの最新バージョンを使用します。 g。エラーを出したり、特定の固定版などを使用することができます。バージョンを除いて座標が等しい限り、両方のバージョンをクラスパスに追加することはありません。 – Vampire

    0

    座標が等しくないライブラリのバージョンが異なる場合、Gradlesの競合解消メカニズムが有効になります。

    デフォルトの解決策は、ライブラリの最新バージョンを使用することです。依存関係グラフには、同じライブラリの複数のバージョンは用意されていません。

    実行時に同じライブラリの異なるバージョンが本当に必要な場合は、間違いなく可能なClassLoaderマジックを実行するか、ライブラリのいずれか、またはその両方に対して何らかのシェーディングを行う必要があります。

    Gradleには既定の最新の戦略が組み込まれています。異なるバージョンが依存関係グラフに含まれていて、ビルドファイルのバージョンの競合を明示的に解決する必要がある場合、失敗戦略が失敗します。

    0

    同じクラスが複数のジャーに表示されるケースはまれです。これはもっと狡猾です.CodahaleとDropwizardのメトリクスジャーを、2つのジャーに同じクラスの互換性のないバージョンで見てください。 gradle classpath-hellプラグインがこの恐怖を検出できます。

    関連する問題