Java9java.lang.ModuleAPI
1. 序章
Java 9モジュール性のガイドに続いて、この記事では、Javaプラットフォームと一緒に導入された java .lang.ModuleAPIについて説明します。モジュールシステム。
このAPIは、プログラムでモジュールにアクセスし、モジュールから特定の情報を取得し、通常はモジュールとその Module Descriptorを操作する方法を提供します。
2. モジュール情報の読み取り
Module クラスは、名前付きモジュールと名前なしモジュールの両方を表します。 名前付きモジュールには名前があり、モジュールのグラフを定義として使用して、モジュール層を作成するときにJava仮想マシンによって構築されます。
名前のないモジュールには名前がなく、ClassLoaderごとに1つあります。名前の付いたモジュールにないすべてのタイプは、クラスローダーに関連する名前のないモジュールのメンバーです。
Module クラスの興味深い部分は、モジュール名、モジュールクラスローダー、モジュール内のパッケージなど、モジュールから情報を取得できるようにするメソッドを公開することです。
モジュールに名前が付けられているか、名前が付けられていないかを確認する方法を見てみましょう。
2.1. 名前付きまたは名前なし
isNamed()メソッドを使用して、モジュールに名前が付けられているかどうかを識別できます。
HashMap のような特定のクラスが名前付きモジュールの一部であるかどうかを確認する方法と、その名前を取得する方法を見てみましょう。
Module javaBaseModule = HashMap.class.getModule();
assertThat(javaBaseModule.isNamed(), is(true));
assertThat(javaBaseModule.getName(), is("java.base"));
次に、Personクラスを定義しましょう。
public class Person {
private String name;
// constructor, getters and setters
}
同様に、 HashMap クラスの場合と同様に、Personクラスが名前付きモジュールの一部であるかどうかを確認できます。
Module module = Person.class.getModule();
assertThat(module.isNamed(), is(false));
assertThat(module.getName(), is(nullValue()));
2.2. パッケージ
モジュールを操作するときは、モジュール内で使用できるパッケージを知ることが重要な場合があります。
特定のパッケージ、たとえば java.lang.annotationが特定のモジュールに含まれているかどうかを確認する方法を見てみましょう。
assertTrue(javaBaseModule.getPackages().contains("java.lang.annotation"));
assertFalse(javaBaseModule.getPackages().contains("java.sql"));
2.3. 注釈
同様に、パッケージの場合、 getAnnotations()メソッドを使用して、モジュールに存在する注釈を取得することができます。
名前付きモジュールに注釈が存在しない場合、メソッドは空の配列を返します。
java.baseモジュールに存在する注釈の数を見てみましょう。
assertThat(javaBaseModule.getAnnotations().length, is(0));
名前のないモジュールで呼び出されると、 getAnnotations()メソッドは空の配列を返します。
2.4. ClassLoader
Moduleクラス内で使用可能なgetClassLoader()メソッドのおかげで、特定のモジュールのClassLoaderを取得できます。
assertThat(
module.getClassLoader().getClass().getName(),
is("jdk.internal.loader.ClassLoaders$AppClassLoader")
);
2.5. 層
モジュールから抽出できるもう1つの貴重な情報は、 ModuleLayer です。これは、Java仮想マシンのモジュールのレイヤーを表します。
モジュール層は、モジュールからロードされる可能性のあるクラスについてJVMに通知します。 このようにして、JVMは各クラスがどのモジュールのメンバーであるかを正確に認識します。
ModuleLayer には、その構成、親レイヤー、およびレイヤー内で使用可能なモジュールのセットに関連する情報が含まれています。
特定のモジュールのModuleLayerを取得する方法を見てみましょう。
ModuleLayer javaBaseModuleLayer = javaBaseModule.getLayer();
ModuleLayer を取得すると、その情報にアクセスできます。
assertTrue(javaBaseModuleLayer.configuration().findModule("java.base").isPresent());
特殊なケースは、Java仮想マシンの起動時に作成されるブートレイヤーです。 ブートレイヤーは、java.baseモジュールを含む唯一のレイヤーです。
3. ModuleDescriptorの処理
ModuleDescriptor は、名前付きモジュールを記述し、その各コンポーネントを取得するためのメソッドを定義します。
ModuleDescriptor オブジェクトは不変であり、複数の同時スレッドで安全に使用できます。
ModuleDescriptorを取得する方法を見てみましょう。
3.1. ModuleDescriptorを取得しています
ModuleDescriptorはModuleに緊密に接続されているため、 Module:から直接取得できます。
ModuleDescriptor moduleDescriptor = javaBaseModule.getDescriptor();
3.2. ModuleDescriptorの作成
ModuleDescriptor.Builderクラスを使用するか、モジュール宣言のバイナリ形式 module-info.class を読み取ることにより、モジュール記述子を作成することもできます。
ModuleDescriptor.BuilderAPIを使用してモジュール記述子を作成する方法を見てみましょう。
ModuleDescriptor.Builder moduleBuilder = ModuleDescriptor
.newModule("baeldung.base");
ModuleDescriptor moduleDescriptor = moduleBuilder.build();
assertThat(moduleDescriptor.name(), is("baeldung.base"));
これで通常のモジュールを作成しましたが、オープンモジュールまたは自動モジュールを作成する場合は、それぞれ newOpenModule()または newAutomaticModule()メソッドを使用できます。
3.3. モジュールの分類
モジュール記述子は、通常、オープン、または自動モジュールを記述します。
ModuleDescriptor 内で使用可能なメソッドのおかげで、モジュールのタイプを識別することができます。
ModuleDescriptor moduleDescriptor = javaBaseModule.getDescriptor();
assertFalse(moduleDescriptor.isAutomatic());
assertFalse(moduleDescriptor.isOpen());
3.4. 取得が必要
モジュール記述子を使用すると、モジュールの依存関係を表すRequiredsのセットを取得できます。
これは、 require()メソッドを使用して可能です。
Set<Requires> javaBaseRequires = javaBaseModule.getDescriptor().requires();
Set<Requires> javaSqlRequires = javaSqlModule.getDescriptor().requires();
Set<String> javaSqlRequiresNames = javaSqlRequires.stream()
.map(Requires::name)
.collect(Collectors.toSet());
assertThat(javaBaseRequires, empty());
assertThat(javaSqlRequiresNames, hasItems("java.base", "java.xml", "java.logging"));
java。baseを除くすべてのモジュールには、依存関係としてjava。baseモジュールがあります。
ただし、モジュールが自動モジュールの場合、 java.base を除いて、依存関係のセットは空になります。
3.5. 提供物の取得
provides()メソッドを使用すると、モジュールが提供するサービスのリストを取得できます。
Set<Provides> javaBaseProvides = javaBaseModule.getDescriptor().provides();
Set<Provides> javaSqlProvides = javaSqlModule.getDescriptor().provides();
Set<String> javaBaseProvidesService = javaBaseProvides.stream()
.map(Provides::service)
.collect(Collectors.toSet());
assertThat(javaBaseProvidesService, hasItem("java.nio.file.spi.FileSystemProvider"));
assertThat(javaSqlProvides, empty());
3.6. エクスポートの取得
exports()メソッドを使用して、モジュールがパッケージをエクスポートするかどうか、特に次のいずれかを確認できます。
Set<Exports> javaSqlExports = javaSqlModule.getDescriptor().exports();
Set<String> javaSqlExportsSource = javaSqlExports.stream()
.map(Exports::source)
.collect(Collectors.toSet());
assertThat(javaSqlExportsSource, hasItems("java.sql", "javax.sql"));
特別な場合として、モジュールが自動モジュールの場合、エクスポートされたパッケージのセットは空になります。
3.7. 使用の取得
used()メソッドを使用すると、モジュールのサービス依存関係のセットを取得できます。
Set<String> javaSqlUses = javaSqlModule.getDescriptor().uses();
assertThat(javaSqlUses, hasItem("java.sql.Driver"));
モジュールが自動モジュールの場合、依存関係のセットは空になります。
3.8. オープンの取得
モジュールの開いているパッケージのリストを取得するときはいつでも、 opens()メソッドを使用できます。
Set<Opens> javaBaseUses = javaBaseModule.getDescriptor().opens();
Set<Opens> javaSqlUses = javaSqlModule.getDescriptor().opens();
assertThat(javaBaseUses, empty());
assertThat(javaSqlUses, empty());
モジュールがオープンまたは自動の場合、セットは空になります。
4. モジュールの取り扱い
Module APIを使用すると、モジュールから情報を読み取る以外に、モジュール定義を更新できます。
4.1. エクスポートの追加
特定のモジュールから特定のパッケージをエクスポートして、モジュールを更新する方法を見てみましょう。
Module updatedModule = module.addExports(
"com.baeldung.java9.modules", javaSqlModule);
assertTrue(updatedModule.isExported("com.baeldung.java9.modules"));
これは、呼び出し元のモジュールがコードがメンバーであるモジュールである場合にのみ実行できます。
ちなみに、パッケージがモジュールによってすでにエクスポートされている場合、またはモジュールが開いている場合は、影響はありません。
4.2. 読み取りの追加
特定のモジュールを読み取るようにモジュールを更新する場合は、 addReads()メソッドを使用できます。
Module updatedModule = module.addReads(javaSqlModule);
assertTrue(updatedModule.canRead(javaSqlModule));
すべてのモジュールが自分自身を読み取るため、モジュール自体を追加しても、このメソッドは何もしません。
同様に、モジュールが名前のないモジュールである場合、またはこのモジュールがすでに他のモジュールを読み取っている場合、このメソッドは何もしません。
4.3. オープンの追加
パッケージを開いたモジュールを少なくとも呼び出し元モジュールに更新する場合は、 addOpens()を使用してパッケージを別のモジュールに開くことができます。
Module updatedModule = module.addOpens(
"com.baeldung.java9.modules", javaSqlModule);
assertTrue(updatedModule.isOpen("com.baeldung.java9.modules", javaSqlModule));
パッケージが特定のモジュールに対してすでに開いている場合、このメソッドは効果がありません。
4.4. 用途の追加
サービスの依存関係を追加するモジュールを更新する場合は常に、メソッド addUses()を選択します。
Module updatedModule = module.addUses(Driver.class);
assertTrue(updatedModule.canUse(Driver.class));
名前のないモジュールまたは自動モジュールで呼び出された場合、このメソッドは何もしません。
5. 結論
この記事では、 java.lang.Module APIの使用方法について説明し、モジュールの情報を取得する方法、ModuleDescriptorを使用してモジュールとその操作方法。
いつものように、この記事のすべてのコード例は、GitHubのにあります。