Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 900433 - java-pkg-simple.eclass: Support building multi-release JAR files [JEP 238]
Summary: java-pkg-simple.eclass: Support building multi-release JAR files [JEP 238]
Status: CONFIRMED
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: Eclasses (show other bugs)
Hardware: All Linux
: Normal normal
Assignee: Java team
URL:
Whiteboard:
Keywords: PullRequest
Depends on: 900767
Blocks:
  Show dependency tree
 
Reported: 2023-03-08 22:15 UTC by Yuan Liao (Leo3418)
Modified: 2025-04-01 13:58 UTC (History)
1 user (show)

See Also:
Package list:
Runtime testing required: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Yuan Liao (Leo3418) 2023-03-08 22:15:44 UTC
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.
Comment 1 Yuan Liao (Leo3418) 2023-03-08 22:21:43 UTC
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
Comment 2 Larry the Git Cow gentoo-dev 2025-04-01 13:58:40 UTC
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(-)