I have a simple hello world that I'm trying to build into a modular jar to test running jlink. I can neither run the jar file nor can I create an image for it with jlink.
I an on Windows, and using Java 21.
Here are the java files in the project.
$ find src/main/java -name '*\.java'
src/main/java/com/foo/bar/demoapp/App.java
src/main/java/module-info.java
package com.foo.bar.demoapp;
public class App
{
public static void main( String[] args )
{
System.out.println("hello hello");
}
}
module demoapp {
exports com.foo.bar.demoapp;
}
I'm using Maven 3.9.6, and my pom file is pretty simple. It specifies maven.compiler.(source|target)=21
. It sets the compiler plugin version to 3.13.0. It sets the jar plugin to version 3.1.2, and specifies the App class as the mainClass.
<configuration>
<archive>
<manifest>
<mainClass>com.foo.bar.demoapp.App</mainClass>
</manifest>
</archive>
</configuration>
I have verified that the jar file appears to contain the expected contents.
$ unzip -l jars/demo-app-1.0-SNAPSHOT.jar
Archive: jars/demo-app-1.0-SNAPSHOT.jar
Length Date Time Name
--------- ---------- ----- ----
116 2024-04-08 12:30 META-INF/MANIFEST.MF
552 2024-04-08 12:30 com/foo/bar/demoapp/App.class
5160 2024-04-08 12:09 META-INF/maven/com.foo.bar/demo-app/pom.xml
64 2024-04-08 12:30 META-INF/maven/com.foo.bar/demo-app/pom.properties
283 2024-04-08 12:30 module-info.class
I used javap
to verify that the module-info class shows the main-class as required.
$ javap -verbose --module demoapp --module-path jars module-info
Classfile jar:file:///C:/Users/wrobert1/dev/foo/demo-app/jars/demo-app-1.0-SNAPSHOT.jar!/module-info.class
Last modified Apr 8, 2024; size 283 bytes
SHA-256 checksum 004814b6bbe32c09ecba1fe2a02289d5e4b33a14426856ca6598e1c256405443
Compiled from "module-info.java"
module demoapp@1.0-SNAPSHOT
minor version: 0
major version: 65
flags: (0x8000) ACC_MODULE
this_class: #1 // "module-info"
super_class: #0
interfaces: 0, fields: 0, methods: 0, attributes: 4
... constant pool elided ...
SourceFile: "module-info.java"
Module:
#6,0 // demoapp
#8 // 1.0-SNAPSHOT
1 // requires
#9,8000 // "java.base" ACC_MANDATED
#11 // 21.0.1
1 // exports
#12,0 // com/foo/bar/demoapp
0 // opens
0 // uses
0 // provides
ModuleMainClass: #16 // com.foo.bar.demoapp.App
ModulePackages:
#12 // com.foo.bar.demoapp
I also used javap
to verify that App.class has a main function
$ javap --module demoapp --module-path jars com.foo.bar.demoapp.App
Compiled from "App.java"
public class com.foo.bar.demoapp.App {
public com.foo.bar.demoapp.App();
public static void main(java.lang.String[]);
}
Given all of this, when I attempt to run the jar file, I get a ClassNotFoundException.
$ java --module-path jars com.foo.bar.demoapp.App
Error: Could not find or load main class com.foo.bar.demoapp.App
Caused by: java.lang.ClassNotFoundException: com.foo.bar.demoapp.App
And jlink
fails for what is likely the same reason.
$ jlink --module-path jars --output linked --add-modules=java.base --launcher startmeup=demoapp/com.foo.bar.demoapp.App
Error: java.lang.IllegalArgumentException: demoapp does not have main class: com.dhl.raf.demoapp.App
I have been searching for what could be the issue for quite some time now with no luck. I am not sure what I have done wrong here.
While executing the main class with java
, one way to work this out would be to state which modules shall be added from the module path to resolve.
java --module-path jars --add-modules demoapp com.foo.bar.demoapp.App
This shall work in the case of jlink
too with something like:
jlink --module-path jars --output linked --add-modules=java.base,demoapp --launcher startmeup=demoapp/com.foo.bar.demoapp.App
An alternate that you can relate to your approach of using javap
would be to specify the module along with the mainClass
such as:
java --module-path jars --module demoapp/com.foo.bar.demoapp.App
More information about this can be gathered with the java -help
command line itself.