サーチ…


前書き

Java 9で導入された機能の1つは、同じJarファイル内の複数のJavaリリースをターゲットとするコードをバンドルできるマルチリリースJar(MRJAR)です。この機能は、 JEP 238で指定されています。

マルチリリースJarファイルの内容の例

MANIFEST.MFファイルでMulti-Release: true設定すると、JarファイルはマルチリリースJarになり、Javaランタイムは(MRJAR形式をサポートしている限り)現在のメジャーバージョンに応じて適切なバージョンのクラスを選択します。

このようなJarの構造は次のとおりです。

jar root
  - A.class
  - B.class
  - C.class
  - D.class
  - META-INF
     - versions
        - 9
           - A.class
           - B.class
        - 10
           - A.class
  • JDK <9では、ルートエントリのクラスのみがJavaランタイムに表示されます。
  • JDK 9では、クラスAとBはroot/META-INF/versions/9ディレクトリroot/META-INF/versions/9からロードされ、CとDはベースエントリからロードされます。
  • JDK 10では、クラスAはroot/META-INF/versions/10ディレクトリからロードされます。

jarツールを使用してマルチリリースJarを作成する

jarコマンドを使用すると、Java 8とJava 9の両方でコンパイルされた同じクラスの2つのバージョンを含むマルチリリースJarを作成できますが、クラスが同じであることを示す警告が表示されます。

C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demo
Warning: entry META-INF/versions/9/demo/SampleClass.class contains a class that
is identical to an entry already in the jar

--release 9オプションは、MRJARのバージョン化されたエントリ、つまりroot/META-INF/versions/9下にjarに続くすべてのもの( sampleproject-9ディレクトリ内のdemoパッケージ)を含めるように指示します。結果は次の内容です。

jar root
  - demo
     - SampleClass.class
  - META-INF
     - versions
        - 9
           - demo
              - SampleClass.class

SampleClassのURLを出力し、Java 9バージョン用に追加するMainというクラスを作成しましょう。

package demo;

import java.net.URL;

public class Main {

    public static void main(String[] args) throws Exception {
        URL url = Main.class.getClassLoader().getResource("demo/SampleClass.class");
        System.out.println(url);
    }
}

このクラスをコンパイルしてjarコマンドを再実行すると、エラーが発生します。

C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demoentry: META-INF/versions/9/demo/Main.class, contains a new public class not found in base entries
Warning: entry META-INF/versions/9/demo/Main.java, multiple resources with same name
Warning: entry META-INF/versions/9/demo/SampleClass.class contains a class that
is identical to an entry already in the jar
invalid multi-release jar file MR.jar deleted

その理由は、 jarツールは、ベースエントリにも追加されていない場合でも、パブリッククラスをバージョン管理されたエントリに追加することを防ぐためです。これは、MRJARが異なるJavaバージョン用の同じ公開APIを公開するように行われます。実行時には、このルールは必須ではありません。それは、 jarようなツールによってのみ適用されるかもしれません。この特定のケースでは、 Mainの目的はサンプルコードを実行することで、基本エントリにコピーを追加するだけです。クラスがJava 9に必要な新しい実装の一部であれば、非公開にすることができます。

Mainをルートエントリに追加するには、最初にJava 9より前のリリースを対象にコンパイルする必要があります。これは、 javac新しい--releaseオプションを使用して行うことができます。

C:\Users\manouti\sampleproject-base\demo>javac --release 8 Main.java
C:\Users\manouti\sampleproject-base\demo>cd ../..
C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demo

Mainクラスを実行すると、SampleClassがバージョン管理されたディレクトリからロードされます。

C:\Users\manouti>java --class-path MR.jar demo.Main
jar:file:/C:/Users/manouti/MR.jar!/META-INF/versions/9/demo/SampleClass.class

マルチリリースJar内のロー​​ドされたクラスのURL

次のマルチリリースのJarがあるとします。

jar root
  - demo
     - SampleClass.class
  - META-INF
     - versions
        - 9
           - demo
              - SampleClass.class

次のクラスは、 SampleClassのURLを出力します。

package demo;

import java.net.URL;

public class Main {

    public static void main(String[] args) throws Exception {
        URL url = Main.class.getClassLoader().getResource("demo/SampleClass.class");
        System.out.println(url);
    }
}

クラスがコンパイルされ、Java 9のバージョン管理されたエントリにMRJARで追加された場合、実行すると次のようになります。

C:\Users\manouti>java --class-path MR.jar demo.Main
jar:file:/C:/Users/manouti/MR.jar!/META-INF/versions/9/demo/SampleClass.class


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow