Skip to content

THRIFT-5919: Set JDK 17 as minimum Java version#6

Open
greggdonovan wants to merge 29 commits intomasterfrom
jdk_17_minimum
Open

THRIFT-5919: Set JDK 17 as minimum Java version#6
greggdonovan wants to merge 29 commits intomasterfrom
jdk_17_minimum

Conversation

@greggdonovan
Copy link
Owner

@greggdonovan greggdonovan commented Feb 6, 2026

Summary

THRIFT-5919: Set JDK 17 as minimum Java version

Set JDK 17 as the minimum Java version for the Thrift Java library - Java 8 reached public EOL in March 2022 and Java 11 in September 2023. JDK 17 is the current baseline LTS version.

What changed

Code generation (t_java_generator.cc)

  • Remove android_legacy, java5 generator flags
  • Remove option_type=thrift support (throws error directing users to option_type=jdk8)
  • option_type=jdk8 remains opt-in (default behavior unchanged: raw types, null for unset optional fields)
  • Jakarta annotations (jakarta.annotation.Generated) are now the default; opt out with javax_annotations
  • Generated code uses switch expressions and pattern matching instanceof
  • Remove @Nullable annotations from generated code

Java library

  • Delete org.apache.thrift.Option class (replaced by java.util.Optional)
  • Delete lib/java/android/ (Android AAR build targeting SDK 23 / build tools 23.0.1)
  • Modernize TBaseHelper, TUnion, protocol classes with pattern matching instanceof and switch expressions
  • Fix PartialThriftComparer null comparison bug: when one object was null and the other non-null, returned UNKNOWN instead of NOT_EQUAL
  • Add unwrapOptional() to PartialThriftComparer for Optional-wrapped field values

Build infrastructure

  • Remove ant dependency; Gradle is the sole Java build system
  • Remove manual Gradle download from CI; use gradle/actions/setup-gradle@v5
  • Switch shadow plugin from abandoned com.github.johnrengelman.shadow 8.1.1 to com.gradleup.shadow 9.3.1
  • Remove obsolete shadowRuntimeElements workaround (incompatible with new Shadow plugin)
  • Upgrade Spotless 8.1.0 → 8.2.1, google-java-format pinned to 1.28.0 (latest that works with JDK17)
  • Upgrade SpotBugs tool 4.5.3 → 4.9.8, FindSecBugs 1.12.0 → 1.14.0 (plugin stays at 5.2.5 due to upstream enum property issue)
  • Upgrade PMD 6.0.0 → 7.9.0 with category-based rulesets
  • Fix Gradle 10 deprecation warnings (assignment operators, tasks.register, @Inject ExecOperations)
  • Refactor generateTestThrift.gradle: replace closure-based thriftCompile with ThriftGeneratorTask abstract class
  • Remove jakarta_annotations from generator args in test thrift compilation (now default)

Dependencies

  • SLF4J 1.7.36 → 2.0.17 (OSGi range narrowed to [2.0,3))
  • HttpClient 5.2.1 → 5.4.1, HttpCore 5.2 → 5.3.1
  • Servlet 5.0.0 → 6.1.0, Tomcat 10.1.4 → 11.0.2
  • JUnit 5.9.1 → 5.11.4, Mockito 5.3.0 → 5.15.2
  • javax.annotation 2.1.1 → 3.0.0 (jakarta.annotation-api)
  • Replace slf4j-log4j12 with slf4j-simple for test runtime (log4j 1.x is EOL)
  • commons-lang3 → 3.18.0

Kotlin

  • Set JVM 17 target for all Kotlin modules (was JVM 1.8)
  • Switch from kotlinx-coroutines-jdk8 to kotlinx-coroutines-core (jdk8 APIs merged into core since 1.7.0)
  • Upgrade cross-test deps: SLF4J 2.0.17, Logback 1.5.28, HttpCore 4.4.16, HttpClient 4.5.14, kotlinx-coroutines-core 1.10.2

Other

  • Remove ant from configure.ac Java detection
  • Update contrib/thrift-maven-plugin/pom.xml compiler source/target from 1.8 to 17
  • Dependabot: add labels and dependency groups for Java/Kotlin packages
  • Remove lib/java/android/ from Makefile.am
  • Flatten lib/java/CMakeLists.txt (remove if(ANDROID) branch)

Breaking Changes

See CHANGES.md for full details. Summary:

Change Migration
Minimum Java version is JDK 17 Upgrade JDK
org.apache.thrift.Option deleted Use java.util.Optional
option_type=thrift removed Use option_type=jdk8 instead
Jakarta annotations are default Use javax_annotations flag to opt out
android_legacy, java5 flags removed Remove from --gen java: args
SLF4J 2.0+ required Upgrade SLF4J dependency

POM diff vs published 0.22.0

All differences are intentional (version bump, dependency upgrades, new maven.compiler.release property):

--- libthrift-0.22.0.pom (Maven Central)
+++ libthrift-0.23.0-SNAPSHOT (this branch)
@@ version
-  <version>0.22.0</version>
+  <version>0.23.0-SNAPSHOT</version>
@@ new properties block
+  <properties>
+    <maven.compiler.release>17</maven.compiler.release>
+  </properties>
@@ dependency version upgrades
   slf4j-api:          1.7.36 → 2.0.17
   httpclient5:        5.2.1  → 5.4.1
   httpcore5:          5.2    → 5.3.1
   jakarta.servlet-api: 5.0.0 → 6.1.0
   jakarta.annotation-api: 2.1.1 → 3.0.0
   commons-lang3:      3.12.0 → 3.18.0

No structural changes — same <groupId>, <artifactId>, <name>, <description>, <url>, <licenses>, <developers>, <scm>, and <dependencies> layout.

Related JIRA Issues

  • THRIFT-5644 - Upgrade to Java 17 in build env and upgrade minimal Java version to 11 (partially reverted by THRIFT-5702)
  • THRIFT-5702 - Support Java 8 (reverted the minimum version bump)

Test plan

  • CI green: all 3 workflows (Build, Build with CMake, MSVC Build) pass
  • Verify generated code compiles with JDK 17
  • Verify cross-test client/server work with Kotlin modules
  • Verify --gen java:javax_annotations opt-out works
  • Verify --gen java:option_type=jdk8 works (opt-in Optional wrapping)
  • Verify --gen java:option_type=thrift fails with clear error message
  • Verify generated POM matches published 0.22.0 structure (only version + dep upgrades differ)

claude and others added 20 commits February 6, 2026 11:48
- Update lib/java/build.gradle to require JDK 17 minimum
- Update lib/java/gradle/sourceConfiguration.gradle to target Java 17
- Update contrib/thrift-maven-plugin/pom.xml to use Java 17
- Update .github/workflows/build.yml cross-test to use JDK 17
- Update lib/kotlin/*.gradle.kts files to target JVM 17
- Add Jdk17Test.java to verify JDK 17 runtime features
- Apply JDK 17 features:
  - Pattern matching for instanceof in TBaseHelper, TUnion
  - Switch expressions in TBinaryProtocol, TCompactProtocol, TJSONProtocol

https://claude.ai/code/session_01EQ812qEBnt14Gq7gKCriiS
Remove obsolete options:
- java5: Java 1.5 compatibility no longer needed
- android_legacy: Android 2.3 compatibility no longer needed
- option_type: Always use java.util.Optional for optional fields

Change defaults:
- jakarta_annotations is now the default (use javax_annotations to opt out)
- Optional fields are always wrapped in java.util.Optional

Remove custom Option class:
- Delete org.apache.thrift.Option (replaced by java.util.Optional)
- Delete TestOptionType.java test
- Delete JavaOptionTypeJdk8Test.thrift test resource

Update build configuration:
- Simplify Gradle test generation tasks
- Remove option_type and jakarta_annotations from generator invocations

Generated code now requires JDK 17 or later.

https://claude.ai/code/session_01EQ812qEBnt14Gq7gKCriiS
Maven artifact improvements:
- Add maven.compiler.release=17 property to published POM so consumers
  know JDK 17 is required
- Remove obsolete Java 9 compatibility check in javadoc configuration

Remove legacy Android library:
- Remove lib/java/android directory (unmaintained since 2015)
- Android Gradle Plugin 1.5.0 and SDK 23 are incompatible with JDK 17
- Not tested in CI and not published to Maven
- Update CMakeLists.txt to remove Android build support
- Update Makefile.am to remove android from EXTRA_DIST
- Clean up outdated Android comment in THttpClientResponseHandler

https://claude.ai/code/session_01EQ812qEBnt14Gq7gKCriiS
The Thrift-specific @nullable annotation is no longer needed since:
- The code generator now uses @org.jspecify.annotations.Nullable
- The library code uses JSpecify annotations
- JSpecify is a standard dependency

https://claude.ai/code/session_01EQ812qEBnt14Gq7gKCriiS
- Add labels for easier PR categorization (dependencies, java, kotlin, github-actions)
- Group related dependencies to reduce PR noise:
  - static-analysis: ErrorProne, NullAway, SpotBugs
  - testing: JUnit, Mockito
  - apache-http: HttpClient, HttpCore

This ensures automated updates for ErrorProne, NullAway, JSpecify, and other
dependencies added as part of the JDK 17 modernization.

https://claude.ai/code/session_01EQ812qEBnt14Gq7gKCriiS
Dependency upgrades:
- SpotBugs: plugin 5.2.5→6.4.8, tool 4.5.3→4.9.8
- FindSecBugs: 1.12.0→1.14.0
- PMD: 6.0.0→7.9.0 (with updated ruleset for PMD 7)
- SLF4J: 1.7.36→2.0.17 (switch to slf4j-simple for tests)
- JUnit: 5.9.1→5.11.4
- Mockito: 5.3.0→5.15.2
- HttpClient: 5.2.1→5.4.1
- HttpCore: 5.2→5.3.1
- Jakarta Servlet: 5.0.0→6.1.0
- Jakarta Annotation: 2.1.1→3.0.0
- Tomcat Embed: 10.1.4→11.0.2

Dependabot enhancements:
- Add jakarta group for Jakarta EE APIs
- Add logging group for SLF4J dependencies
- Add PMD and FindSecBugs to static-analysis group

https://claude.ai/code/session_01EQ812qEBnt14Gq7gKCriiS
- Add JSpecify, Spotless to static-analysis group
- Rename apache-http to apache, add Commons Lang and Tomcat Embed

https://claude.ai/code/session_01EQ812qEBnt14Gq7gKCriiS
Reorder imports to follow Google Java Format conventions:
- java.* imports first
- org.apache.* imports next
- org.jspecify.* imports last

https://claude.ai/code/session_01EQ812qEBnt14Gq7gKCriiS
…s-test-server

- Fix potential NPE in TUnion.toString() by using String.valueOf(v) instead
  of v.toString() for @nullable getFieldValue() result
- Use local variables after null checks so NullAway can track narrowing
  in toString(), StandardScheme.write(), and TupleScheme.write()
- Add null check in getFieldValue(F) to satisfy NullAway since it delegates
  to @nullable getFieldValue()
- Make deepCopyObject() accept/return @nullable to match @nullable value_
- Add JVM 17 target to Kotlin cross-test-server build to match
  cross-test-client and root module

https://claude.ai/code/session_01EQ812qEBnt14Gq7gKCriiS
Update code formatting tooling to latest versions and apply
reformatting to ensure CI passes spotlessCheck.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use assignment syntax (=) for property assignments
- Add comment noting SpotBugs enum string coercion needs fixing for Gradle 10

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add test Thrift IDL and Java test for Optional-based fields
* Fix sourceConfiguration.gradle to use file() for test resources dir
* Fix generateTestThrift.gradle to always generate Optional-style code

Co-Authored-By: Claude <noreply@anthropic.com>
- Java codegen: add ErrorProne/NullAway suppressions, use switch expressions for enums,
  remove JSpecify @nullable from positions incompatible with TYPE_USE annotations
- Kotlin: modernize deps (kotlin-stdlib, kotlinx-coroutines-core)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Strip out ErrorProne/NullAway/JSpecify artifacts that came through from
cherry-picks:
- Remove jspecify @nullable imports from TApplicationException and TUnion
- Restore original @SuppressWarnings in code generator (remove ErrorProne-specific entries)
- Remove JSpecify comments from code generator
- Clean ErrorProne/NullAway/JSpecify patterns from dependabot config
- Restore org.apache.thrift.annotation.Nullable class (still used by code generator)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SpotBugs Gradle plugin 6.x requires typed enum values for effort and
reportLevel properties, which don't resolve in applied script files.
Keep plugin at 5.2.5 while still upgrading SpotBugs tool to 4.9.8
and FindSecBugs to 1.14.0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The code generator now always wraps optional fields in java.util.Optional,
so all test files need .orElseThrow() to unwrap values:

- TestDeepCopy: unwrap Optional getters for deep copy assertions
- TestEnumContainers: unwrap Optional getters for enum container operations
- TestPartialThriftDeserializer: unwrap Optional collection getters
- ThriftStructProcessorTest: fix field lookup for new Optional struct
- Remove TestOptionalsWithJdk8.java (replaced by TestOptionalsWithJavaOptional)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use Provider(String, String, String) instead of deprecated
Provider(String, double, String) to avoid -Werror failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The code generator now wraps optional fields in java.util.Optional,
causing ClassCastException when PartialThriftComparer tries to cast
field values directly to List/Set/Map. Add unwrapOptional() to extract
values before comparison and fix checkNullEquality to return NOT_EQUAL
when one operand is null.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Kotlin code generator emits `scope.future { }` blocks that require
`kotlinx.coroutines.future.future` from the jdk8 coroutines artifact.
Reverting the modernization from coroutines-jdk8 to coroutines-core
which removed this required API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@greggdonovan greggdonovan changed the base branch from master to php-8.2-modernization February 6, 2026 19:11
@greggdonovan greggdonovan changed the base branch from php-8.2-modernization to master February 6, 2026 19:11
greggdonovan and others added 2 commits February 6, 2026 15:40
- Remove ant dependency from configure.ac and CI (Java build is pure Gradle)
- Replace manual Gradle download with gradle/actions/setup-gradle@v5
  (uses wrapper version 9.3.1 automatically, handles caching)
- Switch shadow plugin from abandoned com.github.johnrengelman.shadow 8.1.1
  to com.gradleup.shadow 9.3.1 (new maintainer, requires Gradle 9+/JDK 17+)
- Replace kotlinx-coroutines-jdk8 with kotlinx-coroutines-core
  (jdk8 module was merged into core in kotlinx.coroutines 1.7.0)
- Bump kotlinx-coroutines version from 1.6.1 to 1.10.2 in gradle.properties

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove Jdk17Test.java (served its purpose verifying JDK 17 compiler)
- Upgrade SLF4J 1.7.35 -> 2.0.17 (active maintained line)
- Upgrade Logback 1.3.0-alpha14 -> 1.5.28 (stable release, SLF4J 2.x compatible)
- Upgrade HttpCore 4.4.15 -> 4.4.16 (final 4.x patch)
- Upgrade HttpClient 4.5.13 -> 4.5.14 (final 4.x patch)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…timization, SLF4J 2.0

- Add breaking changes and bugfix notes to CHANGES.md
- Remove orphaned TUnion null check (was added for NullAway, which was removed)
- Replace var with TFieldIdEnum in TUnion write methods
- Optimize PartialThriftComparer: move unwrapOptional from hot dispatch path
  to struct field retrieval only (avoids instanceof check on every nested
  element in lists, maps, and sets)
- Narrow SLF4J OSGi Import-Package range from [1.4,3) to [2.0,3) since
  SLF4J 1.x is EOL

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@greggdonovan greggdonovan changed the title Jdk 17 minimum Set JDK 17 as minimum Java version Feb 6, 2026
greggdonovan and others added 2 commits February 6, 2026 19:31
Restore the option_type=jdk8 generator flag as opt-in (default false) so
optional fields return raw types by default, preserving backward
compatibility. Only jdk8 is supported; option_type=thrift now throws an
error directing users to option_type=jdk8.

- Restore use_option_type_ member and option_type flag parsing
- Restore bool optional guard in generate_java_bean_boilerplate
- Revert .orElseThrow() calls in 4 test files (compiled without option_type)
- Move JavaOptionTypeOptionalTest.thrift to separate compilation task
  with java:option_type=jdk8
- Update CHANGES.md breaking changes accordingly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The workaround for GradleUp/shadow#651 is not compatible with
com.gradleup.shadow 9.3.1, which does not create a
shadowRuntimeElements configuration. This caused publishToMavenLocal
to fail with "Variant for configuration 'shadowRuntimeElements' does
not exist in component 'java'".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Repository owner deleted a comment from greptile-apps bot Feb 7, 2026
@greggdonovan
Copy link
Owner Author

@greptile

greptile-apps[bot]

This comment was marked as outdated.

@greptile-apps
Copy link

greptile-apps bot commented Feb 7, 2026

Additional Comments (1)

lib/java/gradle/publishing.gradle
Shadow artifact may publish

This PR removed the withVariantsFromConfiguration(configurations.shadowRuntimeElements) { skip() } guard. With the Shadow plugin still applied, publishing can start including additional variants/artifacts (e.g., a shadow runtime variant) depending on plugin behavior, which would change what gets pushed to Maven compared to prior releases. If the intent is to keep publishing only the normal java component, please re-add an explicit exclusion for Shadow variants under the new plugin (or otherwise verify the published publication contents don’t change).

- Use https://thrift.apache.org/ to match the published 0.22.0 POM
- Replace fragile withXml appendNode with Gradle's native properties
  DSL to avoid risk of duplicate <properties> blocks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@greggdonovan greggdonovan changed the title Set JDK 17 as minimum Java version THRIFT-5919: Set JDK 17 as minimum Java version Feb 7, 2026
- Remove @SuppressWarnings({"UnusedVariable"}) from
  TestPartialThriftDeserializer — was added for the since-reverted
  .orElseThrow() changes and is no longer needed
- Revert TUnion toString/write cleanups (local variable extraction,
  String.valueOf) that were unrelated to JDK 17 modernization, keeping
  only the pattern matching instanceof changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The thrift compiler does not generate package-info.java files, so the
filter excluding them from secondary gen directories was dead code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Repository owner deleted a comment from greptile-apps bot Feb 7, 2026
Restore 6 @nullable annotation sites in t_java_generator.cc that were
accidentally dropped during the JDK 17 modernization. The annotation
class was preserved but the code generator stopped emitting @nullable
on field declarations, getters, setters, setFieldValue/getFieldValue,
and iterator accessors for nullable types.

Move our Java changelog entries from 0.22.0 into a new 0.23.0 section,
citing THRIFT-5919 per project conventions. THRIFT-5858 stays in 0.22.0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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