sql >> Base de Datos >  >> RDS >> Database

Explorando las API del módulo en Java 9

Java 9 incorporó la API en una colección de módulos. Por lo tanto, la modularidad es el tema central; esto afectó el diseño del programa desde el nivel superior. Los programas se pueden construir modularmente desde el principio. No sorprende que habrá API para tratar específicamente con el elemento de programación llamado módulo . Las API proporcionan una forma de acceder a los módulos mediante programación. Estas API son bastante útiles para obtener información específica sobre los módulos o para leerlos o manipularlos. Este artículo explora las clases de las API del módulo y algunos de los métodos, con ejemplos para darle una idea de su funcionalidad general.

Una visión general

Java 9 proporciona un conjunto de clases e interfaces para manejar el módulo mediante programación. Estas API son particularmente útiles para:

  • Lectura, carga y búsqueda de módulos
  • Lectura y manipulación de descriptores de módulos

La lista de API se engloba principalmente en paquetes:java.lang y java.lang.module . Aunque el java.lang.module El paquete consta de la mayoría de las clases e interfaces para manejar los descriptores de módulos, el java.lang el paquete contiene clases Módulo , capa de módulo y una excepción, LayerInstantiationException . Entre estos tres, el Módulo La clase es de primordial importancia porque una instancia de esta clase proporciona todos los métodos conectados a los módulos de lectura, carga y búsqueda. La clase más importante en java.lang.module el paquete es el ModuleDescriptor . Esta clase proporciona los métodos necesarios para manejar los descriptores de módulos.

API de módulos

De acuerdo con la documentación de la API de Java, la clase de módulo representa módulos de tiempo de ejecución con nombre y sin nombre. Los módulos con nombre tienen un nombre y son construidos por la máquina virtual de Java cuando se define un gráfico de módulos en la máquina virtual de Java para crear una capa de módulo. Un módulo sin nombre no tiene nombre. Hay un módulo sin nombre para cada ClassLoader , obtenido invocando su getUnnamedModule método. Todos los tipos que no están en un módulo con nombre son miembros del módulo sin nombre del cargador de clases que los define.

Es sencillo averiguar el módulo de una clase a la que pertenece. Por ejemplo, si queremos averiguar el módulo de una clase, digamos, ArrayList , desde la API de colección o, por ejemplo, Aplicación de JavaFX, podemos hacerlo de la siguiente manera.

Class<ArrayList> c= ArrayList.class;
Module mod=c.getModule();
System.out.println(mod.getName());

O, en una sola declaración, como sigue:

System.out.println(Application.class
   .getModule().getName());

Esto imprime el nombre del módulo de la clase, como java.base , para Lista de arreglos y javafx.gráficos para Solicitud . Debido a que un módulo puede tener nombre o no, podemos averiguarlo invocando isNamed() método. Este método devuelve verdadero si el módulo tiene nombre o falso si es un módulo sin nombre. Este es un ejemplo de módulos sin nombre.

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());
   }
}

Salida:

unnamed module @4c75cab9
null
null is Unnamed Module
null

Y, para los módulos con nombre, podemos escribir lo siguiente:

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());
   }
}

Salida:

module java.base
java.base
java.base is Named Module
module { name: [email protected], uses:
   [java.nio.file.spi.FileTypeDetector, ...}

Una capa de módulo contiene solo módulos con nombre. Podemos invocar el getLayer método para obtener la información sobre la capa que contiene en el módulo. Si devuelve nulo, significa que el módulo no está en una capa o es un módulo sin nombre. Si queremos obtener una lista de paquetes disponibles en un módulo, podemos invocar el getPackages método. El getClassLoader El método devuelve el cargador de clases del módulo. Aquí hay un ejemplo para ilustrar los métodos descritos anteriormente.

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);
      }
   }
}

Salida:

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

Descripción del módulo

