This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar.git
The following commit(s) were added to refs/heads/master by this push:
new 1a5dff6a3e7 [improve][build] Support building and testing with Java 25
(#25453)
1a5dff6a3e7 is described below
commit 1a5dff6a3e790548030c42f28880653e2e3498d1
Author: Lari Hotari <[email protected]>
AuthorDate: Wed Apr 1 18:18:36 2026 +0300
[improve][build] Support building and testing with Java 25 (#25453)
---
.github/actions/setup-gradle/action.yml | 11 ++++++
.github/actions/tune-runner-vm/action.yml | 4 +--
.github/workflows/codeql.yaml | 4 +--
.github/workflows/pulsar-ci-flaky.yaml | 8 ++---
.github/workflows/pulsar-ci.yaml | 33 +++++++----------
README.md | 5 ++-
.../main/kotlin/pulsar.java-conventions.gradle.kts | 9 +++++
distribution/server/src/assemble/LICENSE.bin.txt | 2 +-
distribution/shell/src/assemble/LICENSE.bin.txt | 2 +-
gradle/libs.versions.toml | 3 +-
microbench/README.md | 41 ++++++++++++++++------
pulsar-build/run_integration_group_gradle.sh | 3 +-
settings.gradle.kts | 17 +++++++++
.../integration/offload/TestFileSystemOffload.java | 11 ++++++
.../integration/offload/TestOffloadDeletionFS.java | 11 ++++++
tiered-storage/file-system/build.gradle.kts | 9 +++++
16 files changed, 128 insertions(+), 45 deletions(-)
diff --git a/.github/actions/setup-gradle/action.yml
b/.github/actions/setup-gradle/action.yml
index c7f2518a232..ceac3840231 100644
--- a/.github/actions/setup-gradle/action.yml
+++ b/.github/actions/setup-gradle/action.yml
@@ -39,13 +39,24 @@ inputs:
runs:
using: composite
steps:
+ - name: Set Develocity Project ID and configure custom settings
+ if: ${{ inputs.develocity-access-key != '' && inputs.build-scan-publish
== 'true' }}
+ shell: bash
+ run: |
+ mkdir -p ~/.gradle
+ touch ~/.gradle/gradle.properties
+ grep -q 'systemProp.develocity.projectId=' ~/.gradle/gradle.properties
|| echo systemProp.develocity.projectId=pulsar >> ~/.gradle/gradle.properties
+ grep -q 'systemProp.scan.uploadInBackground='
~/.gradle/gradle.properties || echo systemProp.scan.uploadInBackground=false >>
~/.gradle/gradle.properties
+
- name: Setup Gradle with Develocity
if: ${{ inputs.develocity-access-key != '' && inputs.build-scan-publish
== 'true' }}
uses:
gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f
with:
develocity-injection-enabled: true
develocity-url: https://develocity.apache.org
+ # expected format is develocity.apache.org:<access-key>
develocity-access-key: ${{ inputs.develocity-access-key }}
+ build-scan-publish: ${{ inputs.build-scan-publish }}
cache-read-only: ${{ inputs.cache-read-only }}
add-job-summary: ${{ inputs.add-job-summary }}
diff --git a/.github/actions/tune-runner-vm/action.yml
b/.github/actions/tune-runner-vm/action.yml
index d071f534dbb..00eb084990e 100644
--- a/.github/actions/tune-runner-vm/action.yml
+++ b/.github/actions/tune-runner-vm/action.yml
@@ -65,8 +65,8 @@ runs:
# stop unnecessary services
sudo systemctl stop php8.3-fpm.service ModemManager.service \
- multipathd.service udisks2.service walinuxagent.service || true
-
+ multipathd.socket multipathd.service udisks2.service
walinuxagent.service || true
+
echo '::endgroup::'
# show memory
diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml
index 7f6c5480f2d..bf029bde911 100644
--- a/.github/workflows/codeql.yaml
+++ b/.github/workflows/codeql.yaml
@@ -35,8 +35,8 @@ env:
jobs:
analyze:
- # only run scheduled analysis in apache/pulsar repository
- if: ${{ (github.event_name == 'schedule' && github.repository ==
'apache/pulsar') || github.event_name != 'schedule' }}
+ # only run on push and schedule in apache/pulsar repo
+ if: ${{ github.repository == 'apache/pulsar' || github.event_name ==
'workflow_dispatch' }}
name: Analyze
runs-on: 'ubuntu-latest'
timeout-minutes: 360
diff --git a/.github/workflows/pulsar-ci-flaky.yaml
b/.github/workflows/pulsar-ci-flaky.yaml
index 041970735a9..a7ce06573e1 100644
--- a/.github/workflows/pulsar-ci-flaky.yaml
+++ b/.github/workflows/pulsar-ci-flaky.yaml
@@ -27,7 +27,7 @@ on:
schedule:
# scheduled job with JDK 21
- cron: '0 12 * * *'
- # scheduled job with JDK 17
+ # scheduled job with JDK 25
# if cron expression is changed, make sure to update the expression in
jdk_major_version step in preconditions job
- cron: '0 6 * * *'
workflow_dispatch:
@@ -42,9 +42,7 @@ on:
required: true
type: choice
options:
- - '17'
- '21'
- - '24'
- '25'
default: '21'
trace_test_resource_cleanup:
@@ -106,9 +104,9 @@ jobs:
- name: Select JDK major version
id: jdk_major_version
run: |
- # use JDK 17 for the scheduled build with cron expression '0 6 * * *'
+ # use JDK 25 for the scheduled build with cron expression '0 6 * * *'
if [[ "${{ github.event_name == 'schedule' && github.event.schedule
== '0 6 * * *' && 'true' || 'false' }}" == "true" ]]; then
- echo "jdk_major_version=17" >> $GITHUB_OUTPUT
+ echo "jdk_major_version=25" >> $GITHUB_OUTPUT
exit 0
fi
# use JDK 21 for build unless overridden with workflow_dispatch input
diff --git a/.github/workflows/pulsar-ci.yaml b/.github/workflows/pulsar-ci.yaml
index 35d7ab41318..4cfdfdf6e5c 100644
--- a/.github/workflows/pulsar-ci.yaml
+++ b/.github/workflows/pulsar-ci.yaml
@@ -27,7 +27,7 @@ on:
schedule:
# scheduled job with JDK 21
- cron: '0 12 * * *'
- # scheduled job with JDK 17
+ # scheduled job with JDK 25
# if cron expression is changed, make sure to update the expression in
jdk_major_version step in preconditions job
- cron: '0 6 * * *'
workflow_dispatch:
@@ -37,9 +37,7 @@ on:
required: true
type: choice
options:
- - '17'
- '21'
- - '24'
- '25'
default: '21'
trace_test_resource_cleanup:
@@ -99,9 +97,9 @@ jobs:
- name: Select JDK major version
id: jdk_major_version
run: |
- # use JDK 17 for the scheduled build with cron expression '0 6 * * *'
+ # use JDK 25 for the scheduled build with cron expression '0 6 * * *'
if [[ "${{ github.event_name == 'schedule' && github.event.schedule
== '0 6 * * *' && 'true' || 'false' }}" == "true" ]]; then
- echo "jdk_major_version=17" >> $GITHUB_OUTPUT
+ echo "jdk_major_version=25" >> $GITHUB_OUTPUT
exit 0
fi
# use JDK 21 for build unless overridden with workflow_dispatch input
@@ -443,7 +441,7 @@ jobs:
run: tar xf gradle-build-outputs.tar
- name: Build java-test-image Docker image
- run: ./gradlew :tests:java-test-image:dockerBuild
+ run: ./gradlew :tests:java-test-image:dockerBuild${{
env.CI_JDK_MAJOR_VERSION != '21' && format(' -PdockerJavaVersion={0}',
env.CI_JDK_MAJOR_VERSION) || '' }}
- name: Save docker image to file
run: |
@@ -500,10 +498,10 @@ jobs:
upload_name: SHADE_RUN_21
runtime_jdk: 21
- - name: Shade on Java 24
+ - name: Shade on Java 25
group: SHADE_RUN
- upload_name: SHADE_RUN_24
- runtime_jdk: 24
+ upload_name: SHADE_RUN_25
+ runtime_jdk: 25
- name: Standalone
group: STANDALONE
@@ -534,11 +532,13 @@ jobs:
with:
limit-access-to-actor: true
- - name: Set up JDK ${{ env.CI_JDK_MAJOR_VERSION }}
+ - name: Set up JDK ${{ env.CI_JDK_MAJOR_VERSION }}${{ matrix.runtime_jdk
&& matrix.runtime_jdk != env.CI_JDK_MAJOR_VERSION && format(' and {0}',
matrix.runtime_jdk) || '' }}
uses: actions/setup-java@v5
with:
distribution: ${{ env.JDK_DISTRIBUTION }}
- java-version: ${{ env.CI_JDK_MAJOR_VERSION }}
+ java-version: |
+ ${{ matrix.runtime_jdk != env.CI_JDK_MAJOR_VERSION &&
matrix.runtime_jdk || '' }}
+ ${{ env.CI_JDK_MAJOR_VERSION }}
- name: Setup Gradle
uses: ./.github/actions/setup-gradle
@@ -567,16 +567,9 @@ jobs:
run: |
${{ matrix.setup }}
- - name: Set up runtime JDK ${{ matrix.runtime_jdk }}
- uses: actions/setup-java@v5
- if: ${{ matrix.runtime_jdk }}
- with:
- distribution: ${{ env.JDK_DISTRIBUTION }}
- java-version: ${{ matrix.runtime_jdk }}
-
- name: Run integration test group '${{ matrix.group }}'
run: |
- ./pulsar-build/run_integration_group_gradle.sh ${{ matrix.group }}
+ ./pulsar-build/run_integration_group_gradle.sh ${{ matrix.group
}}${{ matrix.runtime_jdk && matrix.runtime_jdk != env.CI_JDK_MAJOR_VERSION &&
format(' -PtestJavaVersion={0}', matrix.runtime_jdk) || '' }}
- name: print JVM thread dumps when cancelled
if: cancelled()
@@ -666,7 +659,7 @@ jobs:
run: tar xf gradle-build-outputs.tar
- name: Build pulsar-test-latest-version Docker image
- run: ./gradlew :tests:latest-version-image:dockerBuild
+ run: ./gradlew :tests:latest-version-image:dockerBuild${{
env.CI_JDK_MAJOR_VERSION != '21' && format(' -PdockerJavaVersion={0}',
env.CI_JDK_MAJOR_VERSION) || '' }}
- name: Check binary licenses
run: |
diff --git a/README.md b/README.md
index f4600d5e186..bca501cfd99 100644
--- a/README.md
+++ b/README.md
@@ -168,7 +168,8 @@ Docker image Java runtime: 17
| Pulsar Version | JDK Version
|
|------------------|:--------------------------------------------------------------------------------:|
- | master and 4.0+ | [JDK
21](https://adoptium.net/en-GB/temurin/releases?version=21&os=any&arch=any) |
+ | master | [JDK
21](https://adoptium.net/en-GB/temurin/releases?version=21&os=any&arch=any) or
[JDK
25](https://adoptium.net/en-GB/temurin/releases?version=25&os=any&arch=any) |
+ | 4.0+ | [JDK
21](https://adoptium.net/en-GB/temurin/releases?version=21&os=any&arch=any) |
| 2.11 + | [JDK
17](https://adoptium.net/en-GB/temurin/releases?version=17&os=any&arch=any) |
| 2.8 / 2.9 / 2.10 | [JDK
11](https://adoptium.net/en-GB/temurin/releases?version=11&os=any&arch=any) |
| 2.7 - | [JDK
8](https://adoptium.net/en-GB/temurin/releases?version=8&os=any&arch=any) |
@@ -181,6 +182,8 @@ There is also a guide for [setting up the tooling for
building Pulsar](https://p
>
> This project includes a [Gradle
> Wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) so
> no separate Gradle installation is needed.
> Use `./gradlew` on Linux/macOS and `gradlew.bat` on Windows.
+>
+> For a better developer experience, install [Gradle command-line
completion](https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_completion)
([gradle-completion
installation](https://github.com/gradle/gradle-completion?tab=readme-ov-file#gradle-completion))
for bash and zsh shells.
### Build
diff --git
a/build-logic/conventions/src/main/kotlin/pulsar.java-conventions.gradle.kts
b/build-logic/conventions/src/main/kotlin/pulsar.java-conventions.gradle.kts
index 666648175b5..daf10c90098 100644
--- a/build-logic/conventions/src/main/kotlin/pulsar.java-conventions.gradle.kts
+++ b/build-logic/conventions/src/main/kotlin/pulsar.java-conventions.gradle.kts
@@ -116,7 +116,16 @@ dependencies {
"testImplementation"(catalog.findLibrary("slf4j-api").get())
}
+// Allow overriding the JDK used for running tests via -PtestJavaVersion=17
+val testJavaVersion = providers.gradleProperty("testJavaVersion").map {
it.toInt() }
+val javaToolchains = extensions.getByType<JavaToolchainService>()
+
tasks.withType<Test>().configureEach {
+ testJavaVersion.orNull?.let { version ->
+ javaLauncher.set(javaToolchains.launcherFor {
+ languageVersion.set(JavaLanguageVersion.of(version))
+ })
+ }
useTestNG {
listeners.addAll(listOf(
"org.apache.pulsar.tests.PulsarTestListener",
diff --git a/distribution/server/src/assemble/LICENSE.bin.txt
b/distribution/server/src/assemble/LICENSE.bin.txt
index 5177464d39e..a5f26bc9ffe 100644
--- a/distribution/server/src/assemble/LICENSE.bin.txt
+++ b/distribution/server/src/assemble/LICENSE.bin.txt
@@ -289,7 +289,7 @@ The Apache Software License, Version 2.0
- org.apache.commons-commons-collections4-4.5.0.jar
- org.apache.commons-commons-compress-1.28.0.jar
- org.apache.commons-commons-configuration2-2.12.0.jar
- - org.apache.commons-commons-lang3-3.19.0.jar
+ - org.apache.commons-commons-lang3-3.20.0.jar
- org.apache.commons-commons-text-1.14.0.jar
* Netty
- io.netty-netty-buffer-4.1.132.Final.jar
diff --git a/distribution/shell/src/assemble/LICENSE.bin.txt
b/distribution/shell/src/assemble/LICENSE.bin.txt
index 70cc3a61fa3..7d42b4b9467 100644
--- a/distribution/shell/src/assemble/LICENSE.bin.txt
+++ b/distribution/shell/src/assemble/LICENSE.bin.txt
@@ -341,7 +341,7 @@ The Apache Software License, Version 2.0
* Apache Commons
- commons-codec-1.20.0.jar
- commons-io-2.21.0.jar
- - commons-lang3-3.19.0.jar
+ - commons-lang3-3.20.0.jar
- commons-text-1.14.0.jar
- commons-compress-1.28.0.jar
* Netty
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 4ed2e758314..d75fa3a73b7 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -19,7 +19,6 @@
[versions]
# Core
pulsar = "4.3.0-SNAPSHOT"
-java = "17"
# Docker
docker-jdk = "21"
pulsar-client-python = "3.10.0"
@@ -45,7 +44,7 @@ opentelemetry-instrumentation = "2.21.0"
opentelemetry-instrumentation-alpha = "2.21.0-alpha"
opentelemetry-semconv = "1.37.0"
# Apache Commons
-commons-lang3 = "3.19.0"
+commons-lang3 = "3.20.0"
commons-io = "2.21.0"
commons-codec = "1.20.0"
commons-compress = "1.28.0"
diff --git a/microbench/README.md b/microbench/README.md
index 9138c3de2c1..6b1b8af593d 100644
--- a/microbench/README.md
+++ b/microbench/README.md
@@ -32,7 +32,7 @@ The benchmarks are written using
[JMH](http://openjdk.java.net/projects/code-too
./gradlew :microbench:shadowJar
# run the benchmarks using the standalone shaded jar in any environment
-java -jar microbench/build/libs/microbenchmarks.jar
+java -jar microbench/build/libs/microbench-*-benchmarks.jar
```
### Running specific benchmarks
@@ -40,25 +40,25 @@ java -jar microbench/build/libs/microbenchmarks.jar
Display help:
```shell
-java -jar microbench/build/libs/microbenchmarks.jar -h
+java -jar microbench/build/libs/microbench-*-benchmarks.jar -h
```
Listing all benchmarks:
```shell
-java -jar microbench/build/libs/microbenchmarks.jar -l
+java -jar microbench/build/libs/microbench-*-benchmarks.jar -l
```
Running specific benchmarks:
```shell
-java -jar microbench/build/libs/microbenchmarks.jar ".*BenchmarkName.*"
+java -jar microbench/build/libs/microbench-*-benchmarks.jar ".*BenchmarkName.*"
```
Running specific benchmarks with machine-readable output and saving the output
to a file:
```shell
-java -jar microbench/build/libs/microbenchmarks.jar -rf json -rff
jmh-result-$(date +%s).json ".*BenchmarkName.*" | tee jmh-result-$(date +%s).txt
+java -jar microbench/build/libs/microbench-*-benchmarks.jar -rf json -rff
jmh-result-$(date +%s).json ".*BenchmarkName.*" | tee jmh-result-$(date +%s).txt
```
The `jmh-result-*.json` file can be used to visualize the results using [JMH
Visualizer](https://jmh.morethan.io/).
@@ -66,16 +66,37 @@ The `jmh-result-*.json` file can be used to visualize the
results using [JMH Vis
Checking what benchmarks match the pattern:
```shell
-java -jar microbench/build/libs/microbenchmarks.jar ".*BenchmarkName.*" -lp
+java -jar microbench/build/libs/microbench-*-benchmarks.jar
".*BenchmarkName.*" -lp
```
Profiling benchmarks with
[async-profiler](https://github.com/async-profiler/async-profiler):
+Set `LIBASYNCPROFILER_PATH` to the path of the async-profiler library.
+
+Corretto JDK ships with async-profiler (asprof binary and libasyncProfiler
dynamic library)
+
+```shell
+LIBASYNCPROFILER_PATH=$(ls $JAVA_HOME/lib/libasyncProfiler.*)
+```
+
+Alternatively, download async-profiler from
https://github.com/async-profiler/async-profiler/releases and install to
~/async-profiler directory.
+
+Mac OS example:
+
```shell
-# example of profiling with async-profiler
-# download async-profiler from
https://github.com/async-profiler/async-profiler/releases
LIBASYNCPROFILER_PATH=$HOME/async-profiler/lib/libasyncProfiler.dylib
-java -jar microbench/build/libs/microbenchmarks.jar -prof
async:libPath=$LIBASYNCPROFILER_PATH\;output=flamegraph\;dir=profile-results
".*BenchmarkName.*"
+```
+
+Linux example:
+
+```shell
+# macos example
+LIBASYNCPROFILER_PATH=$HOME/async-profiler/lib/libasyncProfiler.dylib
+```
+
+Then run the benchmarks with the `-prof` argument:
+```shell
+java -jar microbench/build/libs/microbench-*-benchmarks.jar -prof
async:libPath=$LIBASYNCPROFILER_PATH\;output=flamegraph\;dir=profile-results
".*BenchmarkName.*"
```
When profiling on Mac OS, you might need to add `\;event=itimer` to the
`-prof` argument since it's the only [async profiler CPU sampling engine that
supports Mac
OS](https://github.com/async-profiler/async-profiler/blob/master/docs/CpuSamplingEngines.md#summary).
The default value for `event` is `cpu`.
@@ -83,5 +104,5 @@ When profiling on Mac OS, you might need to add
`\;event=itimer` to the `-prof`
It's possible to add options to the async-profiler that aren't supported by
the JMH async-profiler plugin. This can be done by adding `rawCommand` option
to the `-prof` argument. This example shows how to add `all` (new in Async
Profiler 4.1), `jfrsync` (record JFR events such as garbage collection) and
`cstack=vmx` options.
```shell
-java -jar microbench/build/libs/microbenchmarks.jar -prof
async:libPath=$LIBASYNCPROFILER_PATH\;output=jfr\;dir=profile-results\;rawCommand=all,jfrsync,cstack=vmx
".*BenchmarkName.*"
+java -jar microbench/build/libs/microbench-*-benchmarks.jar -prof
async:libPath=$LIBASYNCPROFILER_PATH\;output=jfr\;dir=profile-results\;rawCommand=all,jfrsync,cstack=vmx
".*BenchmarkName.*"
```
\ No newline at end of file
diff --git a/pulsar-build/run_integration_group_gradle.sh
b/pulsar-build/run_integration_group_gradle.sh
index 388aa16dcfe..8ab24b08936 100755
--- a/pulsar-build/run_integration_group_gradle.sh
+++ b/pulsar-build/run_integration_group_gradle.sh
@@ -140,7 +140,8 @@ test_group_shade_run() {
./gradlew --no-configuration-cache \
:tests:pulsar-client-shade-test:test \
:tests:pulsar-client-admin-shade-test:test \
- :tests:pulsar-client-all-shade-test:test
+ :tests:pulsar-client-all-shade-test:test \
+ "$@"
echo "::endgroup::"
"$SCRIPT_DIR/pulsar_ci_tool.sh" move_test_reports
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 45ba3587e7f..45847e44465 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -36,10 +36,27 @@ dependencyResolutionManagement {
}
}
}
+
+ // override docker-jdk version with -PdockerJavaVersion=21|25
+ val overrideDockerJavaVersion =
settings.providers.gradleProperty("dockerJavaVersion")
+ if (overrideDockerJavaVersion.isPresent) {
+ versionCatalogs {
+ create("libs") {
+ version("docker-jdk", overrideDockerJavaVersion.get())
+ }
+ }
+ }
}
rootProject.name = "pulsar"
+// Running this build requires Java 21 or 25. Version check can be skipped
with -PskipJavaVersionCheck parameter.
+val javaVersion = providers.provider { JavaVersion.current() }
+val statisfiedJavaVersion = javaVersion.map { it == JavaVersion.VERSION_21 ||
it == JavaVersion.VERSION_25 }
+require(providers.gradleProperty("skipJavaVersionCheck").isPresent ||
statisfiedJavaVersion.get()) {
+ "This build requires Java 21 or 25, but is running on Java
${javaVersion.get()}. Pass -PskipJavaVersionCheck to skip this check."
+}
+
//
──────────────────────────────────────────────────────────────────────────────
// Core modules
//
──────────────────────────────────────────────────────────────────────────────
diff --git
a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/offload/TestFileSystemOffload.java
b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/offload/TestFileSystemOffload.java
index d658d80ddf4..9f5653ef779 100644
---
a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/offload/TestFileSystemOffload.java
+++
b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/offload/TestFileSystemOffload.java
@@ -22,11 +22,22 @@ import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.JavaVersion;
+import org.apache.commons.lang3.SystemUtils;
+import org.testng.SkipException;
+import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@Slf4j
public class TestFileSystemOffload extends TestBaseOffload {
+ @BeforeClass
+ public void checkJavaVersion() {
+ if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_25)) {
+ throw new SkipException("Filesystem Offload is incompatible with
Java 25");
+ }
+ }
+
@Test(dataProvider = "ServiceAndAdminUrls")
public void testPublishOffloadAndConsumeViaCLI(Supplier<String>
serviceUrl, Supplier<String> adminUrl)
throws Exception {
diff --git
a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/offload/TestOffloadDeletionFS.java
b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/offload/TestOffloadDeletionFS.java
index 70c2527e8ad..873b73d8c2b 100644
---
a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/offload/TestOffloadDeletionFS.java
+++
b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/offload/TestOffloadDeletionFS.java
@@ -25,14 +25,25 @@ import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.JavaVersion;
+import org.apache.commons.lang3.SystemUtils;
import org.apache.pulsar.common.naming.TopicName;
import org.apache.pulsar.tests.integration.docker.ContainerExecException;
import org.apache.pulsar.tests.integration.docker.ContainerExecResult;
+import org.testng.SkipException;
+import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@Slf4j
public class TestOffloadDeletionFS extends TestBaseOffload {
+ @BeforeClass
+ public void checkJavaVersion() {
+ if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_25)) {
+ throw new SkipException("Filesystem Offload is incompatible with
Java 25");
+ }
+ }
+
@Override
protected int getEntrySize() {
return 512;
diff --git a/tiered-storage/file-system/build.gradle.kts
b/tiered-storage/file-system/build.gradle.kts
index ab9366d1573..83558e1ae4d 100644
--- a/tiered-storage/file-system/build.gradle.kts
+++ b/tiered-storage/file-system/build.gradle.kts
@@ -81,3 +81,12 @@ dependencies {
testImplementation("org.eclipse.jetty:jetty-servlet:9.4.58.v20250814")
testImplementation("org.eclipse.jetty:jetty-util:9.4.58.v20250814")
}
+
+// Hadoop 3.4.x is incompatible with Java 25
+val testJavaVersion = providers.gradleProperty("testJavaVersion")
+val effectiveTestJava = testJavaVersion
+ .orElse(provider { JavaVersion.current().majorVersion })
+ .map { it.toInt() }
+tasks.withType<Test>().configureEach {
+ enabled = effectiveTestJava.get() < 25
+}
\ No newline at end of file