The craftsman may be late, but he is never absent. Finally, he decided to share his cloud notes

background

Java 9 has enhanced support for multiple versions of the Jar bytecode file format, which means that we can include multiple Java versions of the class file in the same Jar. This allows Jar packages to be upgraded to the new Java version (used by the new feature API) without forcing users to upgrade their business module Java versions in order to use the new Jar package, and without providing different JARS for different lowest-supported Java versions. Truly achieving a Jar package compatible for all purposes. Such jars are called MRJars.

The code in MRJAR contains class files compiled under different versions of the JDK. For example, classes compiled using JDK9 can call the API provided by JDK9, and classes compiled using JDK8 can call the API provided by JDK8, as long as their MRJAR package name, class name, and class call are consistent.

MRJAR rules

A typical JAR package contains a class file and a meta-INF/manifest.mf file, as follows:

- jar-root
  - A.class
  - B.class
  - C.class
- META-INF
  - MANIFEST.MF
Copy the code

MRJAR extends the JAR directory structure by extending the meta-INF directory to store class files for a particular JDK version. The meta-INF directory contains a version subdirectory, which may contain many subdirectories, each named the same as the main JDK version. For example, jdk9-specific classes can be placed under meta-INF /versions/9, jdk10-specific classes can be placed under meta-INF /versions/10, etc. So a typical MRJAR package would look like this:

- jar-root
  - A.class
  - B.class
  - C.class
- META-INF
  - MANIFEST.MF
  - versions
    - 9
      - A.class
      - D.class
    - 10
      - A.class
      - B.class
Copy the code

The above example runs in different JDK environments as follows:

  • If the MRJAR is used in a JDK environment that does not support MRJARS (such as JDK8), it is automatically compatible with being used as a normal JAR, i.eMETA-INF/versions/Directory is ignored, directly use the root class, so can not access D.
  • If the MRJAR is used in JDK9, only classes A, B, C, and D can be usedMETA-INF/versions/9/The class below, and the other classes in the root directory.
  • For JDK10, the principle is similar to that of JDK9, which is not explained here. It’s just that when we use class C in the JDK10 environment, the search order is firstMETA-INF/versions/10/If C exists, search for itMETA-INF/versions/9/If C does not exist, search the root directory for C, the order of search must be clear.
  • For JDK11, it doesn’t existMETA-INF/versions/11/, so in order to search for the lower version of the class, which in this case is equivalent to the hit class under JDK10.

Making MRJAR

JDK9 to generate JAR package various commands and tools are upgraded to support MRJAR, so making MRJAR directly using the best JDK9 began to environment, the JAR command a new parameters for release, syntax is as follows:

//N represents a major JDK version, such as 9 in JDK9, and the N value must be greater than or equal to 9. // All files after --release N will be added to MRJAR meta-INF /versions/N; jar <options> --release N <other-options>Copy the code

Suppose we now have a set of JDK8 classes and a set of JDK12 classes and their compiled products as follows:

//JDK8 source file, the compile product directory is assumed to be JDK8 /build/classes/
package cn.yan.mrjar;

public class JarUtil {
    public String func(a) {
        //JDK8 API implementation function}}//JDK12 source file, the compile product directory is assumed to be JDK12 /build/classes/
package cn.yan.mrjar;

public class JarUtil {
    public String func(a) {
        //JDK12 API implementation function}}Copy the code

We then generate an MRJAR for each of the above versions with the following command:

jar --create --verbose --file test-out.jar
-C jdk8/build/classes .
--release 12 -C jdk12/build/classes .
Copy the code

The JarUtil classes in JDK12 will be placed in meta-INF /versions/12/, and the JarUtil classes in JDK8 will be placed in root. The MRJAR decompression structure is as follows:

- jar-root
  - cn
    - yan
      - mrjar
        - JarUtil.class
- META-INF
  - MANIFEST.MF
  - versions
    - 9
      - cn
        - yan
          - mrjar
            - JarUtil.class
Copy the code

This will be able to make the above good MRJAR in different JDK environment to use, you say great is not great, feel used to read at the same time to send your good gay friends.

[Artisans if the water is not reproduced without permission, please respect the author’s labor achievements]