Dependening on legacy jar in Java 9 Module System library using gradle

2.7k views Asked by At

Problem

How do you create a java library jar that both:

  • is java module (has module-info)
  • has a depending legacy (non-module) jar. (like commons-exec)?

The dependency is an implementation detail - should not be exported.

Sources

Having the following build.gradle (using gradle-6.8):

plugins {
    id 'java-library'
}

group = 'test'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '15'

repositories {
    mavenCentral()
}
java {
    modularity.inferModulePath = true
}

dependencies {
    implementation 'org.apache.commons:commons-exec:1.3'
}

and the following module-info.java:

module test.module {
    requires commons.exec;
}

Errors

I'm getting the following compile error:

module-info.java:2: error: module not found: commons.exec
    requires commons.exec;
                    ^

If I don't include requires commons.exec then the error becomes:

error: package org.apache.commons.exec is not visible
import org.apache.commons.exec.CommandLine;
                         ^
  (package org.apache.commons.exec is declared in the unnamed module,
   but module test.module does not read it)

commons.exec module name?

Running jar --file=commons-exec-1.3.jar --describe-module does output:

No module descriptor found. Derived automatic module.

[email protected] automatic
requires java.base mandated
contains org.apache.commons.exec
contains org.apache.commons.exec.environment
contains org.apache.commons.exec.launcher
contains org.apache.commons.exec.util

So commons.exec looks like a valid module name for commons-exec-1.3.jar. Intelij Idea seem to agree and does auto-complete it in module-info.java. Though it fails at build time.

1

There are 1 answers

0
eHayik On BEST ANSWER

I managed to overcome the same issue using java-module-info plugin.

This plugin allows you to add module information to a Java library that does not have any. If you do that, you can give it a proper module name and Gradle can pick it up to put it on the module path during compilation, testing and execution.

plugins {
   id 'java-library'
   id("de.jjohannes.extra-java-module-info") version "0.6"
}

Add this section into your build.gradle to add the commons-exec module information

  extraJavaModuleInfo {
    module("commons-exec-1.3.jar", "org.apache.commons.exec", "1.3") {
        exports("org.apache.commons.exec")
    }
}

Add requires org.apache.commons.exec; to your module-info.java

EDIT 1:

Gradle 7.0 comes with full support for the Java module system. Users can now build, test, and run Java modules via Gradle. The mere presence of module-info.java will let Gradle infer that your jar is a module and has to be put on the modulepath instead of the traditional classpath.

Using libraries that are not modules