pgjdbc/pgjdbc GitHub issues and pull requests (mirror)  
help / color / mirror / Atom feed
From: vlsi (@vlsi) <[email protected]>
To: pgjdbc/pgjdbc <[email protected]>
Subject: [pgjdbc/pgjdbc] PR #4152: build: 42.6 compile with a Java 17 toolchain, run tests on multiple JDKs
Date: Thu, 04 Jun 2026 07:36:37 +0000
Message-ID: <[email protected]> (raw)

## Why

On the 42.6 branch the build compiled with whatever JVM ran Gradle and pinned source/target compatibility to Java 8, so the build JDK and the test JDK were always the same. That makes it impossible to compile on a modern JDK while still running the test suite on the older JDKs we support. This backports master's `build-logic` toolchain approach to 42.6.

## What

- `build-logic/build-parameters`: add `jdkBuildVersion` (default 17) and `jdkTestVersion` (default 0) parameters.
- `build-logic.java.gradle.kts`: replace the fixed `sourceCompatibility`/`targetCompatibility` with a Gradle toolchain selected by `jdkBuildVersion`. `JavaCompile` emits Java 8 bytecode via `--release 8` when the compiler is javac 9+.
- `build-logic.test-base.gradle.kts`: select a test JDK via a toolchain launcher when `jdkTestVersion` is set, and forward only `pgjdbc.*` system properties to the test JVM (the build JVM's `java.*` properties must not leak into a test JVM on a different Java version).
- CI (`main.yml`): run Gradle on JDK 17 and run tests on the matrix JDK via `jdkTestVersion=${{ matrix.java_version }}`. Build JDK moves from 11 to 17 for `linux-checkerframework` and `source-distribution-check`. `buildcache.yml` seeds on JDK 17.

The build JDK is **17** and the produced bytecode targets **Java 8** (`--release 8`).

## How to verify

Verified locally with `JAVA_HOME` set to JDK 17:

- `./gradlew :postgresql:compileJava` compiles with the JDK 17 toolchain (`--info` shows `Compiling with toolchain '.../17.0.10-librca'`).
- `org/postgresql/Driver.class` has bytecode major version **52** (Java 8), confirming `--release 8` works while compiling on JDK 17.
- `./gradlew :postgresql:test -PjdkTestVersion=8 --tests 'org.postgresql.util.PGtokenizerTest'` runs the test on JDK 8 — the Gradle Test Executor launched `.../8.0.402-librca/bin/java` and the suite passed (5 tests, 0 failures).

CI changes were verified by reading only; all edited YAML files pass `yaml.safe_load`.

## Notes

- This backports master's `build-logic` toolchain mechanism, adapted to 42.6's simpler `build-parameters` setup.
- ARM64: the x64 path (the one CI uses) is the focus. On ARM64 the workflow now installs both the test JDK and JDK 17, but `org.gradle.java.installations.fromEnv` is x64-named (`JAVA_HOME_*_X64`); wiring ARM64 toolchain discovery is left as a best-effort follow-up.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

diff --git a/.github/workflows/buildcache.yml b/.github/workflows/buildcache.yml
index 9386ef4b36..5a0179f33a 100644
--- a/.github/workflows/buildcache.yml
+++ b/.github/workflows/buildcache.yml
@@ -43,7 +43,7 @@ jobs:
     strategy:
       matrix:
         os: [ubuntu, macos, windows]
-        jdk: [8, 11]
+        jdk: [17]
 
     name: '${{ matrix.os }}, ${{ matrix.jdk }} seed build cache'
     runs-on: ${{ matrix.os }}-latest
@@ -56,10 +56,6 @@ jobs:
         with:
           java-version: ${{ matrix.jdk }}
           distribution: liberica
-      - name: Skip javadoc with Java 11
-        if: ${{ matrix.jdk == '11' }}
-        run: |
-          echo "skipJavadoc=-PskipJavadoc" >> $GITHUB_ENV
       - uses: burrunan/gradle-cache-action@v1
         name: Build pgjdbc
         env:
@@ -67,4 +63,4 @@ jobs:
           S3_BUILD_CACHE_SECRET_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_KEY }}
         with:
           job-id: jdk${{ matrix.jdk }}
