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 #4151: build: 42.3 compile with a Java 17 toolchain, run tests on multiple JDKs
Date: Thu, 04 Jun 2026 07:35:20 +0000
Message-ID: <[email protected]> (raw)

## Why

The 42.3.x build tied the compile JDK to the JVM running Gradle and set the target via `sourceCompatibility`/`targetCompatibility`. That makes it hard to build on a fixed JDK while testing against several Java versions — the model already used on `master`.

Rebased on top of the Gradle 7.6.6 migration on `release/42.3.x`. The build now uses a **Java 17 toolchain** (matching 42.4.x/42.5.x/42.6.x) while still emitting **Java 8 bytecode**.

## What

- Add a Gradle toolchain for the main modules. `jdkBuildVersion` (default 17) selects the compile JDK; the driver still targets Java 8.
- Replace `sourceCompatibility`/`targetCompatibility` with `javac --release 8`, guarded to javac 9+.
- Run the test task on a separate JDK via `-PjdkTestVersion` (0 reuses the build JVM), using a toolchain launcher.
- Stop forwarding the build JVM's `java.*` system properties to the test JVM; only `pgjdbc.*` is forwarded now, matching `master`.

### Making 42.3.x build on JDK 17

- **bnd**: bump `biz.aQute.bnd.builder` 4.3.1 → 6.3.1. 4.3.1 fails on JDK 17 (this broke `osgiJar`); 6.3.1 is already used on 42.5.x.
- **javadoc**: add `-Xdoclint:all,-missing`, drop the redirecting `javase/9` element-list links on JDK 17+, and document with `--release 8` so the `AccessController` deprecation-for-removal warning does not fail `-Xwerror`.
- **CheckerFramework** job runs on JDK 11; its pinned CheckerFramework 3.5.0 cannot access javac internals on JDK 16+.
- **test-gss**: bump its Gradle wrapper 6.1 → 7.6.6 (6.1 fails on JDK 17), plus the changes that requires — `testCompile` → `testImplementation` and `groovy-all` 2.5.12 → 3.0.11.
- **source distribution**: add a JDK 16+ Maven profile that opens `java.base` so System Stubs can mock environment variables under `mvn verify`.

## How to verify

```
./gradlew :postgresql:compileJava            # JDK 17 toolchain, Driver.class major version 52 (Java 8)
./gradlew :postgresql:javadocJar :postgresql:osgiJar   # clean on JDK 17
./gradlew :postgresql:test -PjdkTestVersion=8          # tests run on JDK 8
```

Verified locally on Gradle 7.6.6 / JDK 17: compile (bytecode 52), `javadoc`, `javadocJar`, `osgiJar`, `sourcesJar` all build cleanly; `-PjdkTestVersion=8` forks the test JVM on JDK 8 and passes; the source distribution's `mvn` tests (`OSUtilTest`, `PGPropertyPasswordParserTest`, `PGPropertyServiceParserTest`) pass on JDK 17.

## Notes

- `jdkBuildVersion` defaults to 17; pass `-PjdkBuildVersion=0` to compile with the current JVM.
- CI changes are verified by reading (they only run on GitHub Actions). The active matrix is x64 `ubuntu-latest`; the ARM64 path and `fromEnv` arch suffix (`_X64`) are 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 ef344a8df9..5923898686 100644
--- a/.github/workflows/buildcache.yml
+++ b/.github/workflows/buildcache.yml
@@ -40,7 +40,9 @@ jobs:
     strategy:
       matrix:
         os: [ubuntu, macos, windows]
-        jdk: [8, 11]
+        # build -x test does not run tests, so only the build JDK matters here.
+        # The driver compiles via a JDK 17 toolchain (still targeting Java 8 bytecode).
+        jdk: [17]
 
     name: '${{ matrix.os }}, ${{ matrix.jdk }} seed build cache'
     runs-on: ${{ matrix.os }}-latest
@@ -49,8 +51,9 @@ jobs:
         with:
           fetch-depth: 50
       - name: 'Set up JDK ${{ matrix.jdk }}'
