[java] honor useJspecify in restclient/webclient ApiClient support class

Merged
AU
5mo ago
+12-2

PR: [java] honor useJspecify in restclient/webclient ApiClient support class

PR checklist

  • Read the contribution guidelines.
  • Pull Request title clearly describes the work and is named according to our commit naming conventions.
  • File the PR against the correct branch: master (no breaking changes).
  • Run the shell script ./bin/generate-samples.sh to update all Petstore samples related to your fix. Regenerated the affected samples and committed the changes.
  • If your PR is targeting a particular programming language and you want a community member to review it, find them in the list of technical committee members and @ mention them.

cc Java technical committee: @bbdouglas @sdltj @martin-mfg @welshm @Bridgevine — and @jpfinne (author of useJspecify, #23256).

Description

Fixes #24054.

useJspecify=true converts model/API nullness to org.jspecify.annotations.Nullable, but the
restclient and webclient ApiClient support classes still hardcoded
import {{javaxPackage}}.annotation.Nullable;. That left every generated client mixing JSpecify
everywhere except the ApiClient, which kept jakarta.annotation.Nullable (or javax.*),
breaking "JSpecify-only" enforcement (ArchUnit / NullAway).

@Nullable is referenced as a simple name in both templates (createDefaultMapper(@Nullable DateFormat dateFormat)), so only the import line needs to be made conditional. No usage sites
change; behavior with useJspecify=false is unchanged. The other java-library ApiClient
templates do not import Nullable and are unaffected.

Diff

--- a/modules/openapi-generator/src/main/resources/Java/libraries/restclient/ApiClient.mustache
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/restclient/ApiClient.mustache
@@ -79,7 +79,12 @@
 import java.util.TimeZone;
 import java.util.function.Supplier;
 
-import {{javaxPackage}}.annotation.Nullable;
+{{#useJspecify}}
+import org.jspecify.annotations.Nullable;
+{{/useJspecify}}
+{{^useJspecify}}
+import {{javaxPackage}}.annotation.Nullable;
+{{/useJspecify}}
 
 {{#jsr310}}
--- a/modules/openapi-generator/src/main/resources/Java/libraries/webclient/ApiClient.mustache
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/webclient/ApiClient.mustache
@@ -82,7 +82,12 @@
 import java.util.Map.Entry;
 import java.util.TimeZone;
 
-import {{javaxPackage}}.annotation.Nullable;
+{{#useJspecify}}
+import org.jspecify.annotations.Nullable;
+{{/useJspecify}}
+{{^useJspecify}}
+import {{javaxPackage}}.annotation.Nullable;
+{{/useJspecify}}
 
 {{#jsr310}}

How to verify

./bin/generate-samples.sh bin/configs/java-restclient-*.yaml
./bin/generate-samples.sh bin/configs/java-webclient-*.yaml

Generate with useJspecify=true and confirm ApiClient.java imports
org.jspecify.annotations.Nullable; generate with useJspecify=false and confirm it still
imports {{javaxPackage}}.annotation.Nullable (jakarta or javax per useJakartaEe).

Notes

  • Run ./bin/generate-samples.sh + ./bin/utils/export_docs_generators.sh before pushing so the
    committed Petstore samples for any useJspecify restclient/webclient config are regenerated;
    CI fails if samples are stale.
  • Commit message (their Conventional-ish convention): [java] honor useJspecify in restclient/webclient ApiClient.

Summary by cubic

Honor useJspecify in Java restclient and webclient ApiClient templates by making the @Nullable import conditional: org.jspecify.annotations.Nullable when useJspecify=true, otherwise {{javaxPackage}}.annotation.Nullable.
This removes mixed nullness annotations in generated clients and keeps behavior unchanged when JSpecify is off.