[JAVA] add JSpecify @Nullable in builder and singleRequestParameter - #24648
[JAVA] add JSpecify @Nullable in builder and singleRequestParameter#24648jpfinne wants to merge 45 commits into
Conversation
merge master
…ure/jspecify_java_builder # Conflicts: # modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java # samples/client/petstore/java/native-jackson3-jspecify/src/main/java/org/openapitools/client/model/Foo.java # samples/openapi3/server/petstore/springboot-4-jspecify/src/main/java/org/openapitools/api/FooApi.java # samples/openapi3/server/petstore/springboot-4-jspecify/src/main/java/org/openapitools/model/Foo.java
…g @NullableCustom
There was a problem hiding this comment.
2 issues found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="modules/openapi-generator/src/main/resources/Java/nullable_var_annotations.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/Java/nullable_var_annotations.mustache:1">
P2: `useJspecify` request-wrapper fields, constructors, accessors, and record components lose `@Nullable` when `useSingleRequestParameter` is enabled, since this lambda suppresses it without a following `jSpecifyDatatype`. Render those declarations via the nullable datatype/argument partial (or preserve the annotation in direct-use contexts).</violation>
</file>
<file name="samples/client/petstore/java/restclient-springBoot4-jackson3-jspecify-openapiNullable/src/main/java/org/openapitools/client/model/Foo.java">
<violation number="1" location="samples/client/petstore/java/restclient-springBoot4-jackson3-jspecify-openapiNullable/src/main/java/org/openapitools/client/model/Foo.java:29">
P3: The generated import block contains three duplicated imports (java.util.Arrays, org.openapitools.jackson.nullable.JsonNullable, com.fasterxml.jackson.annotation.JsonIgnore). Legal but untidy generated output; this sample adds two more duplicates than the sibling jspecify sample, so the new openapiNullable template path is emitting redundant imports. Remove the duplicates.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
2 issues found across 127 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="samples/client/petstore/java/native-jackson3-jspecify/src/main/java/org/openapitools/client/api/FileApi.java">
<violation number="1" location="samples/client/petstore/java/native-jackson3-jspecify/src/main/java/org/openapitools/client/api/FileApi.java:154">
P2: A response header such as `filename=../outside` escapes the generated download directory and writes response content to an unintended filesystem location. Sanitize to a basename (or normalize and reject paths outside `tempDir`) in the native template, then regenerate samples.</violation>
</file>
<file name="samples/client/petstore/java/native-jackson3-jspecify/src/main/java/org/openapitools/client/api/UploadApi.java">
<violation number="1" location="samples/client/petstore/java/native-jackson3-jspecify/src/main/java/org/openapitools/client/api/UploadApi.java:262">
P1: Calling the documented nullable optional upload parameter with `null` throws before a request is sent because it is unconditionally converted to a binary multipart part. Guard the file part (and apply the same generation change in the native template) so an omitted file produces an empty multipart request.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
|
||
| MultipartEntityBuilder multiPartBuilder = MultipartEntityBuilder.create(); | ||
| boolean hasFiles = false; | ||
| multiPartBuilder.addBinaryBody("file", _file); |
There was a problem hiding this comment.
P1: Calling the documented nullable optional upload parameter with null throws before a request is sent because it is unconditionally converted to a binary multipart part. Guard the file part (and apply the same generation change in the native template) so an omitted file produces an empty multipart request.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/java/native-jackson3-jspecify/src/main/java/org/openapitools/client/api/UploadApi.java, line 262:
<comment>Calling the documented nullable optional upload parameter with `null` throws before a request is sent because it is unconditionally converted to a binary multipart part. Guard the file part (and apply the same generation change in the native template) so an omitted file produces an empty multipart request.</comment>
<file context>
@@ -0,0 +1,306 @@
+
+ MultipartEntityBuilder multiPartBuilder = MultipartEntityBuilder.create();
+ boolean hasFiles = false;
+ multiPartBuilder.addBinaryBody("file", _file);
+ hasFiles = true;
+ HttpEntity entity = multiPartBuilder.build();
</file context>
| File file = null; | ||
| if (filename != null) { | ||
| java.nio.file.Path tempDir = java.nio.file.Files.createTempDirectory("swagger-gen-native"); | ||
| java.nio.file.Path filePath = java.nio.file.Files.createFile(tempDir.resolve(filename)); |
There was a problem hiding this comment.
P2: A response header such as filename=../outside escapes the generated download directory and writes response content to an unintended filesystem location. Sanitize to a basename (or normalize and reject paths outside tempDir) in the native template, then regenerate samples.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/java/native-jackson3-jspecify/src/main/java/org/openapitools/client/api/FileApi.java, line 154:
<comment>A response header such as `filename=../outside` escapes the generated download directory and writes response content to an unintended filesystem location. Sanitize to a basename (or normalize and reject paths outside `tempDir`) in the native template, then regenerate samples.</comment>
<file context>
@@ -0,0 +1,269 @@
+ File file = null;
+ if (filename != null) {
+ java.nio.file.Path tempDir = java.nio.file.Files.createTempDirectory("swagger-gen-native");
+ java.nio.file.Path filePath = java.nio.file.Files.createFile(tempDir.resolve(filename));
+ file = filePath.toFile();
+ tempDir.toFile().deleteOnExit(); // best effort cleanup
</file context>
There was a problem hiding this comment.
1 issue found across 157 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="modules/openapi-generator/src/main/resources/Java/libraries/resttemplate/api.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/Java/libraries/resttemplate/api.mustache:79">
P2: Optional abstracted file parameters remain non-null under `@NullMarked` although generated form handling accepts null; apply nullable/nonnull annotations to the `useAbstractionForFiles` branches too.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
2 issues found across 6 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="modules/openapi-generator/src/main/resources/Java/libraries/restclient/single_request_parameter.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/Java/libraries/restclient/single_request_parameter.mustache:5">
P2: Optional or nullable file parameters in `useJspecify=true,useAbstractionForFiles=true` request wrappers remain unannotated because the file branch bypasses `nullableArgument`. Apply the same nullable/type-use handling to the `Resource` and `Collection<Resource>` branches so builders meet the JSpecify contract for every parameter type.</violation>
</file>
<file name="modules/openapi-generator/src/main/resources/Java/libraries/webclient/single_request_parameter.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/Java/libraries/webclient/single_request_parameter.mustache:6">
P2: Optional file parameters with `useAbstractionForFiles=true` still generate unannotated `Resource` request members, so this JSpecify request-parameter path loses nullable metadata. Route the literal Resource types through equivalent `jSpecifyNullable`/`jSpecifyDatatype` handling (while retaining existing non-JSpecify annotations).</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
All reported issues were addressed across 9 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
All reported issues were addressed across 10 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
All reported issues were addressed across 5 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 34 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="samples/openapi3/server/petstore/springboot-4-jspecify/src/main/java/org/openapitools/api/UploadFilesApi.java">
<violation number="1" location="samples/openapi3/server/petstore/springboot-4-jspecify/src/main/java/org/openapitools/api/UploadFilesApi.java:65">
P2: The optional `file` form parameter (required=false) is not annotated @Nullable, yet the file imports org.jspecify.annotations.Nullable (unused). Elsewhere in the same sample, optional params are marked @Nullable (e.g. FooApi `@RequestParam(value="dtQuery", required=false) java.time.@Nullable Instant dtQuery`), so under jspecify an absent multipart part is being typed as non-null, and the import is dead. The JavaSpring formParams.mustache isFile branch doesn't apply {{>nullableAnnotation}} to the file array param — add it there, then regenerate the samples.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| consumes = { "multipart/form-data" } | ||
| ) | ||
| default ResponseEntity<Void> uploadFilesPost( | ||
| @Parameter(name = "file", description = "") @RequestPart(value = "file", required = false) List<MultipartFile> file |
There was a problem hiding this comment.
P2: The optional file form parameter (required=false) is not annotated @nullable, yet the file imports org.jspecify.annotations.Nullable (unused). Elsewhere in the same sample, optional params are marked @nullable (e.g. FooApi @RequestParam(value="dtQuery", required=false) java.time.@Nullable Instant dtQuery), so under jspecify an absent multipart part is being typed as non-null, and the import is dead. The JavaSpring formParams.mustache isFile branch doesn't apply {{>nullableAnnotation}} to the file array param — add it there, then regenerate the samples.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/server/petstore/springboot-4-jspecify/src/main/java/org/openapitools/api/UploadFilesApi.java, line 65:
<comment>The optional `file` form parameter (required=false) is not annotated @Nullable, yet the file imports org.jspecify.annotations.Nullable (unused). Elsewhere in the same sample, optional params are marked @Nullable (e.g. FooApi `@RequestParam(value="dtQuery", required=false) java.time.@Nullable Instant dtQuery`), so under jspecify an absent multipart part is being typed as non-null, and the import is dead. The JavaSpring formParams.mustache isFile branch doesn't apply {{>nullableAnnotation}} to the file array param — add it there, then regenerate the samples.</comment>
<file context>
@@ -0,0 +1,71 @@
+ consumes = { "multipart/form-data" }
+ )
+ default ResponseEntity<Void> uploadFilesPost(
+ @Parameter(name = "file", description = "") @RequestPart(value = "file", required = false) List<MultipartFile> file
+ ) {
+ return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
</file context>
When useJspecify=true, add the
@Nullableannotation to the java builders.Add
@Nullableannotation to singleRequestParameters for restclient and webclient libraries.Regenerate jspecify samples with more options to improve coverage.
Tags added to jspecify sample -> multiple generate api classes. It covers more cases (like missing
@Nullableimport when all parameters are required.Add sample for restClient+jspecify+openapiNullable
The builders are not modified when useJspecify=false. (it can be done in a # PR)
For simplicity, this PR does NOT cover. (it can be done in a # PR)
@Nullable@NullMarkedPR checklist
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.
Summary by cubic
Adds
org.jspecify.annotations.Nullableto Java builder methods and API request parameters whenuseJspecifyis enabled, including file params and arrays of files withuseAbstractionForFiles. Regenerates jspecify samples with tag-split APIs, adds anuploadFilesexample, and includes a Spring Boot 4restclientsample withopenApiNullablein CI.New Features
Java/nullableArgument_builder.mustache.Java/nullableArgumentForApi.mustacheand use it inrestclient/webclientfor API params and single-request types, supportingorg.springframework.core.io.ResourceandCollection<Resource>when handling file params withuseAbstractionForFiles.generateBuilders, all-args constructors,useSingleRequestParameter,useAbstractionForFiles, anduseTagsacrossnative-jackson3-jspecify,restclient,resttemplate, andwebclient.restclient-springBoot4-jackson3-jspecify-openapiNullablesample (incl.uploadFiles) and include it in the JDK17 workflow.Bug Fixes
@Nullableparsing inAbstractJavaCodegento handle a trailing space.nullable_var_annotations.mustachespacing; fixwebclientsingle-requesttoIndentedString.restclientAPI test/template to use correct file param types withuseAbstractionForFiles; update tests for param annotations, tag-based API splits, array-of-file uploads; fix failing unit tests.Written for commit 8df500c. Summary will update on new commits.