-          arguments: build -x test --scan -i ${{ env.skipJavadoc }}
+          arguments: build -x test --scan -i
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index a97b958efa..fe31ac6dd4 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -44,7 +44,7 @@ jobs:
     - uses: actions/checkout@v4
       with:
         fetch-depth: 50
-    - name: 'Set up JDK 8'
+    - name: 'Set up JDK 17'
       uses: actions/setup-java@v3
       with:
         distribution: zulu
@@ -65,11 +65,11 @@ jobs:
       - uses: actions/checkout@v4
         with:
           fetch-depth: 50
-      - name: 'Set up JDK 11'
+      - name: 'Set up JDK 17'
         uses: actions/setup-java@v3
         with:
           distribution: zulu
-          java-version: 11
+          java-version: 17
       - uses: burrunan/gradle-cache-action@v1
         name: Run CheckerFramework
         env:
@@ -81,7 +81,7 @@ jobs:
           arguments: --scan --no-parallel --no-daemon -PenableCheckerframework classes
 
   source-distribution-check:
-    name: 'Source distribution (JDK 11)'
+    name: 'Source distribution (JDK 17)'
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
@@ -90,11 +90,11 @@ jobs:
       - name: Start PostgreSQL
         working-directory: docker/postgres-server
         run: docker compose up -d && docker compose logs
-      - name: 'Set up JDK 11'
+      - name: 'Set up JDK 17'
         uses: actions/setup-java@v3
         with:
           distribution: zulu
-          java-version: 11
+          java-version: 17
       - uses: burrunan/gradle-cache-action@v1
         name: Prepare source distribution
         env:
@@ -166,20 +166,30 @@ jobs:
     - name: 'Get test node ARCH'
       run: echo "arch_name=$(uname -i)" >> $GITHUB_OUTPUT
       id: get_arch_name
-    - name: Set up Java ${{ matrix.java_version }}, ${{ matrix.java_distribution }}
+    - name: Set up test JDK ${{ matrix.java_version }} and build JDK 17, ${{ matrix.java_distribution }}
       if: ${{ steps.get_arch_name.outputs.arch_name != 'aarch64' }}
       uses: actions/setup-java@v3
       with:
-        java-version: ${{ matrix.java_version }}
+        # Gradle runs on the last entry (JDK 17), and the toolchain runs the tests on matrix.java_version
+        java-version: |
+          ${{ matrix.java_version }}
+          17
         distribution: ${{ matrix.java_distribution }}
         architecture: x64
-    - name: 'Setup JDK ${{ matrix.java_version }} on ARM64'
+    - name: 'Setup test JDK ${{ matrix.java_version }} on ARM64'
       if: ${{ steps.get_arch_name.outputs.arch_name == 'aarch64' }}
       uses: AdoptOpenJDK/install-jdk@v1
       with:
         impl: hotspot # or openj9
         version: ${{ matrix.java_version }}
         architecture: aarch64
+    - name: 'Setup build JDK 17 on ARM64'
+      if: ${{ steps.get_arch_name.outputs.arch_name == 'aarch64' }}
+      uses: AdoptOpenJDK/install-jdk@v1
+      with:
+        impl: hotspot # or openj9
+        version: '17'
+        architecture: aarch64
     - name: Prepare local properties
       run: |
         # See https://github.com/actions/runner/issues/409
@@ -203,6 +213,11 @@ jobs:
         properties: |
           includeTestTags=${{ matrix.includeTestTags }}
           testExtraJvmArgs=${{ matrix.testExtraJvmArgs }}
+          jdkBuildVersion=17
+          jdkTestVersion=${{ matrix.java_version }}
+          org.gradle.java.installations.fromEnv=JAVA_HOME_${{ matrix.java_version }}_X64,JAVA_HOME_17_X64
+          # We provision JDKs with GitHub Actions for caching purposes, so Gradle should rather fail in case JDK is not found
+          org.gradle.java.installations.auto-download=false
 
     - name: 'Install krb5 for GSS tests'
       if: ${{ matrix.gss == 'yes' }}
diff --git a/build-logic/build-parameters/build.gradle.kts b/build-logic/build-parameters/build.gradle.kts
index 82383dcce4..bc69b1682a 100644
--- a/build-logic/build-parameters/build.gradle.kts
+++ b/build-logic/build-parameters/build.gradle.kts
@@ -16,6 +16,14 @@ buildParameters {
         defaultValue.set(false)
         description.set("Collect test coverage")
     }
