Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Les modules Java et l'outil jmod

Les archives Java et l'outil jar Les outils jlink et jaotc



Accès rapide :
Qu'est-ce qu'un module Java ?
Quels sont les formats d'archives supportés pour définir un module Java ?
Mise en oeuvre de modules
Définir son fichier module-info.java
Mise en oeuvre d'un module Jar
Mise en oeuvre d'un module JMod
Utilisation de modules
Utilisation d'un module Jar
Utilisation d'un module JMod

les modules constituent une nouveauté de la plateforme Java SE 9.0. Si vous utilisez une version antérieure de Java (c'est qui est encore très souvent le cas), vous ne pourrez pas mettre en oeuvre les exemples qui suivent. Dans ce cas, je vous conseille d'installer une version plus récente de Java. Pour rappel, plusieurs versions de Java peuvent être installées en parallèle.

Qu'est-ce qu'un module Java ?

De manière simpliste, un module est un ensemble de packages Java qui vont être archivés ensembles : un module est donc relativement proche de la notion de Jar vu précédemment. Cependant un module permet de gérer de manière plus subtile les aspects suivants :

Pour qu'une archive soit comprise comme étant un module Java, il faut impérativement qu'elle contienne à sa racine un fichier module-info.java. Nous allons revenir dans quelques instants sur le contenu de ce fichier.

Quels sont les formats d'archives supportés pour définir un module Java ?

Un module Java peut être stocké dans deux types d'archives :

Dans les deux cas, il s'agit de fichiers ZIP, mais le nouveau format JMod permet de contenir d'autres types des fichiers, outre les classiques fichiers .class (contenant du Byte Code Java). On peut, notamment, y trouver du code natif et des fichiers de configuration...

Mise en oeuvre de modules

Nous allons maintenant nous intéresser à la mise en oeuvre d'un module. Pour ce faire nous allons considérer deux packages constituant une librairie fictive. Ces deux packages sont :

Voici une capture d'écran d'un projet mettant en oeuvre notre module et ses deux packages.

Structure de notre projet associé au module à produire.

Définir son fichier module-info.java

Commençons par définir le fichier de description du module. Ce fichier doit être placé à la racine de votre module (default package) et doit se nommer module-info.java. En voici son contenu :

 1 
 2 
 3 
 4 
 5 
module fr.koor.superlib {
    requires java.base;                 // Par défaut
    requires transitive java.logging;   // Si l'API exposée utilise ce module, il faut aussi l'exposer !
    exports fr.koor.superlib.api;
}
Le fichier de définition du module : module-info.java

Le module se nommera donc fr.koor.superlib : il est recommandé de nommer ses modules en minuscules, à l'instar des packages Java.

Notre module tire une dépendance sur le module java.base contenant les types de bases de Java, mais cette dépendance est normalement implicite. Il tire une seconde dépendance, transitive, sur le module java.logging. Une dépendance transitive est exposée par le module ayant tiré cette dépendance.

un module Java ne peut tirer une dépendance que vers un autre module Java. Il ne peut pas tirer une dépendance vers une simple archive Java (une archive Jar qui ne contiendrait pas un fichier module-info.java à sa racine).

Enfin, notre module expose le package fr.koor.superlib.api, ce qui laisse entendre que le package fr.koor.superlib.impl ne sera pas visible en dehors de notre module.

Mise en oeuvre d'un module Jar

Pour produire le module au format Jar, vous pouvez utiliser la commande jar[.exe] proposée par votre JDK (Java Development Kit). Pour de plus amples informations sur l'utilisation de cet outil, je vous renvoie vers le chapitre précédent qui traite de ce sujet.

Notez que vous pouvez aussi produire un fichier Jar à partir d'Eclipse. Pour ce faire, cliquez avec le bouton droit de la souris sur le projet puis cliquez sur « Export... », comme le montre la capture d'écran ci-dessous.

Démarrage de l'assistant de production d'un Jar

Puis sélectionnez l'assistant « JAR file », comme ci-dessous.

Démarrage de l'assistant de production d'un Jar

Il ne vous reste plus qu'à sélectionner les éléments à archiver. N'oubliez pas le fichier module-info.class !

Démarrage de l'assistant de production d'un Jar
même si on voit le fichier module-info.java sélectionné dans l'assistant, c'est bien son .class associé qui sera archivé. Cela vient du fait que l'IDE Eclipse cherche à vous cacher, tant que possible, les fichiers compilés (rappelez-vous, on ne voit pas non plus le dossier bin dans l'explorateur de projet).

Mise en oeuvre d'un module JMod

L'exécutable jmod[.exe], proposé depuis le Java SE 9.0, permet de gérer le nouveau format d'archives Java. Dans une certaine mesure, l'outil est proche de l'outil jar[.exe] bien que les options proposées ne soient pas les mêmes. Voici, en premier lieu, l'aide en ligne proposé par la commande jmod[.exe].

$> jmod --help
Usage: jmod (create|extract|list|describe|hash) <OPTIONS> <jmod-file>

Main operation modes:
  create    - Creates a new jmod archive
  extract   - Extracts all the files from the archive
  list      - Prints the names of all the entries
  describe  - Prints the module details
  hash      - Records hashes of tied modules.

 Option                              Description                           
 ------                              -----------                           
  -?, -h, --help                      Print this help message               
  --class-path <path>                 Application jar files|dir containing  
                                        classes                             
  --cmds <path>                       Location of native commands           
  --config <path>                     Location of user-editable config files
  --dir <path>                        Target directory for extract          
  --dry-run                           Dry run of hash mode                  
  --exclude <pattern-list>            Exclude files matching the supplied   
                                        comma separated pattern list, each  
                                        element using one the following     
                                        forms: <glob-pattern>, glob:<glob-  
                                        pattern> or regex:<regex-pattern>   
  --hash-modules <regex-pattern>      Compute and record hashes to tie a    
                                        packaged module with modules        
                                        matching the given <regex-pattern>  
                                        and depending upon it directly or   
                                        indirectly. The hashes are recorded 
                                        in the JMOD file being created, or a
                                        JMOD file or modular JAR on the     
                                        module path specified the jmod hash 
                                        command.                            
  --header-files <path>               Location of header files              
  --help-extra                        Print help on extra options           
  --legal-notices <path>              Location of legal notices             
  --libs <path>                       Location of native libraries          
  --main-class <String: class-name>   Main class                            
  --man-pages <path>                  Location of man pages                 
  --module-version <module-version>   Module version                        
  -p, --module-path <path>            Module path                           
  --target-platform <String: target-  Target platform                       
    platform>                                                               
  --version                           Version information                   
  @<filename>                         Read options from the specified file
$> 

Voici comment produire l'archive à partir des codes du projet précédent : je suis placé dans le dossier correspondant au projet et les codes sources sont localisés dans le répertoire bin.

$> jmod create --class-path bin fr.koor.superlib.jmod

Comme indiqué précédemment, une archive jmod est au format ZIP. De plus, une archive jmod peut contenir de fichiers .class, bien entendu, mais aussi d'autres types de fichiers. C'est pour cela que ce ZIP contient un dossier classes : il contiendra les codes Java compilés. Pour démontrer ces points je vous propose d'utiliser un outil de manipulant d'archive ZIP (dans mon cas, 7-Zip).

$> 7z l fr.koor.superlib.jmod

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=fr_FR.utf8,Utf16=on,HugeFiles=on,64 bits,8 CPUs Intel(R) Core(TM) i7-4700HQ CPU @ 2.40GHz (306C3),ASM,AES-NI)

Scanning the drive for archives:
1 file, 2193 bytes (3 KiB)

Listing archive: fr.koor.superlib.jmod

--
Path = fr.koor.superlib.jmod
Type = zip
Offset = 4
Physical Size = 2189

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2020-03-29 12:50:46 .....          243          169  classes/module-info.class
2020-03-29 12:50:46 .....          138          116  classes/fr/koor/superlib/api/SecondaryInterface.class
2020-03-29 12:50:46 .....          208          145  classes/fr/koor/superlib/api/EntryInterface.class
2020-03-29 12:50:46 .....          544          331  classes/fr/koor/superlib/impl/SecondaryInterfaceImpl.class
2020-03-29 12:50:46 .....          937          468  classes/fr/koor/superlib/impl/EntryInterfaceImpl.class
------------------- ----- ------------ ------------  ------------------------
2020-03-29 12:50:46               2070         1229  5 files

Notez aussi que depuis le Java SE 9.0, les classes proposées en standard en Java ne sont plus stockées dans le fichier $JDK_HOME/jre/lib/rt.jar (rt pour RunTime). Maintenant, elles sont réparties dans différentes archives au format .jmod. Ces archives se trouvant dans le dossier $JDK_HOME/jmods. Voici quelques-unes de ces archives.

Les archives JMod du Java SE

Utilisation de modules

Si vous avez spécifié des dépendances entre modules, lors de son exécution, la Machine Virtuelle Java (la JVM) vérifie récursivement que tous les modules sont bien présents avant d'effectivement démarrer le programme. La JVM trouve les modules à partir du « Module Path » et non plus à partir du « Class Path ».

Utilisation d'un module Jar

Pour compiler, en mode ligne de commande, un module ayant lui-même une dépendance sur un autre module, veuillez procéder ainsi :

$> javac --module-path pathToYourModules src/fr/koor/client/*.java -d  bin

Pour démarrer une JVM, en mode ligne de commande, qui utilise des modules Java et parmi lesquels un de ces modules définit une classe de démarrage.

$> java --module-path pathToYourModules --module fr.koor.client

Par contre, si aucun module ne définit de classe de démarrage, il faudra alors spécifier la classe de démarrage.

$> java --module-path pathToYourModules --module fr.koor.client/fr.koor.client.Start

Si vous souhaitez ajouter un module à votre projet Eclipse, veuillez demander les propriétés du projet. Ensuite, sélectionnez l'entrée « Java Build Path » puis ajoutez le jar associé à votre module. Normalement Eclipse détecte automatiquement le fichier module-info.java et placera l'archive dans la section dédiée aux modules.

Utilisation d'un module dans Eclipse

Vous pouvez maintenant tester l'exemple suivant. Normalement, l'API doit être visible dans votre projet, alors que son implémentation interne sera non accessible. Voici un exemple de message d'erreur proposé par l'IDE Eclipse sur l'utilisation d'un package non exposé.

Mise en évidence de l'encapsulation réalisée par le module

Utilisation d'un module JMod

Un module JMod ne peut pas être utilisé directement au runtime, contrairement à un module Jar. Par contre, il peut être utilisé durant la phase de compilation ou durant une phase de link. Cette dernière possibilité est disponible depuis la version 9.0 du Java SE et sera présentée dans le prochain chapitre.



Les archives Java et l'outil jar Les outils jlink et jaotc