Según la documentación de la API de Java 9, "un descriptor de módulo describe un módulo con nombre y define métodos para obtener cada uno de sus componentes". El descriptor de módulo para un módulo con nombre en la máquina virtual Java se obtiene invocando el Módulo 's getDescriptor método. Los descriptores de módulos también se pueden crear usando el ModuleDescriptor.Builder class o leyendo la forma binaria de una declaración de módulo (module-info.class ) usando el leer métodos definidos en esta clase.

Por lo tanto, normalmente el ModuleDescriptor instancia representa la definición del módulo que se encuentra en formato binario del archivo descriptor del módulo, llamado module-info.class . Además de leer y manipular la definición del módulo, podemos usar el ModuleDescriptor.Builder class para describir el módulo en tiempo de ejecución.

Un descriptor de módulo describe tres tipos de módulos, como módulos normales, abiertos y automáticos.

Un módulo normal y otro abierto describen explícitamente los servicios que proporcionan o usan, las dependencias, los paquetes exportados y otros componentes. La principal diferencia entre un módulo normal y un módulo abierto es que Los módulos normales pueden abrir paquetes específicos. El descriptor de módulo para un módulo abierto no declara ningún paquete abierto (su abre devuelve un conjunto vacío), pero cuando se crea una instancia en la máquina virtual de Java, se trata como si todos los paquetes estuvieran abiertos.

Sin embargo, el módulo automático no declara ningún paquete exportado, abierto ni dependencias, excepto la declaración implícita de java.base módulo. Cuando se crea una instancia de un módulo automático en la máquina virtual de Java, lee todos los módulos sin nombre y se trata como si todos los paquetes estuvieran exportados y abiertos.

El getDescriptor método del Módulo la clase devuelve una instancia de ModuleDescriptor clase. El ModuleDescriptor class contiene clases anidadas estáticas cuya instancia representa la declaración de directiva en el archivo de declaración del módulo. La clase, sin embargo, no contiene usos declaración que normalmente se puede representar mediante una instancia de servicio String . Aquí están esos otros cuatro:

  • ModuleDescriptor.Requiere
  • ModuleDescriptor.Abre
  • ModuleDescriptor.Proporciona
  • ModuleDescriptor.Exportaciones

Un ejemplo 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());
   }
}

Salida:

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]

El archivo binario del descriptor del módulo, llamado module-info.class , se puede leer directamente de la siguiente manera para crear una instancia de ModuleDescriptor clase:

try {
   ModuleDescriptor descriptor = ModuleDescriptor
      .read(new FileInputStream("module-info.class"));
} catch (IOException ex) { }

Hay cuatro versiones de la lectura estática sobrecargada método definido en el ModuleDescriptor clase. Se utilizan para leer la forma binaria de la descripción del módulo desde un flujo de entrada o un búfer de bytes. Aquí está la extracción de la documentación de la API de Java 9.

  • leer(InputStream en) :lee la forma binaria de una declaración de módulo de un flujo de entrada como descriptor de módulo.
  • leer(InputStream in, proveedor > packageFinder) :lee la forma binaria de una declaración de módulo de un flujo de entrada como descriptor de módulo.
  • leer(ByteBuffer bb) :lee la forma binaria de una declaración de módulo desde un búfer de bytes como descriptor de módulo.
  • leer(ByteBuffer bb, proveedor > packageFinder) :lee la forma binaria de una declaración de módulo desde un búfer de bytes como descriptor de módulo.

Los paquetes establecidos por packageFinder incluye todos los paquetes que el módulo exporta, abre, los servicios prestados y el paquete de la clase principal que no están codificados por el descriptor proporcionado en el flujo de entrada o el búfer de bytes.

Conclusión

Además de leer información básica sobre el módulo, el Módulo class proporciona algunos métodos clave para consultar el estado del módulo, ya sea leído, abierto, exportado, etc. La API también proporciona métodos como addOpens , añadirExportar , agregarUsos y añadirlecturas para agregar usos de apertura y exportación y declaraciones de lectura al descriptor de módulos mediante programación. En pocas palabras, la API del módulo proporciona muchos otros métodos para tratar específicamente los módulos mediante programación. Aquí, solo hemos arañado la superficie para dar una idea inicial de qué se trata.