Usage

Introduction

The JLink-JPackager Maven Plugin is intended to create Modular Java Run-Time Images via jlink with JDK 9 and above or native installable packages via jpackage with JDK 14 and above.

Although the jlink and jpackage tools have some limitations in regards to using non module jars and automatic module jars the JLink-JPackager Maven Plugin can create ZIP files for Modular Java Run-Time Images or package installers with Java Runtimes and mixed real and automatic modules and non modular jars.

It does this by analyzing java module dependencies of all maven dependencies using the jdeps java tool and modifying command line parameters for the jlink the jpackage and the java executable based on the findings.

The resulting Java Runtime contains all java system module dependencies of all real modules, all automatic modules and all non-modular JAR files which are put on the classpath.

NOTE: This is an alpha release which means everything can change until we reach the first milestone release.

The JLink-JPackager Maven Plugin is available on GitHub: jlink-jpackager-maven-plugin

It is based on the Apache maven-jlink-plugin

The intended artifacts to be linked together into a Modular Run-Time Image are the jmod and jar files. JMod files can be created by using the Maven JMod Plugin and jar files can be created by using the Maven JAR Plugin.

Configuration of the JLink-JPackager Maven Plugin

To use the JLink-JPackager Maven Plugin you have to configure it as an extensions which means the configuration in your pom file has to look like this:

<project>
  [...]
  <build>
    [...]
    <plugins>
      [...]
      <plugin>
        <groupId>net.agilhard.maven.plugins</groupId>
        <artifactId>jlink-jpackager-maven-plugin</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <extensions>true</extensions>
        <configuration>
          <!-- configuration elements goes here -->
        </configuration>
      </plugin>
   [...]
</project>

The configuration element contains the configuration for the plugin }like any other Maven plugin. The different elements which can be configured for this plugin can identified by the goals documentation.

Requirements

Based on the foundation of the plugin it is required to have at least JDK 9 installed to use the jlink goal and at least JDK11 or JDK14 must be installed to use the jpackager goal. This means either you have such JDK configured via JAVA_HOME which means to run the whole Maven build with JDK 9/14 or you can use this via Maven Toolchains.

Howto configure Maven related to Toolchains can be read in the Toolchains documentation.

You need to use the special JDK-14 Early Access build that includes JPackager support to use the jpackager goal.

This JPackager JDK-14 Early Access build can be downloaded from http://jdk.java.net/14/.

Alternatively you can also use the JDK-11 backported JPackager tool wich is mentioned in Filling the Packager gap - OpenJDK mailing list - Java.net

Usage of the JLink-JPackager Maven Plugin

Usually you will use the Maven JLink-JPackager Maven Plugin to create a Run Time Image or an installable Package from one or more modules within a multi module build

You will than use one submodule there with a pom.xml which uses one of the special Maven packaging types the plugin provides and a configuration for the plugin.

In other words it is not possible to create a Run Time Image or Installation Package from a single Maven Project within the same single Maven Project and you usually would not call the goals of the plugin by using a plugin execution configuration.

Let us assume you have a multi module structure which contains two modules mod-1 and mod-2 which you like to put into the resulting Run Time Image.

The parent of the multi module looks similar like this:

<project ...>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.corporate.maven</groupId>
    <artifactId>maven-parent</artifactId>
    <version>2.3.1</version>
  </parent>
  <groupId>com.corporate.project</groupId>
  <artifactId>parent</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>
   [...]
  <modules>
    <module>mod-1</module>
    <module>mod-2</module>
  </modules>  
   [...]
</project>

A directory structure of such a project looks like this:

.
├── mod-1
│   └── src
└── mod-2
    └── src

The mod-1 module looks similar like this:

<project ...>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.corporate.project</groupId>
    <artifactId>parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>mod-1</artifactId>
   [...]
</project>

The mod-2 module looks similar like this:

<project ...>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.corporate.project</groupId>
    <artifactId>parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>mod-2</artifactId>
   [...]
</project>

If you like to create a Java Run Time Image of your modules you have to create a separate module mod-jlink which contains the configuration to create the Run Time Image which looks similar like this:

<project ...>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.corporate.project</groupId>
    <artifactId>parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <packaging>jlink</packaging>
  <artifactId>mod-jlink</artifactId>
   [...]
</project>

The directory structure now looks like this:

.
├── mod-1
│   └── src
├── mod-2
│   └── src
└── mod-jlink
    └── src

Or if you like to create a installable package of your modules you have to create a separate module mod-jpackager which contains the configuration to create the Run Time Image which looks similar like this:

<project ...>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.corporate.project</groupId>
    <artifactId>parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <packaging>jpackager</packaging>
  <artifactId>mod-jpackager</artifactId>
   [...]
</project>

The directory structure than looks like this:

.
├── mod-1
│   └── src
├── mod-2
│   └── src
└── mod-jpackager
    └── src

Before you can do this you have to add the configuration to the parent like shown in Configuration of the JLink-JPackager Maven Plugin.

Now you need to define which modules should be linked into the resulting Java Run Time Image which simply can be done by defining the modules as dependencies to your mod-jlink or mod-jpackager module like this:

<project ...>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.corporate.project</groupId>
    <artifactId>parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <packaging>jlink</packaging>
  <artifactId>mod-jlink</artifactId>
 <dependencies>
    <dependency>
      <groupId>com.corporate.project</groupId>
      <artifactId>mod-1</artifactId>
      <version>${project.version}</version>
    </dependency>
    <dependency>
      <groupId>com.corporate.project</groupId>
      <artifactId>mod-2</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>  
   [...]
</project>

When you use the jpackager goal you also have to at least specify some minimal configuration with a module element specifying the main module and the main class like this:

<project ...>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.corporate.project</groupId>
    <artifactId>parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <packaging>jpackager</packaging>
  <artifactId>mod-jpackager</artifactId>

  <build>
    <plugins>

      <plugin>
        <groupId>net.agilhard.maven.plugins</groupId>
        <artifactId>jlink-jpackager-maven-plugin</artifactId>
        <extensions>true</extensions>
        <configuration>
          <verbose>true</verbose>
          <module>com.corporate.project.mod-1/MainClass</module>
        </configuration>
      </plugin>

    </plugins>

 <dependencies>
    <dependency>
      <groupId>com.corporate.project</groupId>
      <artifactId>mod-1</artifactId>
      <version>${project.version}</version>
    </dependency>
    <dependency>
      <groupId>com.corporate.project</groupId>
      <artifactId>mod-2</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>  
   [...]
</project>

After you have added the appropriate configuration you can simply create the Java Run Time Image or Installable Package by calling from the root of your multi module project like this:

mvn clean package

There are some output lines similar like this:

[INFO]
[INFO] --- jlink-jpacker-plugin:1.0.0-SNAPSHOT:jlink (default-jlink) @ mod-jlink ---
[INFO] Toolchain in jlink-jpackager-maven-plugin: jlink [ /.../jdk1.9.0_ea+181.jdk/Contents/Home/bin/jlink ]
[INFO] The following dependencies will be linked into the runtime image:
[INFO]  -> module: com.soebes.nine.one.jar ( /.../mod-1/target/mod-1-1.0-SNAPSHOT.jar )
[INFO]  -> module: com.soebes.nine.two.jar ( /.../mod-2/target/mod-2-1.0-SNAPSHOT.jar )
[INFO] Building zip: /.../mod-jlink/target/mod-jlink-1.0-SNAPSHOT.zip
[INFO]

If you like to install the resulting Java Run Time Image files into your local cache you can achieve this by using:

mvn clean install

or if you like to deploy the resulting artifacts to a remote repository you have to use:

mvn clean deploy

At the moment the resulting Java Run Time Image is packaged into a zip archive which used to transport the whole structure which is created by jlink to a repository.

The resulting Java Run Time Image directory structure looks like this:

jlink/
├── bin
├── conf
├── include
├── legal
├── lib
└── release

Packages build with the jpackager goal are deployed into the repository with a maven classifier based on the package type and the extension for the package format, eg. .rpm .msi

Using Mixed real and automatic modules plus non modular JARs

Although the jlink and jpackage tools have some limitations in regards to using non module jars and automatic module jars the JLink-JPackager Maven plugin can create ZIP files or package installers with Java Runtimes and mixed real and automatic modules and non modular jars.

It does this by analyzing java module depdencies of all maven dependencies using the jdeps java tool and modifying command line parameters for the jlink the jpackage and the java executable based on the findings.

For jlink execution mode jars which are automatic jars or non-modular jars these are copied into the folder created by jlink after jlink execution and before creating the result ZIP file.

For jpackage execution mode jars which are automatic jars or non-modular jars these are copied into the folder used with the jpackage --input parameter before jpackage execution.

For jlink execution mode a startup script is generated by a template engine which generates the necessary command line parameters to put automatic jars on the module path and non-modular jars on the classpath.

For jpackage execution mode the --arguments parameter for jpackage> is modified to put automatic jars on the module path and non-modular jars on the classpath.

The jlink-jpackager:jpacktool-prepare goal prepares the execution of the jlink-jpackager:jlink and jlink-jpackager:jpackager goals by analyzing java module dependencies and copying files from maven dependencies.

To select this execution mode use one of the jpacktool-jlink or jpacktool-jpackager maven packaging modes.

<project ...>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.corporate.project</groupId>
    <artifactId>parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <packaging>jpackage-jlink</packaging>
  <artifactId>mod-jlink</artifactId>
   [...]
</project>
<project ...>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.corporate.project</groupId>
    <artifactId>parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <packaging>jpackage-jpackager</packaging>
  <artifactId>mod-jlink</artifactId>
   [...]
</project>

Maven Packaging types

The JPacktool plugin provides the following maven packaging types

Simple use cases:

  <packaging>jlink</packaging>
  <packaging>jpackager</packaging>

Use cases for projects with mixed real-modules, automatic modules and non-modular jars:

  <packaging>jpacktool-jlink</packaging>
  <packaging>jpacktool-jpackager</packaging>