Skip to content

[improve][build] Require Java 21 for servers while preserving Java 17 client compatibility - #26769

Merged
lhotari merged 6 commits into
apache:masterfrom
lhotari:lh-improve-java21-server
Sep 29, 2026
Merged

lhotari merged 6 commits into
apache:masterfrom
lhotari:lh-improve-java21-server

Conversation

@lhotari

@lhotari lhotari commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Motivation

Pulsar 5 server components should default to Java 21, preparing for features such as virtual threads, while client libraries remain usable on Java 17, as discussed on the dev mailing list. Users must also be able to compile Functions and IO implementations against the public interfaces with Java 17, even though Pulsar's Functions runtime requires Java 21.

Modifications

  • Add pulsarJavaVersion=21 and pulsarClientJavaVersion=17 Gradle properties controlling release targets, JVM metadata, and client compatibility verification. Consumer tests select the configured client JDK through Gradle toolchains.
  • Default server startup to Java 21 with a PULSAR_MIN_JAVA_VERSION environment override. A custom -PpulsarJavaVersion=17 build can use PULSAR_MIN_JAVA_VERSION=17 while source/dependency compatibility permits it; Gradle still requires a supported build JDK. No Java 17 server CI job is added.
  • Pass pulsarJavaVersion into both Alpine and Wolfi Docker builds and persist it as the image environment variable PULSAR_MIN_JAVA_VERSION.
  • Default main sources to Java 21. Keep an explicit Java 17 dependency closure covering both client generations, admin/auth/crypto clients, client tools and their custom-command example, CLI utilities, TLS/HTTP SPIs, shared APIs, and Functions/IO interfaces.
  • Publish matching Gradle JVM attributes and reject incompatible dependencies. Check Java 17 class-file versions in dependencies and final shaded jars, respecting multi-release jar selection.
  • Move the complete org.apache.pulsar.websocket.data package to pulsar-common, and move WebSocketError into that package alongside the DTOs. Update websocket handler imports and remove the now-empty parent package from common. Client tools no longer depends on the websocket server module.
  • Upgrade JLine from 4.3.1 to 4.4.6, retaining its jdk11 classifier for client tools to exclude the optional Java 22 FFM provider; update binary license filenames.
  • Keep the fastutil minimizer's reachability inputs separate from its published artifact.
  • Compile ordinary tests for Java 21 so client tests can use server fixtures. Add a dedicated consumer test compiled with --release 17 and executed with Gradle's Java 17 toolchain launcher, plus CI setup and documentation.

Verifying this change

  • Make sure that the change passes the CI checks.

Passed locally on Gradle 9.8.0:

  • ./gradlew help assemble sanityCheck :tests:pulsar-client-java-compatibility:test generateMetadataFileForMavenPublication -PtestRetryCount=0 --configuration-cache --warning-mode all
  • ./gradlew -p build-logic :conventions:test --tests VerifyJavaCompatibilityTest
  • Three Java 17 consumer tests and four bytecode-checker tests passed. sanityCheck includes Spotless, Checkstyle, and main/test compilation.
  • After moving the error enum into data, sanityCheck, the Java 17 consumer tests, and AbstractWebSocketHandlerTest passed with retries disabled.
  • JLine 4.4.6 passes the Java 17 bytecode check and all 21 focused CLI, shell, and consumer tests on Java 17, with retries disabled.
  • Custom target checks passed locally: assemble and sanityCheck with -PpulsarJavaVersion=17 (broker bytecode/metadata verified as Java 17); consumer tests and bytecode verification with -PpulsarClientJavaVersion=21; launcher minimum-version checks for defaults and overrides. No Java 17 server CI job is added.
  • Verified both Docker task command lines use PULSAR_MIN_JAVA_VERSION=21 by default and 17 with the project override; quickCheck passed. Docker images were not built locally.
  • Inspected generated client, client-tools, minimized/shaded client, Functions API, and broker JVM metadata.
  • After the client-tools correction, assemble sanityCheck checkBinaryLicense and all three Java 17 consumer tests passed. Focused V5 shaded/all client classpath tests passed on Java 17; the complete CI shade-test task graph also resolves on Java 17 (--dry-run).

Full broker and cross-JVM interoperability tests were not run. The bytecode checker does not prove all third-party JDK API or reflective compatibility. Gradle reports deprecations for Configuration.setVisible and publication dependencies on unpublished projects; these are outside this change.

Does this pull request potentially affect one of the following parts:

  • Dependencies (add or upgrade a dependency)
  • The public API
  • The schema
  • The default values of configurations
  • The threading model
  • The binary protocol
  • The REST endpoints
  • The admin CLI options
  • The metrics
  • Anything that affects deployment

Server components and Functions runtime implementations now require Java 21 or later. Client libraries, client CLI tools, and Functions/IO public interfaces retain Java 17 compatibility. JLine is upgraded to 4.4.6 using its Java 11-compatible bundle classifier. JLine 4.4 reduces the default ambiguous-key timeout from 1000 ms to 100 ms; Pulsar does not override it. Its SSH agent-forwarding change does not affect Pulsar's shell usage.

WebSocketError moves from org.apache.pulsar.websocket to org.apache.pulsar.websocket.data; its constants and error codes are unchanged.

… client compatibility

Keep client and Functions/IO API dependency closures on Java 17, verify bytecode and published JVM metadata, and run consumer compatibility tests with a Java 17 Gradle toolchain.

Assisted-by: Codex
Move shared websocket DTOs and their error enum to pulsar-common without changing packages. Keep client tools, CLI utilities and custom-command examples on Java 17, use the compatible JLine bundle and verify the CLI on a Java 17 toolchain.

Assisted-by: Codex
Retain the jdk11 bundle for Java 17 client tools and update distribution license filenames.

Assisted-by: Codex
Add pulsarJavaVersion and pulsarClientJavaVersion release targets and a PULSAR_MIN_JAVA_VERSION launcher override. Keep Java 21/17 defaults, follow configured targets in compatibility checks and toolchains, and remove version numbers from compatibility task and test names.

Assisted-by: Codex
Pass pulsarJavaVersion to Alpine and Wolfi Docker builds and persist it as PULSAR_MIN_JAVA_VERSION in the final images.

Assisted-by: Codex
@lhotari
lhotari merged commit f893620 into apache:master Sep 29, 2026
49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants