Skip to content

Commit d7dec5c

Browse files
Ignacio-Vidalclaude
andcommitted
fix(microprofile): annotate enum getters and optional file form params
Two gaps found in review, both leaving optional properties unannotated under useJspecify: 1. pojo.mustache wired only the {{^isEnum}} getter branch, so an optional enum-typed property had a @nullable field but a non-null getter — nullness analysis would treat it as never null. The three enum getter branches (scalar, array, map) now route through the same partials. 2. formParams.mustache left the isFile branch untouched, so optional file uploads rendered as bare File / List<File>. Adding the annotation partial alone was not enough: nullable_var_annotations only *stashes* the annotation in jSpecifyNullableLambda, and it is re-emitted by a paired jSpecifyDatatype call. The isFile branch writes a literal type rather than {{>nullableDataType}}, so the stashed annotation was silently dropped; the literal is now wrapped in the lambda. Both are covered by new assertions in testJspecify_microprofile, which fail if either fix is reverted. The third review comment, @nullable on a @PathParam, is not a defect: the jspecify.yaml fixture declares that path parameter `required: false` on purpose, and the pre-existing tests for the other libraries assert the same output. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BQa4EUVfxzqe4qi9PDj5RU
1 parent f861114 commit d7dec5c

5 files changed

Lines changed: 21 additions & 7 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{#isFormParam}}{{^isFile}}{{#required}}{{#useBeanValidation}}@NotNull {{/useBeanValidation}}{{/required}}@FormParam("{{baseName}}") {{#useJspecify}}{{>nullable_var_annotations}}{{/useJspecify}}{{>nullableDataType}} {{paramName}}{{/isFile}}{{#isFile}} {{#required}}{{#useBeanValidation}}@NotNull {{/useBeanValidation}}{{/required}}@FormParam("{{baseName}}") {{^isArray}}File{{/isArray}}{{#isArray}}List<File>{{/isArray}} {{paramName}}Detail{{/isFile}}{{/isFormParam}}
1+
{{#isFormParam}}{{^isFile}}{{#required}}{{#useBeanValidation}}@NotNull {{/useBeanValidation}}{{/required}}@FormParam("{{baseName}}") {{#useJspecify}}{{>nullable_var_annotations}}{{/useJspecify}}{{>nullableDataType}} {{paramName}}{{/isFile}}{{#isFile}} {{#required}}{{#useBeanValidation}}@NotNull {{/useBeanValidation}}{{/required}}@FormParam("{{baseName}}") {{#useJspecify}}{{>nullable_var_annotations}}{{/useJspecify}}{{#lambda.jSpecifyDatatype}}{{^isArray}}File{{/isArray}}{{#isArray}}List<File>{{/isArray}}{{/lambda.jSpecifyDatatype}} {{paramName}}Detail{{/isFile}}{{/isFormParam}}

‎modules/openapi-generator/src/main/resources/Java/libraries/microprofile/pojo.mustache‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,11 @@ public {{>sealed}}class {{classname}} {{#parent}}extends {{{.}}}{{/parent}}{{#ve
105105
return null;
106106
}
107107
return {{name}}.value();
108-
}{{/isMap}}{{/isArray}}{{/isEnum}}{{/withXml}}{{^withXml}}{{#isEnum}}{{^isArray}}{{^isMap}}public {{datatypeWithEnum}} {{getter}}() {
108+
}{{/isMap}}{{/isArray}}{{/isEnum}}{{/withXml}}{{^withXml}}{{#isEnum}}{{^isArray}}{{^isMap}}public {{#useJspecify}}{{>nullable_var_annotations}}{{/useJspecify}}{{>nullableDatatypeWithEnum}} {{getter}}() {
109109
return {{name}};
110-
}{{/isMap}}{{/isArray}}{{/isEnum}}{{/withXml}}{{#isEnum}}{{#isArray}}public {{{datatypeWithEnum}}} {{getter}}() {
110+
}{{/isMap}}{{/isArray}}{{/isEnum}}{{/withXml}}{{#isEnum}}{{#isArray}}public {{#useJspecify}}{{>nullable_var_annotations}}{{/useJspecify}}{{>nullableDatatypeWithEnum}} {{getter}}() {
111111
return {{name}};
112-
}{{/isArray}}{{/isEnum}}{{#isEnum}}{{#isMap}}public {{{datatypeWithEnum}}} {{getter}}() {
112+
}{{/isArray}}{{/isEnum}}{{#isEnum}}{{#isMap}}public {{#useJspecify}}{{>nullable_var_annotations}}{{/useJspecify}}{{>nullableDatatypeWithEnum}} {{getter}}() {
113113
return {{name}};
114114
}{{/isMap}}{{/isEnum}}{{^isEnum}}public {{#useJspecify}}{{>nullable_var_annotations}}{{/useJspecify}}{{>nullableDatatypeWithEnum}} {{getter}}() {
115115
return {{name}};

‎modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4899,6 +4899,20 @@ public void testJspecify_microprofile() throws IOException {
48994899
"@PathParam(\"dtParam\") @Nullable Date dtParam",
49004900
"@QueryParam(\"dtQuery\") @Nullable Date dtQuery");
49014901

4902+
// an optional enum-typed property: its getter must be annotated like any other
4903+
JavaFileAssert.assertThat(files.get("FileContent.java"))
4904+
.fileContains(
4905+
"protected @Nullable VirusScanEnum virusScan;",
4906+
"public @Nullable VirusScanEnum getVirusScan() {");
4907+
4908+
// optional file form parameters. Their type is a literal in the template rather than a
4909+
// {{>nullableDataType}} call, so it must still be routed through the jSpecifyDatatype
4910+
// lambda, or the annotation stashed by nullable_var_annotations is silently dropped.
4911+
JavaFileAssert.assertThat(files.get("UploadApi.java"))
4912+
.fileContains(
4913+
"@FormParam(\"file\") @Nullable File _fileDetail",
4914+
"@FormParam(\"file\") @Nullable List<File> _fileDetail");
4915+
49024916
JavaFileAssert.assertThat(files.get("api/package-info.java"))
49034917
.fileContains("@org.jspecify.annotations.NullMarked");
49044918
JavaFileAssert.assertThat(files.get("model/package-info.java"))

‎samples/client/petstore/java/microprofile-rest-client-3.0-jspecify/src/main/java/org/openapitools/client/api/UploadApi.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ public interface UploadApi {
4545
@POST
4646
@Path("/uploadFiles")
4747
@Consumes({ "multipart/form-data" })
48-
void uploadFilesPost( @FormParam("file") List<File> _fileDetail) throws ApiException, ProcessingException;
48+
void uploadFilesPost( @FormParam("file") @Nullable List<File> _fileDetail) throws ApiException, ProcessingException;
4949

5050
@POST
5151
@Path("/upload")
5252
@Consumes({ "multipart/form-data" })
53-
void uploadPost( @FormParam("file") File _fileDetail) throws ApiException, ProcessingException;
53+
void uploadPost( @FormParam("file") @Nullable File _fileDetail) throws ApiException, ProcessingException;
5454
}

‎samples/client/petstore/java/microprofile-rest-client-3.0-jspecify/src/main/java/org/openapitools/client/model/FileContent.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public String getName() {
122122
**/
123123
@JsonProperty(value = JSON_PROPERTY_VIRUS_SCAN, required = false)
124124
@JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
125-
public VirusScanEnum getVirusScan() {
125+
public @Nullable VirusScanEnum getVirusScan() {
126126
return virusScan;
127127
}
128128

0 commit comments

Comments
 (0)