-        uses: actions/setup-java@v1
+        uses: actions/setup-java@v3
         with:
+          distribution: zulu
           java-version: ${{ matrix.jdk }}
       - uses: burrunan/gradle-cache-action@v1
         name: Build pgjdbc
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 3e037f096a..381b10d537 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -41,11 +41,11 @@ 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
-        java-version: 8
+        java-version: 17
     - uses: burrunan/gradle-cache-action@v1
       name: Verify code style
       env:
@@ -62,6 +62,7 @@ jobs:
       - uses: actions/checkout@v4
         with:
           fetch-depth: 50
+      # CheckerFramework 3.5.0 cannot access javac internals on JDK 16+, so run it on JDK 11.
       - name: 'Set up JDK 11'
         uses: actions/setup-java@v3
         with:
@@ -75,10 +76,10 @@ jobs:
         with:
           read-only: ${{ matrix.os == 'self-hosted' }}
           job-id: checker-jdk11
-          arguments: --scan --no-parallel --no-daemon -PenableCheckerframework classes
+          arguments: --scan --no-parallel --no-daemon -PenableCheckerframework classes -PjdkBuildVersion=11
 
   source-distribution-check:
-    name: 'Source distribution (JDK 11)'
+    name: 'Source distribution (JDK 17)'
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
@@ -87,18 +88,18 @@ 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:
           S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ secrets.S3_BUILD_CACHE_ACCESS_KEY_ID }}
           S3_BUILD_CACHE_SECRET_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_KEY }}
         with:
-          job-id: source-release-jdk11
+          job-id: source-release-jdk17
           arguments: --scan --no-parallel --no-daemon sourceDistribution -Ppgjdbc.version=1.0 -Prelease
       - name: Verify source distribution
         working-directory: pgjdbc/build/distributions
