Skip to content
Advertisement

Gradle build – add module path

My question: How do I set a module path for gradle build?

I’ve become comfortable working with Java modules from the command line. I do a frequent exercise in Powershell which results in these source files.

└───src
    ├───appMod
    │   │   module-info.java
    │   │
    │   └───appPack
    │           Entry.java
    │
    └───greetMod
        │   module-info.java
        │
        └───greetPack
                Hello.java

appMod/module-info

module appMod {
    requires greetMod;
}

appMod/appPack.Entry

package appPack;

import greetPack.Hello;

public class Entry {
    public static void main(String[] args) {
        System.out.println(new Hello().sayHello());
    }
}

greetMod/module-info

module greetMod {
    exports greetPack;
}

greetMod/greetPack.Hello

package greetPack;

public class Hello {
    public String sayHello() {
        return "Greetings from Hello class!";
    }
}

Since the appMod module requires greetMod, I compile and jar greetMod first.

javac -d out/greetMod src/greetMod/module-info.java src/greetMod/greetPack/Hello.java;
jar cf lib/greetJar.jar -C out/greetMod .;

Then I compile and jar appMod, but as I do so I specify the module path (-p) where the new greetMod jar (greetJar) can be found (in lib).

javac -d out/appMod -p lib src/appMod/module-info.java src/appMod/appPack/Entry.java;
jar cfe lib/appJar.jar appPack.Entry -C out/appMod .;

I can then run this or jlink it in part by adding a module path.

java -p lib -m appMod;
jlink -p lib --add-modules appMod --launcher launch=appMod --output dist;
dist/bin/launch

I now want to do this same exercise in Gradle, but I can’t figure out how to do the equivalent of setting a module path such as -p lib. I’ve seen code for sourceSets, and countless variations of dependencies, but so far I haven’t been able to put together something that works. I’ve also read conflicting statements that both say that Gradle doesn’t fully support Java modules, and that Gradle does support them.

Advertisement

Answer

I know it can be confusing, but it can definitely be done by gradle. You will need to use a multiproject build to have this work. In your top-most build.gradle, do this:

subprojects {
    apply plugin: 'java'

    sourceCompatibility = 1.9

    compileJava {
        doFirst {
            options.compilerArgs += [
                    '--module-path', classpath.asPath
            ]
            classpath = files()
        }
    }
}

In your settings.gradle:

rootProject.name = 'module-testing'

include 'src:greetMod'
include 'src:appMod'

Everything inside appMod should be moved into a folder called appModSrc. Do the same for greetMod so use greetModSrc.


greetMod

Directory structure:

├── build.gradle
└── greetModSrc
    ├── greetPack
    │   └── Hello.java
    └── module-info.java

build.gradle

sourceSets {
    main {
        java {
            srcDirs 'greetModSrc'
        }
    }
}

appMod

Directory structure:

├── appModSrc
│   ├── appPack
│   │   └── Entry.java
│   └── module-info.java
└── build.gradle

build.gradle

plugins {
    id 'application'
}

sourceSets {
    main {
        java {
            srcDirs 'appModSrc'
        }
    }
}

application {
    mainClassName 'appPack.Entry'
}

jar {
    doFirst {
        manifest {
            attributes('ModuleMainClass': mainClassName)
        }
    }
}

dependencies {
    implementation project(':src:greetMod')
}

With this setup, you can simply run ./gradlew :src:appMod:run:

> Task :src:appMod:run
Greetings from Hello class!

You can download the idea project here: https://github.com/MVCE-Superstars/multi-java9-gradle

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement