Java 9 a incorporé l'API dans une collection de modules. Par conséquent, la modularité est le thème central; cela a affecté la conception du programme au plus haut niveau. Les programmes peuvent être construits de manière modulaire dès le départ. Il n'est pas surprenant qu'il y ait des API pour traiter spécifiquement l'élément de programmation appelé module . Les API fournissent un moyen d'accéder aux modules par programmation. Ces API sont très pratiques pour obtenir des informations spécifiques sur les modules ou pour les lire ou les manipuler. Cet article explore les classes d'API de module et certaines des méthodes, avec des exemples pour vous donner une idée de leur fonctionnalité globale.
Un aperçu
Java 9 fournit un ensemble de classes et d'interfaces pour gérer les modules par programmation. Ces API sont particulièrement utiles pour :
- Modules de lecture, de chargement et de recherche
- Lire et manipuler les descripteurs de modules
La liste des API est principalement incluse dans les packages :java.lang et java.lang.module . Bien que le java.lang.module package se compose de la plupart des classes et des interfaces pour gérer les descripteurs de module, le java.lang le paquet contient les classes Module , ModuleLayer , et une exception, LayerInstantiationException . Parmi ces trois, le Module est primordiale car une instance de cette classe fournit toutes les méthodes liées à la lecture, au chargement et à la recherche de modules. La classe la plus importante du java.lang.module package est le ModuleDescriptor . Cette classe fournit les méthodes nécessaires pour traiter les descripteurs de modules.
API des modules
Selon la documentation de l'API Java, la classe de module représente à la fois les modules d'exécution nommés et non nommés. Les modules nommés ont un nom et sont construits par la machine virtuelle Java lorsqu'un graphe de modules est défini sur la machine virtuelle Java pour créer une couche de module. Un module sans nom n'a pas de nom. Il existe un module sans nom pour chaque ClassLoader , obtenu en appelant son getUnnamedModule méthode. Tous les types qui ne sont pas dans un module nommé sont membres du module sans nom de leur chargeur de classe de définition.
Il est simple de connaître le module d'une classe à laquelle il appartient. Par exemple, si nous voulons connaître le module d'une classe, disons, ArrayList , à partir de l'API Collection ou, par exemple, Application de JavaFX, nous pouvons le faire de la manière suivante.
Class<ArrayList> c= ArrayList.class; Module mod=c.getModule(); System.out.println(mod.getName());
Ou, en une seule instruction, comme suit :
System.out.println(Application.class .getModule().getName());
Cela imprime le nom du module de la classe, tel que java.base , pour Arraylist , et javafx.graphics pour candidature . Parce qu'un module peut être nommé ou sans nom, nous pouvons le savoir en appelant le isNamed() méthode. Cette méthode renvoie true si le module est nommé ou faux s'il s'agit d'un module sans nom. Voici un exemple de modules sans nom.
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()); } }
Sortie :
unnamed module @4c75cab9 null null is Unnamed Module null
Et, pour les modules nommés, on peut écrire comme suit :
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()); } }
Sortie :
module java.base java.base java.base is Named Module module { name: [email protected], uses: [java.nio.file.spi.FileTypeDetector, ...}
Un ModuleLayer contient uniquement des modules nommés. Nous pouvons invoquer le getLayer méthode pour obtenir les informations sur la couche qu'elle contient dans le module. S'il renvoie null, cela signifie que le module n'est pas dans une couche ou qu'il s'agit d'un module sans nom. Si nous voulons obtenir une liste des packages disponibles dans un module, nous pouvons invoquer le getPackages méthode. Le getClassLoader La méthode renvoie le chargeur de classe du module. Voici un exemple pour illustrer les méthodes décrites ci-dessus.
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); } } }
Sortie :
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
Description des modules
Selon Java 9 API Documentation, "Un descripteur de module décrit un module nommé et définit des méthodes pour obtenir chacun de ses composants." Le descripteur de module pour un module nommé dans la machine virtuelle Java est obtenu en appelant le Module est getDescriptor méthode. Les descripteurs de module peuvent également être créés en utilisant le ModuleDescriptor.Builder class ou en lisant la forme binaire d'une déclaration de module (module-info.class ) en utilisant le lire méthodes définies dans cette classe.
Par conséquent, généralement le ModuleDescriptor instance représente la définition de module trouvée sous la forme binaire du fichier descripteur de module, appelé module-info.class . Outre la lecture et la manipulation de la définition de module, nous pouvons utiliser le ModuleDescriptor.Builder classe pour décrire le module au moment de l'exécution.
Un descripteur de module décrit trois types de module, tels que les modules normaux, ouverts et automatiques.
Un module normal et un module ouvert décrivent explicitement les services qu'ils fournissent ou utilisent, les dépendances, les packages exportés et d'autres composants. La principale différence entre un module normal et un module ouvert est que Les modules normaux peuvent ouvrir des packages spécifiques. Le descripteur de module pour un module ouvert ne déclare aucun paquet ouvert (son opens renvoie un ensemble vide), mais lorsqu'elle est instanciée dans la machine virtuelle Java, elle est traitée comme si tous les packages étaient ouverts.
Le module automatique, cependant, ne déclare aucun package exporté, ouvert ou dépendances, à l'exception de la déclaration implicite de java.base module. Lorsqu'un module automatique est instancié dans la machine virtuelle Java, il lit tous les modules sans nom et est traité comme si tous les packages étaient exportés et ouverts.
Le getDescriptor méthode du Module la classe renvoie une instance du ModuleDescriptor classe. Le ModuleDescriptor La classe contient des classes imbriquées statiques dont l'instance représente l'instruction directive dans le fichier de déclaration du module. La classe, cependant, ne contient pas d'usages déclaration qui peut généralement être représentée par une instance de service String . Voici ces quatre autres :
- ModuleDescriptor.Requires
- ModuleDescriptor.Opens
- ModuleDescriptor.Provides
- ModuleDescriptor.Exports
Un exemple rapide
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()); } }
Sortie :
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]
Le fichier binaire descripteur de module, appelé module-info.class , peut être lu directement de la manière suivante pour créer une instance du ModuleDescriptor classe :
try { ModuleDescriptor descriptor = ModuleDescriptor .read(new FileInputStream("module-info.class")); } catch (IOException ex) { }
Il existe quatre versions de la lecture statique surchargée méthode définie dans le ModuleDescriptor classe. Ils sont utilisés pour lire la forme binaire de la description du module à partir d'un flux d'entrée ou d'un tampon d'octets. Voici l'extraction de la documentation de l'API Java 9.
- lire(InputStream in) :lit la forme binaire d'une déclaration de module à partir d'un flux d'entrée en tant que descripteur de module.
- lire(InputStream in, Supplier
> packageFinder) :lit la forme binaire d'une déclaration de module à partir d'un flux d'entrée en tant que descripteur de module. - lire(ByteBuffer bb) :lit la forme binaire d'une déclaration de module à partir d'un tampon d'octets en tant que descripteur de module.
- lire(ByteBuffer bb, Fournisseur
> packageFinder) :lit la forme binaire d'une déclaration de module à partir d'un tampon d'octets en tant que descripteur de module.
Les packages définis par packageFinder inclure tous les packages que le module exporte, ouvre, les services fournis et le package de la classe principale qui ne sont pas encodés par le descripteur fourni dans le flux d'entrée ou le tampon d'octets.
Conclusion
Outre la lecture des informations de base sur le module, le Module La classe fournit des méthodes clés pour se renseigner sur l'état du module, qu'il soit lu, ouvert, exporté, etc. L'API fournit également des méthodes telles que addOpens , ajouterExporter , addUses , et addReads pour ajouter des utilisations d'ouverture et d'exportation et lire des instructions au descripteur de modules par programme. En un mot, l'API de module fournit de nombreuses autres méthodes pour traiter spécifiquement les modules par programmation. Ici, nous n'avons fait qu'effleurer la surface pour donner une première idée de ce dont il s'agit.