Java Language
複数リリースのJARファイル
サーチ…
前書き
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