@@ -117,7 +118,7 @@ jobs:
       run: |
         node -p "
           '::set-output name=matrix::' + JSON.stringify({
-            jdk: [
+            testJdkVersion: [
               8,
               11,
             ],
@@ -127,7 +128,7 @@ jobs:
           })"
 
   build-test:
-    name: 'Test - JDK ${{ matrix.jdk }} on ${{ matrix.os }}'
+    name: 'Test - build JDK 17, test JDK ${{ matrix.testJdkVersion }} on ${{ matrix.os }}'
     runs-on: ${{ matrix.os }}
     needs: matrix_prep
     strategy:
@@ -150,19 +151,23 @@ jobs:
     - name: 'Get test node ARCH'
       run: echo "::set-output name=arch_name::$(uname -i)"
       id: get_arch_name
-    - name: 'Set up JDK ${{ matrix.jdk }}'
+    - name: 'Set up test JDK ${{ matrix.testJdkVersion }} and build JDK 17'
       if: ${{ steps.get_arch_name.outputs.arch_name != 'aarch64' }}
       uses: actions/setup-java@v3
       with:
         distribution: zulu
-        java-version: ${{ matrix.jdk }}
+        # The last version becomes the default JAVA_HOME, so Gradle (and the build) runs on JDK 17.
+        # The test task is launched on JDK ${{ matrix.testJdkVersion }} via the Gradle toolchain.
+        java-version: |
+          ${{ matrix.testJdkVersion }}
+          17
         architecture: x64
-    - name: 'Setup JDK ${{ matrix.jdk }} on ARM64'
+    - name: 'Setup test JDK ${{ matrix.testJdkVersion }} and 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: ${{ matrix.jdk }}
+        version: ${{ matrix.testJdkVersion }}
         architecture: aarch64
     - name: Prepare ssltest.local.properties
       run: echo enable_ssl_tests=true > ssltest.local.properties
@@ -173,10 +178,14 @@ jobs:
         S3_BUILD_CACHE_SECRET_KEY: ${{ secrets.S3_BUILD_CACHE_SECRET_KEY }}
       with:
         read-only: ${{ matrix.os == 'self-hosted' }}
-        job-id: jdk${{ matrix.jdk }}
+        job-id: jdk${{ matrix.testJdkVersion }}
         arguments: --scan --no-parallel --no-daemon jandex test
         properties: |
           includeTestTags=!org.postgresql.test.SlowTests & !org.postgresql.test.Replication
+          jdkBuildVersion=17
+          jdkTestVersion=${{ matrix.testJdkVersion }}
+          org.gradle.java.installations.fromEnv=JAVA_HOME_${{ matrix.testJdkVersion }}_X64,JAVA_HOME_17_X64
+          org.gradle.java.installations.auto-download=false
     - name: Cleanup Docker
       if: ${{ always() }}
       working-directory: docker/postgres-server
@@ -185,12 +194,9 @@ jobs:
         docker compose down -v --rmi local
 
   gss-encryption:
-    name: 'GSS Test - JDK ${{ matrix.jdk }} on ${{ matrix.os }}'
-    runs-on: ${{ matrix.os }}
-    needs: matrix_prep
-    strategy:
-      fail-fast: false
-      matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
+    # The driver is built on JDK 17, so this job no longer varies by the test JDK matrix.
+    name: 'GSS Test - JDK 17 on ubuntu-latest'
+    runs-on: ubuntu-latest
     env:
       ACTIONS_STEP_DEBUG: true
       ACTIONS_RUNNER_DEBUG: true
@@ -199,18 +205,18 @@ jobs:
     - name: 'Get test node ARCH'
       run: echo "::set-output name=arch_name::$(uname -i)"
       id: get_arch_name
-    - name: 'Set up JDK 8'
+    - name: 'Set up JDK 17'
       if: ${{ steps.get_arch_name.outputs.arch_name != 'aarch64' }}
       uses: actions/setup-java@v3
       with:
         distribution: zulu
-        java-version: 8
-    - name: 'Setup JDK 8 on ARM64'
+        java-version: 17
+    - name: 'Setup JDK 17 on ARM64'
       if: ${{ steps.get_arch_name.outputs.arch_name == 'aarch64' }}
       uses: AdoptOpenJDK/install-jdk@v1
       with:
         impl: hotspot # or openj9
-        version: '8'
+        version: '17'
         architecture: aarch64
     - name: 'Install software'
       if: ${{ steps.get_arch_name.outputs.arch_name != 'aarch64' }}
@@ -224,8 +230,8 @@ jobs:
     - uses: burrunan/gradle-cache-action@v1
       name: Build pgjdbc
       with:
-        read-only: ${{ matrix.os == 'self-hosted' }}
-        job-id: gss-jdk8
+        read-only: false
+        job-id: gss-jdk17
         arguments: publishToMavenLocal -Ppgjdbc.version=1.0.0-dev-master -PskipJavadoc
     - name: Run tests
       run: |
diff --git a/build.gradle.kts b/build.gradle.kts
index dd89657916..7d8462a3c8 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -14,6 +14,8 @@ import com.github.vlsi.gradle.publishing.dsl.simplifyXml
 import com.github.vlsi.gradle.publishing.dsl.versionFromResolution
 import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis
 import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApisExtension
+import org.gradle.jvm.toolchain.JavaLanguageVersion
+import org.gradle.jvm.toolchain.JavaToolchainService
 import org.postgresql.buildtools.JavaCommentPreprocessorTask
 
 buildscript {
@@ -66,6 +68,10 @@ val skipJavadoc by props()
 val skipForbiddenApis by props()
 val enableMavenLocal by props()
 val enableGradleMetadata by props()
+// Java version to compile via toolchain; 0 = the JVM running Gradle
+val jdkBuildVersion = props.int("jdkBuildVersion", 17)
+// Java version to run tests via toolchain; 0 = reuse build JVM
+val jdkTestVersion = props.int("jdkTestVersion", 0)
 // For instance -PincludeTestTags=!org.postgresql.test.SlowTests
 //           or -PincludeTestTags=!org.postgresql.test.Replication
 val includeTestTags by props("")
@@ -354,7 +360,13 @@ allprojects {
                 }
                 // javadoc: error - The code being documented uses modules but the packages
                 // defined in https://docs.oracle.com/javase/9/docs/api/ are in the unnamed module
-                source = "1.8"
+                if (JavaVersion.current() >= JavaVersion.VERSION_1_9) {
+                    // Document against the Java 8 API. --release also avoids deprecation-for-removal
+                    // warnings (e.g. AccessController) that newer JDKs emit and -Xwerror turns fatal.
+                    addStringOption("-release", "8")
+                } else {
+                    source = "1.8"
+                }
                 docEncoding = "UTF-8"
                 charSet = "UTF-8"
                 encoding = "UTF-8"
@@ -363,7 +375,12 @@ allprojects {
                 header = "<b>PostgreSQL JDBC</b>"
                 bottom =
                     "Copyright &copy; 1997-$lastEditYear PostgreSQL Global Development Group. All Rights Reserved."
-                if (JavaVersion.current() >= JavaVersion.VERSION_1_9) {
+                // There are too many missing javadocs, so failing the build on missing comments is not an option
+                addBooleanOption("Xdoclint:all,-missing", true)
+                if (JavaVersion.current() >= JavaVersion.VERSION_17) {
+                    // Java 17+ javadoc warns on the redirecting javase/9 element-list, so skip the external links
+                    addBooleanOption("html5", true)
+                } else if (JavaVersion.current() >= JavaVersion.VERSION_1_9) {
                     addBooleanOption("html5", true)
                     links("https://docs.oracle.com/javase/9/docs/api/";)
                 } else {
@@ -375,15 +392,16 @@ allprojects {
     }
 
     plugins.withType<JavaPlugin> {
-        configure<JavaPluginConvention> {
-            sourceCompatibility = JavaVersion.VERSION_1_8
-            targetCompatibility = JavaVersion.VERSION_1_8
-        }
         configure<JavaPluginExtension> {
             withSourcesJar()
             if (!skipJavadoc) {
                 withJavadocJar()
             }
+            if (jdkBuildVersion != 0) {
+                toolchain {
+                    languageVersion.set(JavaLanguageVersion.of(jdkBuildVersion))
+                }
+            }
         }
 
         val sourceSets: SourceSetContainer by project
@@ -535,8 +553,23 @@ allprojects {
 
             configureEach<JavaCompile> {
                 options.encoding = "UTF-8"
+                // Target Java 8 bytecode without referencing Java 9+ API.
+                // --release is only understood by javac 9+, so skip it on JDK 8.
+                options.release.set(
+                    provider {
+                        8.takeIf { javaCompiler.get().metadata.languageVersion.asInt() > 9 }
+                    }
+                )
             }
             configureEach<Test> {
+                // Run tests on a specific Java version, independent of the build JVM.
+                if (jdkTestVersion != 0) {
+                    javaLauncher.set(
+                        project.the<JavaToolchainService>().launcherFor {
+                            languageVersion.set(JavaLanguageVersion.of(jdkTestVersion))
+                        }
+                    )
+                }
                 useJUnitPlatform {
                     if (includeTestTags.isNotBlank()) {
                         includeTags.add(includeTestTags)
@@ -569,7 +602,10 @@ allprojects {
                 passProperty("user.country", "tr")
                 val props = System.getProperties()
                 for (e in props.propertyNames() as `java.util`.Enumeration<String>) {
-                    if (e.startsWith("pgjdbc.") || e.startsWith("java")) {
+                    // Forward only pgjdbc.* here. The build JVM's java.* properties
+                    // (java.home, java.version, ...) must not leak into a test JVM
+                    // running on a different Java version selected via jdkTestVersion.
+                    if (e.startsWith("pgjdbc.")) {
                         passProperty(e)
                     }
                 }
diff --git a/gradle.properties b/gradle.properties
index 73e33b2025..84fc5b3e0b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -16,6 +16,12 @@ kotlin.parallel.tasks.in.project=true
 # Release version can be generated by using -Prelease or -Prc=<int> arguments
 pgjdbc.version=42.3.11
 
+# Java version used to compile the driver via a Gradle toolchain (still targets Java 8 bytecode).
+# Set to 0 to compile with the JVM that runs Gradle.
+jdkBuildVersion=17
+# Java version used to run tests via a Gradle toolchain. 0 reuses the build JVM. e.g. -PjdkTestVersion=8
+jdkTestVersion=0
+
 # The options below configures the use of local clone (e.g. testing development versions)
 # You can pass un-comment it, or pass option -PlocalReleasePlugins, or -PlocalReleasePlugins=<path>
 # localReleasePlugins=../vlsi-release-plugins
@@ -26,7 +32,7 @@ pgjdbc.version=42.3.11
 # publishGradleMetadata=true
 
 # Plugins
-biz.aQute.bnd.builder.version=4.3.1
+biz.aQute.bnd.builder.version=6.3.1
 com.github.autostyle.version=3.1
 com.github.burrunan.s3-build-cache.version=1.1
 com.github.johnrengelman.shadow.version=5.1.0
diff --git a/pgjdbc/reduced-pom.xml b/pgjdbc/reduced-pom.xml
index 084393e116..1107ad3e19 100644
--- a/pgjdbc/reduced-pom.xml
+++ b/pgjdbc/reduced-pom.xml
@@ -37,6 +37,8 @@
         <maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
         <maven-jar-plugin.version>2.6</maven-jar-plugin.version>
         <maven-javadoc-plugin.version>3.0.1</maven-javadoc-plugin.version>
+        <!-- Overridden by the add-opens-jdk16 profile so System Stubs can mock env vars on JDK 16+ -->
+        <surefire.argLine>-Xmx1536m</surefire.argLine>
     </properties>
 
     <dependencies>
@@ -103,7 +105,7 @@
                 <artifactId>maven-surefire-plugin</artifactId>
                 <version>${maven-surefire-plugin.version}</version>
                 <configuration>
-                    <argLine>-Xmx1536m</argLine>
+                    <argLine>${surefire.argLine}</argLine>
                     <systemPropertyVariables>
                         <build.properties.relative.path>.</build.properties.relative.path>
                     </systemPropertyVariables>
@@ -214,5 +216,19 @@
                 </plugins>
             </build>
         </profile>
+        <!--
+          System Stubs mocks environment variables via reflection. JDK 16+ rejects that
+          unless java.base is opened; these options are invalid on Java 8, so they live in a
+          JDK 16+ profile rather than the default argLine.
+          -->
+        <profile>
+            <id>add-opens-jdk16</id>
+            <activation>
+                <jdk>[16,)</jdk>
+            </activation>
+            <properties>
+                <surefire.argLine>-Xmx1536m --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED</surefire.argLine>
+            </properties>
+        </profile>
     </profiles>
 </project>
diff --git a/test-gss/build.gradle b/test-gss/build.gradle
index 4c67cefafd..06590a84da 100644
--- a/test-gss/build.gradle
+++ b/test-gss/build.gradle
@@ -13,9 +13,9 @@ repositories {
 }
 
 dependencies {
-    implementation('org.codehaus.groovy:groovy-all:2.5.12')
+    implementation('org.codehaus.groovy:groovy-all:3.0.11')
     implementation(group: 'org.postgresql', name: 'postgresql', version: '1.0.0-dev-master-SNAPSHOT')
-    testCompile group: 'junit', name: 'junit', version: '4.12'
+    testImplementation(group: 'junit', name: 'junit', version: '4.12')
 }
 application {
     mainClassName = 'TestPostgres'
diff --git a/test-gss/gradle/wrapper/gradle-wrapper.properties b/test-gss/gradle/wrapper/gradle-wrapper.properties
index bff6aebb59..0d01abe8db 100644
--- a/test-gss/gradle/wrapper/gradle-wrapper.properties
+++ b/test-gss/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Fri Jun 05 15:24:44 EDT 2020
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1-all.zip
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.6-bin.zip
 zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists


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 #4151: build: 42.3 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