+    integer("jdkBuildVersion") {
+        defaultValue.set(17)
+        description.set("Java version used to compile the driver via a Gradle toolchain. 0 uses the JVM that runs Gradle.")
+    }
+    integer("jdkTestVersion") {
+        defaultValue.set(0)
+        description.set("Java version used to run tests via a Gradle toolchain. 0 reuses the build JVM.")
+    }
     bool("spotbugs") {
         defaultValue.set(false)
         description.set("Run SpotBugs verifications")
diff --git a/build-logic/jvm/src/main/kotlin/build-logic.java.gradle.kts b/build-logic/jvm/src/main/kotlin/build-logic.java.gradle.kts
index 901e91de02..adadd42d55 100644
--- a/build-logic/jvm/src/main/kotlin/build-logic.java.gradle.kts
+++ b/build-logic/jvm/src/main/kotlin/build-logic.java.gradle.kts
@@ -2,6 +2,7 @@ import com.github.vlsi.gradle.crlf.CrLfSpec
 import com.github.vlsi.gradle.crlf.LineEndings
 import com.github.vlsi.gradle.dsl.configureEach
 import com.github.vlsi.gradle.properties.dsl.props
+import org.gradle.jvm.toolchain.JavaLanguageVersion
 import java.time.LocalDate
 
 plugins {
@@ -16,8 +17,11 @@ plugins {
 }
 
 java {
-    sourceCompatibility = JavaVersion.VERSION_1_8
-    targetCompatibility = JavaVersion.VERSION_1_8
+    buildParameters.jdkBuildVersion.takeIf { it != 0 }?.let {
+        toolchain {
+            languageVersion.set(JavaLanguageVersion.of(it))
+        }
+    }
 }
 
 sourceSets {
@@ -48,6 +52,8 @@ tasks.configureEach<JavaCompile> {
     inputs.property("java.vm.version", System.getProperty("java.vm.version"))
     options.apply {
         encoding = "UTF-8"
+        // Target Java 8 bytecode without referencing Java 9+ API (--release needs javac 9+).
+        release.set(provider { 8.takeIf { javaCompiler.get().metadata.languageVersion.asInt() > 9 } })
         compilerArgs.add("-Xlint:deprecation")
         if (JavaVersion.current().isJava9Compatible) {
             // See https://bugs.openjdk.org/browse/JDK-8032211
diff --git a/build-logic/jvm/src/main/kotlin/build-logic.test-base.gradle.kts b/build-logic/jvm/src/main/kotlin/build-logic.test-base.gradle.kts
index dec93446ca..97c7fa4751 100644
--- a/build-logic/jvm/src/main/kotlin/build-logic.test-base.gradle.kts
+++ b/build-logic/jvm/src/main/kotlin/build-logic.test-base.gradle.kts
@@ -3,10 +3,18 @@ import com.github.vlsi.gradle.properties.dsl.props
 import org.gradle.api.tasks.testing.Test
 
 plugins {
+    id("java-library")
     id("build-logic.build-params")
 }
 
 tasks.configureEach<Test> {
+    buildParameters.jdkTestVersion.takeIf { it != 0 }?.let {
+        javaLauncher.set(
+            javaToolchains.launcherFor {
+                languageVersion.set(org.gradle.jvm.toolchain.JavaLanguageVersion.of(it))
+            }
+        )
+    }
     inputs.file("../build.properties")
     if (file("../build.local.properties").exists()) {
         inputs.file("../build.local.properties")
@@ -36,7 +44,9 @@ tasks.configureEach<Test> {
     val props = System.getProperties()
     @Suppress("UNCHECKED_CAST")
     for (e in props.propertyNames() as `java.util`.Enumeration<String>) {
-        if (e.startsWith("pgjdbc.") || e.startsWith("java")) {
+        // Forward only pgjdbc.* properties; the build JVM's java.* props must not leak into a
+        // test JVM that may run on a different Java version.
+        if (e.startsWith("pgjdbc.")) {
             passProperty(e)
         }
     }


reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: github://pgjdbc/pgjdbc
  Cc: [email protected], [email protected]
  Subject: Re: [pgjdbc/pgjdbc] PR #4152: build: 42.6 compile with a Java 17 toolchain, run tests on multiple JDKs
  In-Reply-To: <<[email protected]>>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox