11

I'm trying to create a modular, executable jar file, that can be run with java -p <jar file> -m <module> on Java 9.0.1.

This works as expected when creating a jar with jar cfe test.jar test.Main -C classes/ ., but throws module test does not have a MainClass attribute, use -m <module>/<main-class> when generated with mvn package and mvn assembly:single.

These maven generated jars still work with java -p test.jar -m test/test.Main, and all the jars work on the classpath with java -jar test.jar.


I inspected the jar contents with jar xf test.jar, and found that the jars are exactly the same, except for the manifests (see below):

Manifest-Version: 1.0
Created-By: 9.0.1 (Oracle Corporation)
Main-Class: test.Main

and

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: testuser
Build-Jdk: 9.0.1
Main-Class: test.Main

Notably, one still can't use java -p test.jar -m test when specifying the working manifest:

$ jar cfm test.jar test-contents/META-INF/MANIFEST.MF -C classes/ .
$ java -p test.jar -m test

module test does not have a MainClass attribute, use -m <module>/<main-class>

Edit: A repo with the expected behavior: https://github.com/deontologic/test

Naman
  • 27,789
  • 26
  • 218
  • 353
kantianethics
  • 671
  • 5
  • 21
  • I'm using the latest (3.1.0) assembly plugin, but I don't think it's maven specific. I can only seem to create an executable jar when specifying the main class through `jar` – kantianethics Dec 19 '17 at 01:37
  • I'm unable to execute the jar without manually specifying the main class, in every case except when using jar's `--main-class` attribute. – kantianethics Dec 19 '17 at 01:47
  • @nullpointer I added a repo, hopefully the readme clarifies the expected behavior. – kantianethics Dec 19 '17 at 02:04
  • Well I guess the question is eventually why does `-m test` doesn't work while `-m test/test.Main` or `java -jar` does. Is it? – Naman Dec 19 '17 at 03:03
  • yes, precisely. What's so strange is that it works fine when using `jar --main-class` – kantianethics Dec 19 '17 at 03:09
  • 2
    Yes, they are different! The maven one is missing the ModuleMainClass specifier. The open issue is here: https://issues.apache.org/jira/browse/MJAR-238 Thanks for the help! – kantianethics Dec 19 '17 at 03:35
  • Even I got that hint from the jmod tool description and then was certain from the code that there was an explicit mapping for the mainClass in descriptor as well. – Naman Dec 19 '17 at 03:48
  • 1
    The main thing to understand is the Main-Class attribute in the JAR manifest is for executable JARs (java -jar), it's not the same thing as the ModuleMainClass class file attribute in module-info.class. The jar tool sets both when you use the --main-class or -e options. The jar --manifest-file or -m options do not add or update the ModuleMainClass class file attribute when the manifest file contains the Main-Class attribute. – Alan Bateman Dec 19 '17 at 08:08

1 Answers1

6

I couldn't though find this in the jar tool documentation precisely either, yet the jmod tool defined it a little better.

--main-class class-name 

Specifies main class to record in the module-info.class file.

I could further look into the JDK code and the behavior as you execute different commands seems related to the mainClass attribute of the ModuleDescriptor.mainClass().

Since when packaging the jar with --main-class flag, the entry in the module descriptor should be made to execute the module without specifying the fully qualified name of the main class during execution.

On the other hand this is not true using the maven jar creation and might be fixed in future upgrades as found by you as well.


More on why the following works :

java -jar test-1.0.0-SNAPSHOT-jar-with-dependencies.jar

If the -jar option is specified, then its argument is the name of the JAR file containing class and resource files for the application. The startup class must be indicated by the Main-Class manifest header in its manifest file(META-INF/MANIFEST.MF)

and pretty obvious why specifying the fully qualified name works as:

java -p target/test-1.0.0-SNAPSHOT-jar-with-dependencies.jar -m test/test.Main
Naman
  • 27,789
  • 26
  • 218
  • 353