Java 9 incorporou a API em uma coleção de módulos. Portanto, a modularidade é o tema central; este projeto de programa afetado do nível superior. Os programas podem ser construídos modularmente desde o início. Não é surpresa que haverá APIs para lidar especificamente com o elemento de programação chamado módulo . As APIs fornecem uma maneira de acessar módulos programaticamente. Essas APIs são bastante úteis para obter informações específicas sobre os módulos ou para lê-los ou manipulá-los. Este artigo explora as classes de APIs de módulo e alguns dos métodos, com exemplos para dar uma ideia de sua funcionalidade geral.
Uma visão geral
O Java 9 fornece um conjunto de classes e interfaces para lidar com o módulo programaticamente. Essas APIs são particularmente úteis para:
- Módulos de leitura, carregamento e pesquisa
- Ler e manipular descritores de módulo
A lista de APIs é englobada principalmente nos pacotes:java.lang e java.lang.module . Embora o java.lang.module pacote consiste na maioria das classes e interfaces para lidar com descritores de módulo, o java.lang pacote contém classes Módulo , ModuleLayer , e uma exceção, LayerInstantiationException . Entre esses três, o Módulo classe é de importância primordial porque uma instância dessa classe fornece todos os métodos conectados a módulos de leitura, carregamento e pesquisa. A classe mais importante no java.lang.module pacote é o ModuleDescriptor . Esta classe fornece os métodos necessários para lidar com descritores de módulo.
API de módulos
De acordo com a documentação da API Java, a classe do módulo representa os módulos de tempo de execução nomeados e não nomeados. Módulos nomeados têm um nome e são construídos pela Java Virtual Machine quando um gráfico de módulos é definido para a Java Virtual Machine para criar uma camada de módulo. Um módulo sem nome não tem um nome. Existe um módulo sem nome para cada ClassLoader , obtido invocando seu getUnnamedModule método. Todos os tipos que não estão em um módulo nomeado são membros de seu módulo sem nome definidor do carregador de classes.
É simples descobrir o módulo de uma classe à qual ele pertence. Por exemplo, se quisermos descobrir o módulo de uma classe, digamos, ArrayList , da API Collection ou, digamos, Aplicativo da JavaFX, podemos fazê-lo da seguinte maneira.
Class<ArrayList> c= ArrayList.class; Module mod=c.getModule(); System.out.println(mod.getName());
Ou, em uma única declaração, como segue:
System.out.println(Application.class .getModule().getName());
Isso imprime o nome do módulo da classe, como java.base , para Lista de matrizes e javafx.graphics para Aplicativo . Como um módulo pode ser nomeado ou não nomeado, podemos descobrir invocando o método isNamed() método. Este método retorna true se o módulo for nomeado ou false se for um módulo sem nome. Aqui está um exemplo de módulos sem nome.
package org.mano.java9.examples; public class Main { public static void main(String[] args) { Class<Main> c= Main.class; Module mod=c.getModule(); System.out.println(mod); System.out.println(mod.getName()); System.out.println(mod.getName()+" is " +(mod.isNamed()? "Named Module":"Unnamed Module")); System.out.println(mod.getDescriptor()); } }
Saída:
unnamed module @4c75cab9 null null is Unnamed Module null
E, para módulos nomeados, podemos escrever da seguinte forma:
package org.mano.java9.examples; import java.util.ArrayList; public class Main { public static void main(String[] args) { Class<ArrayList> c= ArrayList.class; Module mod=c.getModule();< System.out.println(mod); System.out.println(mod.getName()); System.out.println(mod.getName()+" is " +(mod.isNamed()? "Named Module":"Unnamed Module")); System.out.println(mod.getDescriptor()); } }
Saída:
module java.base java.base java.base is Named Module module { name: [email protected], uses: [java.nio.file.spi.FileTypeDetector, ...}
Uma ModuleLayer contém apenas módulos nomeados. Podemos invocar o getLayer método para obter as informações sobre a camada que contém no módulo. Se retornar nulo, significa que o módulo não está em uma camada ou é um módulo sem nome. Se quisermos obter uma lista de pacotes disponíveis em um módulo, podemos invocar o método getPackages método. O getClassLoader retorna o carregador de classes do módulo. Aqui está um exemplo para ilustrar os métodos descritos acima.
package org.app.module1; import javafx.application.Application; import java.util.Set; public class Main { public static void main(String[] args) { Class<Application> c = Application.class; Module mod = c.getModule(); System.out.println("Name :" + mod.getName()); System.out.println(mod.getName() + " is " + (mod.isNamed() ? "Named Module" : "Unnamed Module")); System.out.println("Layer :" + mod.getLayer()); System.out.println("ClassLoader :" + mod.getClassLoader()); System.out.println("List of Packagesn....................."); Set<String> set = mod.getPackages(); int i=1; for (String s : set) { System.out.println(i+++") "+s); } } }
Saída:
Name :javafx.graphics javafx.graphics is Named Module Layer :jdk.compiler, java.compiler, jdk.management.jfr, jdk.scripting.nashorn, ... ClassLoader :jdk.internal.loader.ClassLoaders [email protected] .................... List of Packages ..................... 1) com.sun.javafx.stage 2) com.sun.scenario.effect.impl.prism.ps 3) javafx.print ... 107) com.sun.prism.j2d 108) javafx.scene.image
Descrição do módulo
De acordo com a documentação da API do Java 9, “Um descritor de módulo descreve um módulo nomeado e define métodos para obter cada um de seus componentes”. O descritor de módulo para um módulo nomeado na máquina virtual Java é obtido invocando o Módulo ‘s getDescriptor método. Descritores de módulo também podem ser criados usando o ModuleDescriptor.Builder class ou lendo a forma binária de uma declaração de módulo (module-info.class ) usando o ler métodos definidos nesta classe.
Portanto, normalmente o ModuleDescriptor instância representa a definição do módulo encontrada na forma binária do arquivo descritor do módulo, chamado module-info.class . Além de ler e manipular a definição do módulo, podemos usar o ModuleDescriptor.Builder class para descrever o módulo em tempo de execução.
Um descritor de módulo descreve três tipos de módulo, como módulos normais, abertos e automáticos.
Um módulo normal e um módulo aberto descrevem explicitamente os serviços que fornecem ou usam, dependências, pacotes exportados e outros componentes. A principal diferença entre um módulo normal e um módulo aberto é que Módulos normais podem abrir pacotes específicos. O descritor de módulo para um módulo aberto não declara nenhum pacote aberto (seu abre retorna um conjunto vazio), mas quando instanciado na máquina virtual Java, é tratado como se todos os pacotes estivessem abertos.
O módulo automático, no entanto, não declara nenhum pacote exportado, aberto ou dependência, exceto a declaração implícita do java.base módulo. Quando um módulo automático é instanciado na máquina virtual Java, ele lê cada módulo sem nome e é tratado como se todos os pacotes fossem exportados e abertos.
O getDescriptor método do Módulo A classe retorna uma instância do ModuleDescriptor aula. O ModuleDescriptor class contém classes aninhadas estáticas cuja instância representa a instrução de diretiva no arquivo de declaração do módulo. A classe, no entanto, não contém usos declaração que normalmente pode ser representada por uma instância de serviço String . Aqui estão os outros quatro:
- ModuleDescriptor.Requires
- ModuleDescriptor.Opens
- ModuleDescriptor.Provides
- ModuleDescriptor.Exports
Um exemplo rápido
package org.mano.java9.examples; import javax.sql.RowSet; import java.lang.module.ModuleDescriptor; import java.util.List; public class Main { public static void main(String[] args) { System.out.println("Module Name: " + List.class.getModule().getName()); show(List.class.getModule().getDescriptor()); System.out.println("Module Name: " + RowSet.class.getModule().getName()); show(RowSet.class.getModule().getDescriptor()); } public static void show(ModuleDescriptor d) { System.out.println("Module Descriptionn-------------------------"); System.out.println("Requires: " + d.requires()); System.out.println("Exports: " + d.exports()); System.out.println("Uses: " + d.uses()); System.out.println("Provides: " + d.provides()); System.out.println("Packages: " + d.packages()); } }
Saída:
Module Name: java.base Module Description ------------------------- Requires: [] Exports: [jdk.internal.org.objectweb.asm.signature to [jdk.scripting.nashorn], ...] Uses: [java.util.spi.LocaleNameProvider, java.nio.file.spi.FileSystemProvider, ...] Provides: [java.nio.file.spi.FileSystemProvider with [jdk.internal.jrtfs.JrtFileSystemProvider]] Packages: [java.nio.file, jdk.internal.org.objectweb.asm .tree.analysis, com.sun.security.ntlm, ...] Module Name: java.sql Module Description ------------------------- Requires: [mandated java.base, transitive java.logging, transitive java.xml] Exports: [java.sql, javax.transaction.xa, javax.sql] Uses: [java.sql.Driver] Provides: [] Packages: [javax.sql, javax.transaction.xa, java.sql]
O arquivo binário do descritor do módulo, chamado module-info.class , pode ser lido diretamente da seguinte maneira para criar uma instância do ModuleDescriptor aula:
try { ModuleDescriptor descriptor = ModuleDescriptor .read(new FileInputStream("module-info.class")); } catch (IOException ex) { }
Existem quatro versões da leitura estática sobrecarregada método definido no ModuleDescriptor aula. Eles são usados para ler a forma binária da descrição do módulo de um fluxo de entrada ou um buffer de bytes. Aqui está a extração da documentação da API do Java 9.
- read(InputStream in) :lê a forma binária de uma declaração de módulo de um fluxo de entrada como um descritor de módulo.
- read(InputStream in, Supplier
> packageFinder) :lê a forma binária de uma declaração de módulo de um fluxo de entrada como um descritor de módulo. - ler(ByteBuffer bb) :lê a forma binária de uma declaração de módulo de um buffer de bytes como um descritor de módulo.
- read(ByteBuffer bb, Supplier
> packageFinder) :lê a forma binária de uma declaração de módulo de um buffer de bytes como um descritor de módulo.
Os pacotes definidos por packageFinder incluem todos os pacotes que o módulo exporta, abre, serviços fornecidos e o pacote da classe principal que não são codificados pelo descritor fornecido no fluxo de entrada ou buffer de bytes.
Conclusão
Além de ler informações básicas sobre o módulo, o Módulo A classe fornece alguns métodos-chave para consultar o status do módulo - se ele foi lido, aberto, exportado e assim por diante. A API também fornece métodos como addOpens , adicionarExportar , addUses e addReads para adicionar usos de abertura e exportação e instruções de leitura ao descritor de módulos programaticamente. Em poucas palavras, a API Module fornece muitos outros métodos para lidar especificamente com módulos programaticamente. Aqui, apenas arranhamos a superfície para dar uma ideia inicial do que se trata.