Рубрики
Без рубрики

Java 9 java.lang.API модуля

Узнайте, как использовать java.lang.API модуля

Автор оригинала: Carlo Corti.

1. введение

Следующее Руководство по модульности Java 9 , в этой статье мы рассмотрим java.lang.Модуль API, который был представлен вместе с системой модулей платформы Java.

Этот API предоставляет способ программного доступа к модулю, получения конкретной информации из модуля и, как правило, работы с ним и его Модулем дескриптором .

2. Чтение Информации о Модуле

Класс Module представляет как именованные, так и неназванные модули. Именованные модули имеют имя и создаются виртуальной машиной Java при создании слоя модулей, используя граф модулей в качестве определения.

У неназванного модуля нет имени, и для каждого загрузчика классов есть одно имя. Все типы, которые не входят в именованный модуль, являются членами неназванного модуля, связанного с их загрузчиком классов.

Интересная часть класса Module заключается в том, что он предоставляет методы, которые позволяют нам извлекать информацию из модуля, такую как имя модуля, загрузчик классов модуля и пакеты внутри модуля.

Давайте посмотрим, как можно узнать, является ли модуль именованным или безымянным.

2.1. По имени или без имени

Используя метод renamed () , мы можем определить, является ли модуль именованным или нет.

Давайте посмотрим, как мы можем увидеть , является ли данный класс, например HashMap , частью именованного модуля и как мы можем получить его имя:

Class hashMapClass = HashMap.class;
Module javaBaseModule = hashMapClass.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 частью именованного модуля:

Class personClass = Person.class;
Module module = personClass.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. Загрузчик классов

Благодаря методу getClassLoader () , доступному в классе Module , мы можем получить ClassLoader для данного модуля:

assertThat(
  module.getClassLoader().getClass().getName(), 
  is("jdk.internal.loader.ClassLoaders$AppClassLoader")
);

2.5. Слой

Еще одной ценной информацией , которую можно извлечь из модуля, является ModuleLayer , представляющий слой модулей в виртуальной машине Java.

Уровень модуля информирует JVM о классах, которые могут быть загружены из модулей. Таким образом, JVM точно знает, в какой модуль входит каждый класс.

ModuleLayer содержит информацию, связанную с его конфигурацией, родительским слоем и набором модулей, доступных в слое.

Давайте посмотрим, как получить слой модуля данного модуля:

ModuleLayer javaBaseModuleLayer = javaBaseModule.getLayer();

Как только мы извлекли слой Модуля , мы можем получить доступ к его информации:

assertTrue(javaBaseModuleLayer.configuration().findModule("jaa.base").isPresent());

Особым случаем является загрузочный уровень, созданный при запуске виртуальной машины Java. Загрузочный слой-это единственный слой, содержащий модуль java.base .

3. Работа С ModuleDescriptor

A Модульный дескриптор описывает именованный модуль и определяет методы для получения каждого из его компонентов.

Объекты дескриптора модуля являются неизменяемыми и безопасными для использования несколькими параллельными потоками.

Давайте начнем с рассмотрения того, как мы можем получить дескриптор модуля .

3.1. Получение дескриптора модуля

Поскольку дескриптор модуля тесно связан с модулем , его можно получить непосредственно из Модуля:

ModuleDescriptor moduleDescriptor = javaBaseModule.getDescriptor();

3.2. Создание дескриптора модуля

Также можно создать дескриптор модуля с помощью дескриптора Module.Builder class или, прочитав двоичную форму объявления модуля, module-info.class .

Давайте посмотрим, как мы создаем дескриптор модуля, используя дескриптор Module.Конструктор API:

ModuleDescriptor.Builder moduleBuilder = ModuleDescriptor
  .newModule("baeldung.base");

ModuleDescriptor moduleDescriptor = moduleBuilder.build();

assertThat(moduleDescriptor.name(), is("baeldung.base"));

С помощью этого мы создали обычный модуль, но в случае, если мы хотим создать открытый модуль или автоматический, мы можем соответственно использовать метод newOpenModule() или newAutomaticModule () .

3.3. Классификация модуля

Дескриптор модуля описывает обычный, открытый или автоматический модуль.

Благодаря методу , доступному в дескрипторе модуля , можно определить тип модуля:

ModuleDescriptor moduleDescriptor = javaBaseModule.getDescriptor();

