This content requires java

Java 9 Modules: part 1

In this blog we will go through one of the most important features of java 9, which is ‘Modules’ aka ‘Java Platform Module System (JPMS)’. We will understand everything about JPMS like, what is module? How it helps to add modules? and How to create and use module? Even if you don’t know anything about module don’t worry we got it covered.

If you are scared of this new word(‘Modules’), don’t worry once you understand it, it will be very easy.

Difference between JDK8 and JDK9

We all know that JRE is the most important part of JDK. But, since java 9, JDK does not contain the JRE folder 😮. Yes! that is true, because from java 9 JRE is converted to multiple small modules and they are present in folder called ‘jmods’.

We can list system modules or the contents of this ‘jmods’ folder by using the command : java —list-modules.

Table of contents

What is a Java 9 Module?

Module system is a part of Jigsaw Project. It adds one more abstraction level above packages. In other words, it is a ‘package of Packages’ that makes our code even more reusable.
It is also fine to say that a module is a group of closely related packages, resources and module descriptor(module-info.java) file.

In Java 9 ‘java.base’ is a base module. It does not depend on any other modules. By default, all modules including user defined modules are dependent on this module.

Even if we do not specify ‘java.base’ module, it will be imported automatically.

Features of java 9 Modules

java 9 module project structure

  • Increases code reusability: by creating modules we can use them in different projects
  • Easy and meaningful grouping of packages: if we have many packages in one project it is difficult to manage and organize code, this is where modules come to the rescue
  • More abstraction to packages:we can decide which packages are allowed to be accessed outside and which are private or for internal use
  • Separation of resource: each module will have it’s own required resource files like media or configuration files
  • Internal or secure classes can be hidden from outside world

Steps to create Module

  1. Create a folder with module name. Generally company name in reverse with artifact name is used. eg: ‘com.stacktraceguru.util’
  2. Add file with name ‘module-info.java’ in module root folder. This file is called as ‘Module Descriptor’ file
  3. Create java packages as per requirement
  4. Add classes as required under the created packages
Читайте также:  Принадлежит ли точка треугольнику python

What are the rules for creating Module?

  • Module name must be unique
  • Each module must have exactly one Module Descriptor file with name ‘module-info.java’
  • Package names must be unique. Even in the different modules we cannot have same package names
  • We can add media and other resource files in the module
  • Each module will create one jar file. For multiple jars we need to create separate modules
  • One project can have multiple modules

Note: Module name should not end with digits

What are theModule types?

Depending on how the modules are used, they are categorised into 4 types,

  • System Modules: the modules from JDK and JRE. Can be listed using java ´—list-modules
  • Application Modules: all the modules created in an application to achieve a functionality
  • Automatic Modules: existing jar files which are not modules but are added to module path. When we add non module jars to module path, module with jar name is created.
    • By default exports all the packages
    • By default can access classes from all other modules
    • Only exports to other unnamed module and automatic module. This means, application modules cannot access these classes
    • It can access classes from all the modules

    What is Module Descriptor file?

    It is a file with name module-info.java, under the root module path. This file contains the module metadata information.

    This is also java file which is compileable using javac command.

    This file defines following things

    • Public packages: list of packages that current module exports using ‘exports’ keyword
    • Dependencies on other modules: list of other modules on which the current module is dependent on. This is done using ‘requires’ keyword
    • Services offered: list of services that current module provides using ‘provides’ keyword
    • Services consumed: list of services that current module consumes using ‘uses’ keyword
    • Reflection permission: permission to specify if refection can be used to access private members using ‘open’ keyword

    Note: Module descriptor file needs to export packages as by default all packages are private. Also, we can not use reflection on other module classes. We need to enable reflection in order to use reflection.

    module com.module.util < // module exports com.module.util; requires java.sql; >

    Exports

    By default all the packages are private and we can make them public using exports keyword

    Rules to use export keyword:

    Qualified export: Exports … To

    This exports packages to only specific modules and not to all. It is also known as qualified export.

    In above case all modules can access com.module.package1, But only com.module.app can access com.module.package2 as well.

    Requires

    If a module needs to access packages exported from other modules, then these other modules must be imported using ‘requires’ keyword.

    Only after specifying the module dependency using ‘requires’, the other module packages can be used.

    Rules to use requires keyword:

    • only module can be specified for ‘requires’. Packages cannot be specified
    • dependency of each module must be specified separately, with separate ‘requires’ keyword

    Requires Static

    Sometimes we need some modules during compile time only and they are optional at runtime. For example, testing or code generation libraries.

    If we need compile time dependency that is optional at runtime then this dependency must be specified using ‘requires static’ keyword.

    In this example java.sql is mandatory at compile time but optional at runtime.

    Requires Transitive

    There is a possibility to grant access of the modules, on which our current module depends, to the module that uses our current module. The ‘requires transitive’ keyword helps to achieve this.

    This means all the modules that are using our module will get the access to transitive dependency automatically.

    So all other modules that are using com.module.app module can access the exported packages from com.module.util.

    Uses

    Using uses keyword we can specify that our module needs or consumes some service. Service is a interface or abstract class. It should not be an implementation class.

    Note: The most important thing to note here is that ‘requires’ adds a module dependency, whereas ‘uses’ specifies required service class.

    Provides … With

    We can specify that our module provides some services that other modules can use.

    Open

    Since java 9 encapsulation and security is improved for the reflection apis. Using reflection we were able to access even the private members of the objects.

    From java 9 this is not open by default. We can although grant reflection permission to other modules explicitly.

    open module com.module.util

    In this case all the packages from util module are accessible using reflection.

    Opens

    If we do not want to open all the packages for reflection we can specify packages manually using ‘opens’ keyword.

    In this case only classes from package1 are accessible using reflection.

    Opens … To

    Using ‘opens . to’ keyword we can open reflection permission for specific packages to specific modules only.

    In this case only module.a, module.b, org.test.integration modules can access classes from package1 using reflection.

    Note: If we need reflection access to the module, we can gain the access using command line option ‘–add-opens’, even if we are not the owner of the module.

    Aggregator Module

    First of all, this is not a technical concept. It is just a convenience concept for developers to make there life easier.

    Sometimes multiple modules require other multiple modules. Instead of adding these in every module descriptor, we can create one module that will add all the required dependency using ‘transitive’. Then we just need to add dependency of this module wherever needed, this will add all the required modules transitive dependency. This common module is the ‘Aggregator module’.

    For example, we have 10 modules, modA to modJ. modP, modQ, modR needs all 10 modules, then we can create one common module as below,

    Then modules P, Q and R just need to add require for modulePQR

    The module modulePQR is the Aggregator module.

    Fast track reading

    • Java Platform Module System (JPMS) is a part of Jigsaw Project
    • From java 9, jre is converted to multiple small modules and they are present in folder ‘jmods’
    • Module is a group of closely related packages, resources and module descriptor(module-info.java) file
    • Module names must be unique
    • Each module must have exactly one Module Descriptor file with name ‘module-info.java’
    • Packages must be unique. Even in the different modules we cannot have same package
    • 4 Types of Modules: System Modules , Application Modules, Automatic Modules and Unnamed Module
    • Module descriptor file must specify requires modules, exported packages, Services offered, Services Consumed and Reflection permission
    • Exports : By default all the packages are private and we can make them public using exports Keyword
    • Requires : specify the module dependency
    • Only compile time dependency is specified using requires static
    • Requires Transitive: Means all the modules who are using our module will get the access to transitive dependency automatically,
    • Uses: specifies that our module needs or consumes some service
    • Provides … With: specifies that our module provides some services that other modules can use
    • Open reflection permission to other modules explicitly
    • Aggregator Module:- module which will add all the required dependencies using transitive

    Источник

    This content requires java

    Одни модули могут зависить от других, например, как-то использовать их. Например, возьмем проект из прошлой темы с простейшим модулем:

    Модули в Java 9

    В файле Hello.java определим вывод сообщения не на консоль, а через графическое окно, которое предоставляется инфраструктурой Swing:

    package com.metanit.hello; import javax.swing.JOptionPane; public class Hello < public static void main(String[] args)< //System.out.println("Hello Demo Module!"); JOptionPane.showMessageDialog(null, "Hello Demo Module!"); >>

    Для вывода сообщения используется статический метод showMessageDialog() класса JOptionPane , который расположен в пакете javax.swing.JOptionPane . Чтобы использовать данный класс, он импортируется в начале файла. Однако поскольку мы используем данный класс в отдельном модуле, то просто импортировать класс или целый пакет недостаточно. Надо указать нашему модулю, чтобы он использовал модуль, где определен данный класс.

    Как узнать, в каком модуле расположен тот или иной класс? Если речь идет о встроенных классах, то для этого надо смотреть документацию, причем сразу по Java (JDK) 9+. В начале описания класса, как правило, указывается, к какому модулю он принадлежит.

    поиск модулей в Java 9

    Итак, документация нам сообщает, что класс JOptionPane расположен в модуле java.desktop . Теперь укажем нашему модулю, что нам надо использовать модуль java.desktop. Для этого перейдем к определению модуля в файле module-info.java и изменим его следующим образом:

    После оператора requires указывается название модуля, от которого зависит наш модуль. Соответственно если наш модуль использует несколько других модулей, то также с помощью оператора require можно указать все используемые модули.

    Далее скомпилируем модуль и запустим его на выполнение. После запуска нам отобразится графическое окно:

    Источник

Оцените статью