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.