Migrate from Maven Archiver to standard "jar" tool
New feature, improvement proposal
This is a description of a work being done as part of Full Java Module Support effort. If the principle is accepted, a pull request will be submitted later. This issue is for collecting feedbacks in the meantime.
This work is a refactoring of the Maven JAR plugin for using the standard jar tool instead of Maven Archiver. It can be done by using the java.util.spi.ToolProvider interface, which was introduced in Java 9. Since Maven 4 upgraded its requirement from Java 8 to Java 17, the use of that interface is no longer problematic.
Rational
In early Java days, the jar tool was equivalent to a zip command with a different syntax and with the addition of a special handling of the META-INF/MANIFEST.MF file. Because of this quasi-equivalence, it was not difficult to create JAR files ourselves using any library capable to write ZIP files. This is what Maven Archiver does, together with supporting other archive formats. But today, the jar tool became more sophisticated. It now includes options for verifying the consistency of multi-release JAR files, options for updating module-info.class, provides security features specific to Java, etc.. This evolution can be seen in the "Modular JAR files" section of the Maven Plugin documentation, which states that the plugin uses the jar tool for updating the JAR file in a way that the Maven Archiver can't do easily. Therefore, since Maven 4 requires Java 17 and since that Java version gives us an easy access to the jar tool through the java.util.spi.ToolProvider interface (available since Java 9), it may be time to abandon our manual creation of a JAR file and rely fully on the jar tool instead.
Benefits
In a multi-release JAR file, blindingly storing the content of META-INF/versions/ directories as if they were ordinary resources is not equivalent to using the jar --release option. The difference is that in the latter case, the jar tool performs some consistency checks. This issue was independently reported by user in #484, which would be fixed by this proposal. Note that if this verification is not desired, Maven users can disable it by setting the detectMultiReleaseJar plugin option to false.
In a modular JAR file, it is no longer sufficient to declare the main class in the Main-Class entry of the MANIFEST.MF file. The main class needs to be specified by the --main-class option of the jar tool, which will update module-info.class. For compatibility reason the Maven JAR plugin gets the option value from that manifest entry, but internally the use of the jar tool is mandatory.
Other options such as --module-version and --hash-modules which are not yet used in the current plugin will become used in a future version, especially since security is becoming more and more a concern.
This approach makes easy to generate a target/jar.args file when the build fails or when Maven is run in verbose mode. This is similar to the compiler plugin generating a target/javac.args file. This file allows the user to test easily on the command-line, which makes debugging faster. Likewise, the options can also be passed to another tool, which makes easier to resolve #439 as well.
Behavioral changes
The plugin behaviour after the proposed refactoring would be different than version 3 in the following aspects:
Removal of default **/package.html excludes
The current plugin version uses an undocumented **/package.html default excludes. This default seems to exist since the initial revision in March 2004, but I saw no explanation for this oddity. This default is not mentioned in the documentation. The removal of this oddity is necessary for allowing the proposed new plugin implementation to specify only some root directories to the jar tool, which can traverse the directory tree itself.
Prototype
If accepted, the pull request would be created from this clone after all integration tests pass (this is not yet the case at the time of writing this issue).
good idea - lets try for m-jar-p 4.x (ie for Maven 4 only & Java 17). Maven 3.x will not be affected
Yes, this proposal is for Maven 4 only.
Addition to above description:
Benefits
This approach allows to add a <toolArgs> configuration option, similar to the <compilerArgs> in the Maven Compiler Plugin. Such option allows developers to use new tool arguments before they are supported by the plugin.
Behavioural changes
After this refactor, the plugin automatically uses the META-INF/MANIFEST.MF file found in the classes directory. Before this refactor, the plugin used that file only if explicitly specified in the <manifestFile> archive configuration. The previous policy was discussed in #255. The new policy is a natural consequence of the way that the JAR plugin is reimplemented, and also more useful in the context of multi-module (in Java module sense) projects since each module could contain its own MANIFEST.MF file.
Pull request created in #508.