assertFalse(moduleDescriptor.isAutomatic());
assertFalse(moduleDescriptor.isOpen());

3.4. Извлечение Требует

С помощью дескриптора модуля можно получить набор Requires , представляющий зависимости модуля.

Это возможно с помощью метода requires() :

Set javaBaseRequires = javaBaseModule.getDescriptor().requires();
Set javaSqlRequires = javaSqlModule.getDescriptor().requires();

Set 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 javaBaseProvides = javaBaseModule.getDescriptor().provides();
Set javaSqlProvides = javaSqlModule.getDescriptor().provides();

Set javaBaseProvidesService = javaBaseProvides.stream()
  .map(Provides::service)
  .collect(Collectors.toSet());

assertThat(
  javaBaseProvidesService, 
  contains("java.nio.file.spi.FileSystemProvider")
);
assertThat(javaSqlProvides, empty());

3.6. Получение Экспорта

Используя метод exports () , мы можем выяснить, экспортируют ли модули пакеты и какие именно:

Set javaSqlExports = javaSqlModule.getDescriptor().exports();

Set javaSqlExportsSource = javaSqlExports.stream()
  .map(Exports::source)
  .collect(Collectors.toSet());

assertThat(
  javaSqlExportsSource, 
  containsInAnyOrder("java.sql","javax.transaction.xa", "javax.sql")
);

В частном случае, если модуль является автоматическим, набор экспортированных пакетов будет пустым.

3.7. Извлечение использований

С помощью метода uses() можно получить набор служебных зависимостей модуля:

Set javaSqlUses = javaSqlModule.getDescriptor().uses();

assertThat(javaSqlUses, contains("java.sql.Driver"));

В случае, если модуль является автоматическим, набор зависимостей будет пустым.

3.8. Получение открытий

Всякий раз, когда мы хотим получить список открытых пакетов модуля, мы можем использовать метод opens() :

Set javaBaseUses = javaBaseModule.getDescriptor().opens();
Set javaSqlUses = javaSqlModule.getDescriptor().opens();

assertThat(javaBaseUses, empty());
assertThat(javaSqlUses, empty());

Набор будет пустым, если модуль является открытым или автоматическим.

4. Работа С Модулями

Работа с модулем API, помимо считывания информации из модуля, мы можем обновить определение модуля.

4.1. Добавление Экспорта

Давайте посмотрим, как мы можем обновить модуль, экспортируя данный пакет из данного модуля:

Module updatedModule = module.addExports(
  "com.baeldung.java9.modules", javaSqlModule);

assertTrue(updatedModule.isExported("com.baeldung.java9.modules"));

Это может быть сделано только в том случае, если модуль вызывающего абонента является модулем, членом которого является код.

В качестве примечания, нет никаких эффектов, если пакет уже экспортирован модулем или если модуль является открытым.

4.2. Добавление считываний

Когда мы хотим обновить модуль для чтения данного модуля, мы можем использовать метод address() :

Module updatedModule = module.addReads(javaSqlModule);

assertTrue(updatedModule.canRead(javaSqlModule));

Этот метод ничего не делает, если мы добавим сам модуль, так как все модули читают сами себя.

Точно так же этот метод ничего не делает, если модуль является неназванным модулем или этот модуль уже читает другой.

4.3. Добавление Открывает

Когда мы хотим обновить модуль, который открыл пакет, по крайней мере, до вызывающего модуля, мы можем использовать add Opens () , чтобы открыть пакет для другого модуля:

Module updatedModule = module.addOpens(
  "com.baeldung.java9.modules", javaSqlModule);

assertTrue(updatedModule.isOpen("com.baeldung.java9.modules", javaSqlModule));

Этот метод не имеет никакого эффекта, если пакет уже открыт для данного модуля.

4.4. Добавление видов использования

Всякий раз, когда мы хотим обновить модуль, добавляя зависимость от службы, мы выбираем метод adduced() :

Module updatedModule = module.addUses(Driver.class);

assertTrue(updatedModule.canUse(Driver.class));

Этот метод ничего не делает при вызове на безымянном модуле или автоматическом модуле.

5. Заключение

В этой статье мы исследовали использование java.lang.Модуль API, где мы узнали, как получить информацию о модуле, как использовать ModuleDescriptor для доступа к дополнительной информации о модуле и как манипулировать ею.

Как всегда, все примеры кода в этой статье можно найти на GitHub .