2016-11-14 14 views
2

"p1.jar"、 "p2.jar"などのプロジェクトがあり、それらはすべてライブラリ "foo-1.0.0.jar"を使用しているとします。java:jarのバージョン間で互換性を確認する

新しいバージョン "foo-1.0.1.jar"が作成されているものとします。追加のチェックとして、すべてのプロジェクトp1、p2、...が新しいfoo-1.0.1.jarを使用して再コンパイルされます。コンパイルエラーは表示されません。

ここで、本番環境では、foo-1.0.0.jarはfoo-1.0.1.jarに置き換えられました。 p1.jar、p2.jar、...の更新は行われません。残念ながら、すべてがクラッシュします。

新しいライブラリが古いものに置き換わる可能性は100%であることを他のチェックで確認できますか?

明らかに、新しいライブラリに導入されたコードエラーのチェックや機能の変更については言及していません(たとえば、新しいバージョンの関数「sum」が加算ではなく減算を行う場合)。しかし、少なくとも引数の変化、その結果、使用可能なクラスなど

一例をチェックし、FOO-1.0.0.jarは、メソッドが含まれます:

int m1() { 
    // some code 
    return 0; // always return 0, and ignored by the users 
} 

にそれが変更されたのfoo-1.0.1ということをTo:

void m1() { 
    // some code 
} 

残念ながら、この方法の結果は「int型M1()」を探していたときに、「NoSuchMethod」例外で失敗します(ないCで)Javaでマングル名とp1.jarの一部です。あなたがfoo-1.0.0を持っている場合jar x

  • javap
  • でクラスの内容を取得し、古いものと新しい

  • +0

    あなたの投稿をもう一度読んだ後。メソッドのシグネチャのみをチェックしたい場合は、コンパイル時に互換性のない変更があるかどうかを、新しいライブラリに対する単純なコンパイルによって知ることができます。しかし、このような弱い点検で何を達成したいのですか?エラーなしでコンパイルすると、実行時に失敗しないという保証はありません。 – SubOptimal

    +0

    @SubOptimal:正確には、ランタイム互換性の保証が対象です。 –

    +0

    ランタイムの互換性が必要な場合は、私の投稿された回答を参照してください。最も安全な方法は、新しいバージョンでテストコードを実行することです。 – SubOptimal

    答えて

    1
    1. 開梱両方のjarファイルは、たとえば、2瓶

    から内容を比較します。 jar、foo-1.0.1.jarをカレントディレクトリに置いた場合、このbashスクリプトを実行することができます:

    # unpack old jar 
    mkdir foo-1.0.0 
    cd foo-1.0.0 
    jar xf ../foo-1.0.0.jar 
    # unpack new jar 
    mkdir ../foo-1.0.1 
    cd ../foo-1.0.1 
    jar xf ../foo-1.0.1.jar 
    # get unpacked classes contents 
    cd .. 
    for file in `find foo-1.0.0 foo-1.0.1 -name '*.class'`; do javap $file > $file.txt; done 
    # remove redundant .class files 
    find foo-1.0.0 foo-1.0.1 -name '*.class' | xargs rm 
    # compare jar contents 
    diff -r foo-1.0.0 foo-1.0.1 
    

    もちろん、それは完全に自動化された方法ではありませんが、あなたは手動でdiff出力をチェックする必要があります。それでも、何もないよりも優れています。

    2

    japicmpを使用して、APIの変更に関する新旧のライブラリアーカイブを比較することができます。

    ただし、確認するライブラリの依存関係が検出されないというリスクがあります。

    検出されない可能性のある変更を示す例を以下に示します。

    ApiClass1.java

    class ApiClass { 
        public static final int FOO = 23; 
        public static void version() { 
         System.out.println("version 1 FOO: " + FOO); 
        } 
    } 
    

    ApiClass2.java

    class ApiClass { 
        public static final int FOO = 42; 
        public static void version() { 
         System.out.println("version 2 FOO: " + FOO); 
        } 
    } 
    

    ApiDemo。Javaの

    class ApiDemo { 
        public static void main(String...args) { 
         ApiClass.version(); 
         System.out.println("ApiClass.FOO: " + ApiClass.FOO); 
        } 
    } 
    
    • コンパイルおよびAPIバージョン1

      javac ApiClass1.java 
      jar cf api_v1.jar ApiClass.class 
      
    • コンパイルのためのライブラリーを構築し、APIバージョン2

      javac ApiClass2.java 
      jar cf api_v2.jar ApiClass.class 
      
    • コンパイルのためのライブラリーを構築し、ビルドして実行あなたAPI v1のコード

      javac -cp api_v1.jar ApiDemo.java 
      java -cp api_v1.jar:. ApiDemo 
      

      出力

      version 1 FOO: 23 
      ApiClass.FOO: 23 
      
    • 唯一の信頼できる方法が実行されるすべて、新バージョンに対するあなたのコードをコンパイルすることで、再コンパイル

      java -cp api_v2.jar:. ApiDemo 
      
      version 2 FOO: 42 
      ApiClass.FOO: 23 
      

    せずに、API v2のでコードを実行ユニット/統合テストを行い、合格したかどうかを確認してください。

    +0

    答えをありがとう。実行例では、2行の出力が表示されますが、コード例では1つの "println"が表示されていますか? –

    +0

    @pasabaporaqui情報をいただきありがとうございます。修正されました。 – SubOptimal

    +0

    申し訳ありません、コンパイラは "シンボルメソッドのバージョン()を見つけることができません" –