Skip to content

[Java][microprofile] - Add JSpecify support - #24884

Open
Ignacio-Vidal wants to merge 1 commit into
OpenAPITools:masterfrom
Ignacio-Vidal:java-microprofile-jspecify
Open

[Java][microprofile] - Add JSpecify support#24884
Ignacio-Vidal wants to merge 1 commit into
OpenAPITools:masterfrom
Ignacio-Vidal:java-microprofile-jspecify

Conversation

@Ignacio-Vidal

@Ignacio-Vidal Ignacio-Vidal commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Adds useJspecify support to the java generator's microprofile library.

Fixes #24883

Changes

  • JavaClientCodegen: add MICROPROFILE to JSPECIFY_SUPPORTED_LIBRARIES.
  • pojo.mustache: @Nullable on the field, getter, setter and fluent setter, with types routed through nullableDatatypeWithEnum so the annotation lands type-use style on qualified types (java.math.@Nullable BigDecimal).
  • queryParams / pathParams / headerParams / bodyParams / cookieParams / formParams: @Nullable on operation parameters, alongside the existing JAX-RS annotations.
  • pom.mustache + pom_3.0.mustache: declare org.jspecify:jspecify:1.0.0.
  • Regenerated docs/generators/java.md and docs/generators/java-microprofile.md.

Why the template changes are guarded

