mrJar usage | lingocoder

5 min read Original article ↗
mrJar mrJar
Modular MRJAR Files Made Easy¹   Usage:  
    /* (1) Decide which type of module artifact your project needs to produce and proceed accordingly         */
    /*                                                                                                        */
    /*     (a) A Single-Release Jar File that targets a single JDK release and packages a single module       */
    /*         • DO NOT set any JDK release environment variables. Proceed to (2)                             */
    /*                                                                                                        */
    /*     (b) A Multi-Release Jar File that targets two or more Java 9+ releases.                            */
    /*         • Set an environment variable for each JDK release you want to support. For example,           */
    /*           if you want to support JDKs 8, 11 and 17, you must set three environment variables; one      */
    /*           named JAVA_8, another named JAVA_11 and the last one named JAVA_17.                          */
    /*                                                                                                        */
    /*           The environment variables must point to the file system installations of JDK versions 8, 11  */ 
    /*           and 17 respectively.                                                                         */
    /*                                                                                                        */
    /* (2) Apply the mrJar plugin using the plugins DSL.                                                      */
    plugins{
        id 'com.lingocoder.mrjar' version '1.0.1'
    }
		
    /* (3) Configure repositories. */
    repositories { mavenCentral() }

    dependencies {
        /* Declare your api|implementation|testImplementation dependencies required by your system. */
        api 'org.apache.commons:commons-math4-core:4.0-beta1'
        implementation 'com.google.guava:guava:32.0.1-jre'
    }

    mrjar {
        /* (4) Tell mrJar which releases you want your MRJAR to support                       */
        /*     • This property is mandatory. Values must be Gradle's JavaVersion constants    */
        releases = [JavaVersion.VERSION_11, JavaVersion.VERSION_17, JavaVersion.VERSION_21]
 
        /* (5) Optionally, you can tell mrJar to create the packages you need                 */
        /*     • Each package in the list will be created in each release src directory       */
        packages = ['org.example.foo', 'io.another.one']

        /* (6) Optionally, tell mrJar your existing project already is a Java module          */
        /*     • Or just the existence of a module-info.java file has the same effect         */
        isModular = true

        /* (7) Optionally, tell mrJar to use a specific name for your module                  */
        /*     • By default, mrJar uses the project name and version                          */
        moduleName = 'org.example.foo.bar'

        /* (8) Optionally, tell mrJar to generate module-info.java descriptors                */
        /*     • Defaults to false. If true, generates descriptors in release src dirs        */
        generateModuleInfo = true

        /* (9) Optionally, provide JPMS options for compilation/execution                     */
        /* jpmsOpts = ['--add-modules', 'jdk.incubator.vector']                               */

        /* (10) Optionally — or, mandatorily if you're using Gradle's Application             */
        /*     Plugin to execute a Java application bundled in your module — tell             */
        /*     mrJar the binary name of the class you want the Application Plugin to run      */
        /*     • The value of this property will automatically propagate to the               */
        /*       Application Plugin's :run task                                               */
        /* main = 'com.acme.main.JavaMain'                                                    */
    }
  From the command line, run:  
    $ ./gradlew mrinit
 What mrinit gets you is a source directory hierarchy for each release you specified. So for the above example, folders at src/main/java11, src/main/java17 and src/main/java21 will have been created. After that initial setup, you will, of course, need to populate the source directories with the source code for each respective release to be supported by your MRJAR. If you're going the modular jar² route — a single-release module that is just one single library per jar file is not an uncommon use case.  
 After you have all your release source folders, your packages hierarchy, your module descriptors and, of course, your actual source code in place, that's pretty much it. The mrinit task is more or less³ a one-time deal; just to initialize your releases in preparation for their eventual bundling into the artifact your project will ultimately produce. After you run mrinit the one time, you then simply proceed with your typical test/develop/build cycle exactly as you ordinarily would. Then, when you want to publish the artifacts of your project, you do that too exactly like you normally would. Nothing different:
    $ ./gradlew publish
 So for example, the mrJar plugin uses itself to build itself as a modular MRJAR File. As I developed the plugin, I did the steps outlined above. Because I used Gradle's Java Plugin Development Plugin, I ran the :publish task often. The output of that built-in task was my plugin's jar as a modular MRJAR File. Which I used during development on the plugin itself (dog-fooding). Likewise, when I published the plugin to Gradle's Plugin Portal. In that use case, you just use the Plugin Publishing Plugin as usual:
    $ ./gradlew publishPlugin
 In the presense of any plugin that relies on Gradle's built-in :jar task, mrJar in the mix enhances Gradle's built-in :jar to be MRJAR-capable. However, mrJar itself does not provide its own custom task for creating MRJARs.
 Any and all questions or suggestions are welcomed. Please do not hesitate to message me about anything. I'd be thrilled to hear from you.
__________
¹I recommend running Gradles init task to generate a skeleton java-library project super quickly.
²It's important to bear in mind that Modular Jars are distinct from Multi-Release Jars. They are related. But they are not the same. You can have one, but it will not neccessarily mean you also have the other.
³To generate module-info descriptors, you can run the mrinit task at any point; even in an existing project.