Database
 sql >> Base de Dados >  >> RDS >> Database

Explorando as APIs de módulo no Java 9


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.