# Build on latest Java, test through lowest Java

DevFeed: [Build on latest Java, test through lowest Java](<https://devfeed.tech/articles/build-on-latest-java-test-through-lowest-java-20920.md>)

Original publisher: [Read original article](<https://jakewharton.com/build-on-latest-java-test-through-lowest-java/>)

Published: 2022-05-17T00:00:00Z

Content type: tutorial

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [ci](<https://devfeed.tech/topics/ci.md>), [Gradle](<https://devfeed.tech/topics/gradle.md>), [Java](<https://devfeed.tech/topics/java.md>), [Testing](<https://devfeed.tech/topics/testing.md>), [toolchains](<https://devfeed.tech/topics/toolchains.md>), [Open Source](<https://devfeed.tech/topics/open-source.md>)

Tags: [ci](<https://devfeed.tech/tags/ci.md>), [gradle](<https://devfeed.tech/tags/gradle.md>), [java](<https://devfeed.tech/tags/java.md>), [open-source](<https://devfeed.tech/tags/open-source.md>), [testing](<https://devfeed.tech/tags/testing.md>), [toolchains](<https://devfeed.tech/tags/toolchains.md>), [verification](<https://devfeed.tech/tags/verification.md>)

## AI overview

This article explains how to use Gradle toolchains to compile a Java project once with the latest Java version while running tests across every supported version down to the lowest. The approach reduces CI workload and is especially useful for projects whose behavior or API usage varies by Java version.

## Source excerpt

In the past, when a new version of Java was released, I would add that version to our open source project's CI builds. strategy: matrix: java-version: - 8 - 9 ⋮ - 17 + - 18 This ensures that each project can be built and its tests pass on every major version. But this makes no sense! No user is building these projects on different versions. No user is building these projects at all. Consumers are using the pre-built .jar which we ship to Maven Central built on a single version. Testing on every version, however, is something extremely valuable. Thankfully, Gradle toolchains let us retain this while still only building once. First, CI only has to build on a single version. We choose the latest because Java has excellent cross-compilation capabilities, and we want to be using the latest tools. - uses: actions/setup-java@v2 with: distribution: 'zulu' - java-version: ${{ matrix.java-version }} + java-version: 18 Second, unchanged from before, we still target whichever Java version is the lowest supported through either the --release flag or sourceCompatibility/targetCompatibility per the Gradle docs. And finally, we set up tests to run on every supported version. // Normal test task runs on compile JDK. (8..17).each { majorVersion -> def jdkTest = tasks.register("testJdk$majorVersion", Test) { javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(majorVersion) } description = "Runs the test suite on JDK $majorVersion" group = LifecycleBasePlugin.VERIFICATION_GROUP // Copy inputs from normal Test task. def testTask = tasks.getByName("test") classpath = testTask.classpath testClassesDirs = testTask.testClassesDirs } tasks.named("check").configure { dependsOn(jdkTest) } } This setup reduces CI burden since we only compile the main and test sources once but execute the tests on every supported version from latest to lowest. Verification tasks ------------------ check - Runs all checks. test - Runs the test suite. testJdk10 - Runs the test sui