Many Java projects have adopted the *multi-release JAR file* standard (introduced by JEP 238 <https://openjdk.org/jeps/238>) to: - Maintain compatibility with older Java major releases - Leverage new features in the latest Java releases - Avoid delivering multiple JAR files just for different Java major releases For example, a multi-release JAR file can target Java 8 as the minimal supported release and, at the same time, include class files that are only compatible with Java 9 and above. In this case, the class files compatible with only Java 9+ will not be loaded on Java 8. Thus, users can switch between Java 8 and 9+ and reuse the same JAR file, instead of download a different JAR file for different Java major releases. The multi-release JAR file standard is specified in the JAR File Specification: https://docs.oracle.com/en/java/javase/17/docs/specs/jar/jar.html#multi-release-jar-files java-pkg-simple.eclass should provide the functionality to create a multi-release JAR file, so ebuilds for Java projects whose upstream delivers multi-release JAR files can be easily created.
Extra Information That May Be Useful to This Functionality's Implementation Summary of the multi-release JAR file standard: - Definitions: - Multi-release JAR file: A JAR file in which the META-INF/MANIFEST.MF file bears the line: Multi-Release: true - Versioned directory: A 'META-INF/versions/<N>' directory in a multi-release JAR file, where <N> is the Java major release number (9, 10, 11, ..., 17, ...) that files under this directory target. - Requirements: - "The public API exported by the classes in a multi-release JAR file must be exactly the same across versions". Interpretation: This eliminates the possibility where a class that is part of a public API is only available on certain latest Java major releases and not on older releases. The public API's implementation may alter between different Java major releases to utilize the releases' latest features, but the API's interface may not. The 'jar' tool itself naturally supports building a multi-release JAR file <https://docs.oracle.com/en/java/javase/17/docs/specs/man/jar.html>: --release VERSION Creates a multirelease JAR file. Places all files specified after the option into a versioned directory of the JAR file named META-INF/versions/VERSION/, where VERSION must be must be a positive integer whose value is 9 or greater. At run time, where more than one version of a class exists in the JAR, the JDK will use the first one it finds, searching initially in the directory tree whose VERSION number matches the JDK's major version number. It will then look in directories with successively lower VERSION numbers, and finally look in the root of the JAR. The same page also provides an example invocation of 'jar' that builds a multi-release JAR file under the "Examples of jar Command Syntax" section. Build systems like Maven and Gradle have been supporting building multi-release JAR files already: - Maven: https://maven.apache.org/plugins/maven-compiler-plugin/multirelease.html - Gradle: https://blog.gradle.org/mrjars#how-to-create-a-multi-release-jar-with-gradle
The bug has been referenced in the following commit(s): https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=8643a627c63a350e0260b50769cd557272140d4e commit 8643a627c63a350e0260b50769cd557272140d4e Author: Volkmar W. Pogatzki <gentoo@pogatzki.net> AuthorDate: 2024-11-19 15:46:54 +0000 Commit: Florian Schmaus <flow@gentoo.org> CommitDate: 2025-04-01 13:58:01 +0000 java-pkg-simple.eclass: support Multi-Release JAR Files (JEP 238) See https://openjdk.org/jeps/238 This commit adds basic support for building multi-release jar files. A multi-release jar file has release-specific classes in directories under META-INF/versions/ and its MANIFEST.MF contains a line with 'Multi-Release: true'. The probably most common case of a multi-release jar file has only one single such class which is 'META-INF/versions/9/module-info.class'. To do so, we add JAVA_RELEASE_SRC_DIRS as a new eclass variable which is also used as the condition to trigger the new functionality. A new local variable 'multi_release' is added to the packaging section (the part using the 'jar -create' command). Only when JAVA_RELEASE_SRC_DIRS is set, additional actions take place: - Compilation (those are the parts with 'ejavac') will additionally loop over the release-specific directories listed in JAVA_RELEASE_SRC_DIRS and compile the release-specific classes into corresponding directories under target/versions/. - Packaging (the part using the 'jar -create' command) will add the details to the 'multi_release' variable so that the release-specific directories under target/versions/ can be packaged into the jar file. This commit also adds funtionality to generate 'module-info.java' files. It is useful for packages where module-info.java is not provided in the sources but needs to be generated by the build system. We use the built-in jdeps function with the --generate-module-info option which became available with Java 11. It generates the module-info.java file based on an intermediate jar file and places it in the "${JAVA_MODULE_INFO_OUT}/${JAVA_INTERMEDIATE_JAR_NAME}/" directory. For this purpose we add three new eclass variables: - JAVA_INTERMEDIATE_JAR_NAME - JAVA_MODULE_INFO_OUT - JAVA_MODULE_INFO_RELEASE When both JAVA_MODULE_INFO_OUT and JAVA_INTERMEDIATE_JAR_NAME are defined in the ebuild we - compile the sources still without module-info - package them as an intermediate {JAVA_INTERMEDIATE_JAR_NAME}.jar - let java-pkg-simple_generate-module-info generate the module-info - compile module-info.java with the --patch-module option - package the final jar file including the module-info.class When the JAVA_MODULE_INFO_RELEASE variable is set, module-info.java is generated into a release specific directory "${JAVA_MODULE_INFO_OUT}/${JAVA_INTERMEDIATE_JAR_NAME}/versions/{JAVA_MODULE_INFO_RELEASE}". Bug: https://bugs.gentoo.org/900433 Signed-off-by: Volkmar W. Pogatzki <gentoo@pogatzki.net> Signed-off-by: Florian Schmaus <flow@gentoo.org> eclass/java-pkg-simple.eclass | 335 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 297 insertions(+), 38 deletions(-)