1

My goal is to package an application into a modular runtime image bundled with a custom JRE, using jlink. My app is a simple "hello world" Java Standard Edition app, with a dependency to Guava. I use the JDK 11.

Basically I try to reproduce this tutorial by Baeldung, but with NetBeans, Maven to manage the dependencies and the Maven Compiler Plugin version 3.8.1 for the build with the module system.

The directory structure:

enter image description here

The module-info.java file:

module TestwithJLink {
    requires guava;
    exports net.clementlevallois.testwithjlink;
}

Controller.java:

package net.clementlevallois.testwithjlink;

import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;

public class Controller {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Multiset<String> test = HashMultiset.create();
       test.add("hello");
       test.add("world");
        System.out.println("test: "+ test.toString());
    }

}

The pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.clementlevallois</groupId>
    <artifactId>TestwithJLink</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>18.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <id>compile</id>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
</project>

But it creates compiled classes, no jars or modules. So I can't go further (analyze the modules of the jar with jdeps, then using jlink). I must be missing something obvious but what?

seinecle
  • 10,118
  • 14
  • 61
  • 120
  • See [ProGamer's answer](https://stackoverflow.com/a/61724345/2525313) for your immediate problem. Beyond that, be aware that in order to use `jlink` everything needs to be a, explicit module (automatic module name in manifest is not enough). Guava 18 isn't and I'm not sure whether the newest version is. – Nicolai Parlog May 11 '20 at 07:36

2 Answers2

2

If you want to create a JAR file, then go to the root folder containing pom.xml in your terminal and type :

mvn package

This will create a JAR in target folder. Now change your path in terminal to target folder and Run the JAR file using:

java -jar {file-name-version}.jar
ProGamer
  • 420
  • 5
  • 16
  • `java -jar` won't work because no main class was defined and there are dependencies, which need to be listed on the module path and neither class nor module path work with the `-jar` option. – Nicolai Parlog May 11 '20 at 07:34
  • thx! what if wanted to package it directly from NetBeans? (all while keeping the JPMS logic intact) – seinecle May 11 '20 at 10:58
  • See this answer ..... [https://stackoverflow.com/a/20786265/11537839](https://stackoverflow.com/a/20786265/11537839) . – ProGamer May 11 '20 at 11:08
0

Finally got it. The scenario:

  • working from NetBeans, with your dependencies handled by Maven
  • you app has a module-info.java declaration
  • your dependencies also have a module-info.java declaration.

You want to package your app in a way that respects the modular system. So:

  • have these 3 Maven plugins listed in your pom (see below). Be careful about the version numbers for the plugins! In particular, the <goal>resolve</goal> in the maven-dependency-plugin makes sure your dependencies are packaged with their module-info.java file, which is not the case otherwise! (see here).
  • when the compilation is done, move the jar of your app in the lib folder where all the jars of your dependencies are already located.

You can run this app directly with the run icon in NetBeans, or:

  • from the parent folder of your lib folder, run: java --module-path lib --module NameOfYourModule

The POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.clementlevallois</groupId>
    <artifactId>TestwithJLink</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>net.clementlevallois</groupId>
            <artifactId>utils</artifactId>
            <version>1.0</version>
            <type>jar</type>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>install</phase>
                        <goals>
                            <goal>resolve</goal>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>

                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.2</version>                
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>net.clementlevallois.testwithjlink.Controller</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <id>compile</id>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
</project>
seinecle
  • 10,118
  • 14
  • 61
  • 120