Message-ID: From: "vlsi (@vlsi)" To: "pgjdbc/pgjdbc" Date: Thu, 04 Jun 2026 07:35:20 +0000 Subject: [pgjdbc/pgjdbc] PR #4151: build: 42.3 compile with a Java 17 toolchain, run tests on multiple JDKs List-Id: X-GitHub-Additions: 108 X-GitHub-Author-Id: 213894 X-GitHub-Author-Login: vlsi X-GitHub-Base: release/42.3.x X-GitHub-Changed-Files: 7 X-GitHub-Commits: 1 X-GitHub-Deletions: 42 X-GitHub-Head-Branch: claude/toolchain-42.3 X-GitHub-Head-SHA: 0e58568113474245607e307099d8795bda066262 X-GitHub-Issue: 4151 X-GitHub-Merge-SHA: 2f6559f5d051845d444821c4d3ec74f27f35e2b9 X-GitHub-Merged-By: vlsi X-GitHub-Repo: pgjdbc/pgjdbc X-GitHub-State: merged X-GitHub-Type: pull_request X-GitHub-Url: https://github.com/pgjdbc/pgjdbc/pull/4151 Content-Type: text/plain; charset=utf-8 ## 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 = "PostgreSQL JDBC" bottom = "Copyright © 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 { - configure { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } configure { withSourcesJar() if (!skipJavadoc) { withJavadocJar() } + if (jdkBuildVersion != 0) { + toolchain { + languageVersion.set(JavaLanguageVersion.of(jdkBuildVersion)) + } + } } val sourceSets: SourceSetContainer by project @@ -535,8 +553,23 @@ allprojects { configureEach { 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 { + // Run tests on a specific Java version, independent of the build JVM. + if (jdkTestVersion != 0) { + javaLauncher.set( + project.the().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) { - 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= 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= # 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 @@ 2.22.2 2.6 3.0.1 + + -Xmx1536m @@ -103,7 +105,7 @@ maven-surefire-plugin ${maven-surefire-plugin.version} - -Xmx1536m + ${surefire.argLine} . @@ -214,5 +216,19 @@ + + + add-opens-jdk16 + + [16,) + + + -Xmx1536m --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED + + 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