Code for different Java versions in same Gradle Project

1.6k Views Asked by At

Is it possible to create a Gradle Project in a way so that the major part can be used with one Java version (e.g. Java 11) while some parts rely on a higher Java version (e.g. Java 17) and can only be used by clients with Java 17?

It should be possible to use dependencies compiled for Java 17 in Java-17-parts. The part of the project that is compiled for Java 11 should also be usable from the Java 17 code.

It should also be possible to import the project in the exact same way into other projects and use the Java 17 parts of the project only if they use Java 17 by themselves.

1

There are 1 best solutions below

0
On BEST ANSWER

Multi-Release JARs can be used for this. Multi-Release JARs allow to create classes that are loaded only in specific Java versions.

You can do that by specifying a source set for Java 17 and keeping your main source set for Java 11. You make the Java 17 source set to use be able to access Java 11 code as well.

Furthermore, you specify a task for compiling Java 17 code with a custom source and target compatibility and the source set for Java 17.

Normal (Java 11) source code goes to src/main/java will Java 17 source code goes to src/java17/java.

When creating a JAR, the Java 17 build output is moved to META-INF/versions/16 making it available for Java 16+ only.

Using the Kotlin DSL, your build.gradle.kts could look like this:

plugins {
    id("java")
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    //Java 11 dependencies here (available for all code)
}
tasks {
    jar {//configure JAR creation
        dependsOn("compileJava17")//requires Java 17 code to be built
        into("META-INF/versions/17") {//move Java 17 code into META-INF/versions/17
            from(sourceSets["java17"].output)//take it from Java 17 output folder
        }
        manifest {
            attributes("Multi-Release" to "true")//configure it to be recognized as a Multi-Release JAR
        }
    }

}
sourceSets.create("java17") {//create Java 17 source set
    this.java.srcDir("src/java17/java")//where to put sources
    dependencies {
        //Java 17 dependencies here (only available for Java 17 code)
    }
    //include Java 11 source code (make it accessible from Java 17)
    compileClasspath += sourceSets["main"].output
    runtimeClasspath += sourceSets["main"].output
}
java {
    //configure project to use Java 11
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
    sourceSets["main"]//use main source set
}
task<JavaCompile>("compileJava17") {//create task for Java 17
    dependsOn("compileJava")//requires normal Java compilation to be finished
    //set source and target compatibility
    sourceCompatibility = JavaVersion.VERSION_17.name
    targetCompatibility = JavaVersion.VERSION_17.name
    sourceSets["java17"]//use Java 17 source set
}