gradle Jigsaw module not found
Asked Answered
A

1

4

I try to run a very simple gradle project which uses java 9 modules, but i receive the following error.

/home/vadim/IdeaProjects/test_modules/src/main/java/module-info.java:2: error: module not found: HdrHistogram
    requires HdrHistogram;
             ^

Here is it https://github.com/vad0/test_modules. The main class does basically nothing.

package app;

import org.HdrHistogram.Histogram;

public class RunHdr {
    public static void main(String[] args) {
        final Histogram histogram = new Histogram(5);
        System.out.println(histogram);
    }
}

It uses only one dependency: HdrHistogram. I included this magic command in build.gradle according to official gradle tutorial https://docs.gradle.org/current/samples/sample_java_modules_multi_project.html.

java {
    modularity.inferModulePath = true
}

The whole build.gradle looks like this.

plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

java {
    modularity.inferModulePath = true
}

dependencies {
    compile group: 'org.hdrhistogram', name: 'HdrHistogram', version: '2.1.12'
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

module.info looks like this

module test.modules.main {
    requires HdrHistogram;
}

I have already read a number of tutorials on Jigsaw and a whole bunch of stackoverflow questions related to it, but still can't make this simple example work. How do i fix it?

Thank you

Amongst answered 1/8, 2020 at 10:9 Comment(7)
Strange! I use maven and I was able to add the module HdrHistogram using the same artifact version.Thomasson
Switching from gradle to maven is not an option for me unfortunatelyAmongst
@Thomasson do you happen to know what maven does to make this an automatic module?All
@All Without diving into the actual code, from the build logs what Maven seems to be doing is to first identify all the dependencies on the compile path. Then based on the artifacts/jars which are themself modular i.e. includes module descriptor, or declaring Automatic-Module-Name in META-INF, or any other artifact which is a part of the module-info.java of the maven module itself is treated to be on the module-path instead of the classpath. The logs shared have two components to make that difference clear.Thomasson
@Thomasson here is how gradle does it via a plugin by a gradle core author. This is a thing of beauty! The idea is not that complicated, but it's very nice. They let you define module-info.java for non-modular jars. Have i said that I love it already?All
@All On the maven side of things and in terms of plugins, Gunnar's work over moditect-maven-plugin seems quite comparable. Though I haven't really explored it but have noticed some open-ended threads out here as well. In the longer term, I wouldn't really be looking out for a plugin to let me explicitly override a module descriptor for a library that itself doesn't choose to. (Things like these add to the reasons why people in our org don't want to migrate.)Thomasson
@Thomasson good to know. Thx.All
A
6

Unfortunately, gradle does not treat every jar as a module (in simple words). If you want to find out how exactly is gradle building the module-path (as opposed to class-path), you probably want to start from here, specifically at the isModuleJar method. It's pretty easy to understand (though it took me almost two days to set-up gradle and debug the problem out) that the dependency that you are trying to use : gradle says that it is not a module (it isn't wrong, but I am not sure it is correct either). To make it very correct, gradle will add your dependency to the CLASSPATH, but in the very next line: it will not add your dependency to the module-path, because if fails the filter in isModuleJar.

I do not know if this is a bug or not, or may be this is on purpose, but the solution is easy:

plugins.withType(JavaPlugin).configureEach {
    java {
        modularity.inferModulePath = true
    }

    tasks.withType(JavaCompile) {
        doFirst {
            options.compilerArgs = [
                '--module-path', classpath.asPath,
            ]
            classpath = files()
        }
    }
}

you add it to the path, on purpose. I will flag this as a defect and let's see what they have to say.

EDIT

Even better, use a plugin that is written by a gradle commiter:

plugins {
    id 'java'
    id 'de.jjohannes.extra-java-module-info' version "0.1"
}

And the easiest option on your case is to do :

extraJavaModuleInfo {
     automaticModule("HdrHistogram-2.1.12.jar", "HdrHistogram")
}
All answered 17/8, 2020 at 19:7 Comment(1)
This is wonderful! Thanks a lot @Eugene. But overall it looks like very few people use modules+gradle these days.Amongst

© 2022 - 2024 — McMap. All rights reserved.