Every template change is wrapped in {{#useJspecify}}, so output with useJspecify=false is unchanged. The guard is required:

  • The shared nullable_var_annotations.mustache emits @{{javaxPackage}}.annotation.Nullable/Nonnull when the flag is off, and those symbols do not resolve in a generated microprofile project
  • jakarta.annotation.Nullable/Nonnull were only added in jakarta.annotation-api 2.1.1, while the microprofile poms pin 1.3.5 (rest client 2.0) and 2.0.0 (rest client 3.0). Both predate the annotations.

Raising microprofile's jakarta.annotation.version would be an alternative, but it would add these annotations to every existing microprofile user's output, which is out of scope here.

Testing

  • New testJspecify_microprofile in JavaClientCodegenTest, asserting type-use placement on qualified types, JAX-RS parameter annotations coexisting with @Nullable, that required properties are not annotated, and the pom dependency.
  • New testJspecify_microprofile_sealedOneOfInterfaces, covering useJspecify together with useSealedOneOfInterfaces (previously uncovered)
  • <java.version>17</java.version> and the jspecify dependency. It uses a dedicated fixture because oneof_interface_petstore.yaml has only required properties, so it would produce no @Nullable and assert nothing.
  • New sample samples/client/petstore/java/microprofile-rest-client-3.0-jspecify, registered in samples-java-client-jdk11.yaml.

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

@Ignacio-Vidal
Ignacio-Vidal marked this pull request as ready for review September 6, 2026 12:15

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 50 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

@Ignacio-Vidal
Ignacio-Vidal marked this pull request as draft September 6, 2026 12:53
@Ignacio-Vidal
Ignacio-Vidal marked this pull request as ready for review September 6, 2026 13:09

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 50 files

Requires human review: Auto-approval blocked by 3 unresolved issues from a previous review of this commit.

Re-trigger cubic

@Ignacio-Vidal

Copy link
Copy Markdown
Contributor Author

Thanks — two of the three were real bugs, fixed in d7dec5c.

1. Optional file form parameters (P2) — valid, fixed. The isFile branch of formParams.mustache left optional uploads as bare File / List<File>. Adding the annotation partial alone was not sufficient: nullable_var_annotations only stashes the annotation in jSpecifyNullableLambda, and it is re-emitted by a paired jSpecifyDatatype call. Because the isFile branch writes a literal type instead of {{>nullableDataType}}, the stashed annotation was silently dropped. The literal is now wrapped in the lambda, and both parameters render as expected:

void uploadPost(@FormParam("file") @Nullable File _fileDetail)
void uploadFilesPost(@FormParam("file") @Nullable List<File> _fileDetail)

2. Enum getter (P2) — valid, fixed. Correct diagnosis: only the {{^isEnum}} getter branch was wired, so an optional enum-typed property had a @Nullable field but a non-null getter. All three enum branches (scalar, array, map) now route through the same partials, so getVirusScan() is annotated. Fixed in the template and regenerated, not just in the sample.

3. @Nullable on @PathParam (P3) — not a defect. The jspecify.yaml fixture declares that parameter required: false deliberately, with an upstream comment on the line ("the Spring generator accepts nullable path param!"). The annotation therefore reflects the spec rather than contradicting it. nullable_var_annotations is gated on {{#required}}/{{^required}}, so it is not applied unconditionally — a required path parameter gets no annotation. The pre-existing testJspecify assertions for the other libraries assert this same output for dtParam, so changing it would diverge from restclient/native/webclient/resttemplate.

Both fixes are covered by new assertions in testJspecify_microprofile that fail if either is reverted. 290 tests green; regenerating all java-microprofile* samples changes only this feature's own sample.

@Ignacio-Vidal
Ignacio-Vidal marked this pull request as draft September 6, 2026 13:25
@Ignacio-Vidal
Ignacio-Vidal marked this pull request as ready for review September 6, 2026 17:16
@Ignacio-Vidal Ignacio-Vidal changed the title [Java][microprofile] add JSpecify support [Java][microprofile] - Add JSpecify support Sep 6, 2026
@Ignacio-Vidal

Ignacio-Vidal commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

@wing328 - could you review it when you have a few minutes please?

@Ignacio-Vidal
Ignacio-Vidal force-pushed the java-microprofile-jspecify branch from d7dec5c to 288e54b Compare September 6, 2026 17:23
@Ignacio-Vidal
Ignacio-Vidal marked this pull request as draft September 6, 2026 17:23

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review completed against the latest diff

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

@Ignacio-Vidal
Ignacio-Vidal marked this pull request as ready for review September 6, 2026 17:46

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 50 files

Re-trigger cubic

@Ignacio-Vidal
Ignacio-Vidal marked this pull request as draft September 6, 2026 17:50
@Ignacio-Vidal
Ignacio-Vidal force-pushed the java-microprofile-jspecify branch 2 times, most recently from b7daf51 to e9936b2 Compare September 6, 2026 18:11
@Ignacio-Vidal
Ignacio-Vidal marked this pull request as ready for review September 6, 2026 18:14

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 50 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

useJspecify was rejected for the microprofile library, even though the
option is listed in its generated documentation. This enables it, reusing
the machinery already shared in AbstractJavaCodegen:

- add MICROPROFILE to JSPECIFY_SUPPORTED_LIBRARIES
- emit @nullable on optional properties and operation parameters via the
  shared nullable_var_annotations partial, and route types through
  nullableDataType/nullableDatatypeWithEnum so annotations on qualified
  types are placed type-use style (java.math.@nullable BigDecimal)
- declare the org.jspecify:jspecify dependency in both microprofile poms

The @NullMarked package-info.java files already came from the base
applyJspecify(), which resolves against the shared Java template dir.

Every template change is guarded by {{#useJspecify}}, so output with the
flag off is byte-identical to before (verified by diffing generated
output against master). The guard is required rather than cosmetic:
jakarta.annotation.Nullable/Nonnull only exist from jakarta.annotation-api
2.1.1, while the microprofile poms pin 1.3.5 and 2.0.0, so emitting the
default annotations produces code that does not compile.

Two cases need the annotation partial paired with the datatype lambda,
which stashes and re-emits it: the enum getter branches, and the literal
File / List<File> type in the isFile form-parameter branch. Without that
pairing the annotation is silently dropped.

Adds a sample (microprofile-rest-client-3.0-jspecify, registered in the
jdk11 samples workflow) and tests covering type-use placement, JAX-RS
parameter annotations coexisting with @nullable, sealed oneOf interfaces,
enum getters, optional file parameters, and that required properties are
not annotated.
@Ignacio-Vidal
Ignacio-Vidal force-pushed the java-microprofile-jspecify branch from e9936b2 to 5118374 Compare September 6, 2026 18:22
@Ignacio-Vidal
Ignacio-Vidal marked this pull request as draft September 6, 2026 18:22
@Ignacio-Vidal
Ignacio-Vidal marked this pull request as ready for review September 6, 2026 18:26

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 50 files

Re-trigger cubic

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.

[REQ][JAVA][microprofile] Support useJspecify for the microprofile library

1 participant