Repository navigation
[Spring-http-interface] JSpecify: fix api argument with default value #24740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
59c67f2
784da69
9ee6075
91ce7ba
0808d0e
46d9c9c
7b6cf90
b50a337
ae1bff7
5229d8d
cdc74eb
9c059d1
df30bd2
246b21d
8e39563
deec130
da9270c
7e4ce22
4f55095
a614eb2
12cb648
e8f0a38
8199a48
4757c1f
a410286
16f02cc
61eb6bf
455affe
9d1fc7d
5d162d1
fb38a0c
c2003fa
0923570
4e821b1
3f7b9f4
5d103b7
c62a962
6432c0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isBodyParam}}{{>paramDoc}}{{#useBeanValidation}} {{>beanValidationBodyParams}}@Valid{{/useBeanValidation}} @RequestBody{{^required}}(required = false){{/required}} {{^reactive}}{{>nullableAnnotation}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}} {{paramName}}{{/isBodyParam}} | ||
| {{#isBodyParam}}{{>paramDoc}}{{#useBeanValidation}} {{>beanValidationBodyParams}}@Valid{{/useBeanValidation}} @RequestBody{{^required}}(required = false){{/required}} {{^reactive}}{{>nullableAnnotation_apiArgument}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}} {{paramName}}{{/isBodyParam}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isCookieParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}} @CookieValue(name = "{{baseName}}"{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{>dateTimeParam}} {{>nullableAnnotation}}{{>optionalDataType}} {{paramName}}{{/isCookieParam}} | ||
| {{#isCookieParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}} @CookieValue(name = "{{baseName}}"{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{>dateTimeParam}} {{>nullableAnnotation_apiArgument}}{{>optionalDataType}} {{paramName}}{{/isCookieParam}} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isHeaderParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}} @RequestHeader(value = "{{baseName}}", required = {{#required}}true{{/required}}{{^required}}false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{>dateTimeParam}} {{>nullableAnnotation}}{{>optionalDataType}} {{paramName}}{{/isHeaderParam}} | ||
| {{#isHeaderParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}} @RequestHeader(value = "{{baseName}}", required = {{#required}}true{{/required}}{{^required}}false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{>dateTimeParam}} {{>nullableAnnotation_apiArgument}}{{>optionalDataType}} {{paramName}}{{/isHeaderParam}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {{#lambda.jSpecifyNullable}}{{#defaultValue}}@Nullable {{/defaultValue}}{{^defaultValue}}{{^required}}{{^useOptional}}@Nullable {{/useOptional}}{{/required}}{{/defaultValue}}{{/lambda.jSpecifyNullable}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#paramName}}{{>nullableAnnotation_default}}{{/paramName}}{{^paramName}}{{>nullableAnnotation_jspecify}}{{^useJspecify}}{{!backward compatibility}}{{>nullableAnnotation_default}}{{/useJspecify}}{{/paramName}} | ||
| {{#useJspecify}}{{>nullableAnnotation_jspecify}}{{/useJspecify}}{{^useJspecify}}{{!backward compatibility}}{{>nullableAnnotation_default}}{{/useJspecify}} | ||
|
jpfinne marked this conversation as resolved.
Resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {{#lambda.jSpecifyNullable}}{{^required}}{{^defaultValue}}{{^useOptional}}{{#openApiNullable}}{{^isNullable}}@Nullable {{/isNullable}}{{/openApiNullable}}{{^openApiNullable}}@Nullable {{/openApiNullable}}{{/useOptional}}{{/defaultValue}}{{#defaultValue}}{{^openApiNullable}}{{#isNullable}}@Nullable {{/isNullable}}{{/openApiNullable}}{{/defaultValue}}{{/required}}{{/lambda.jSpecifyNullable}} | ||
|
jpfinne marked this conversation as resolved.
Resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#useJspecify}}{{#lambda.jSpecifyNullable}}{{#required}}{{#isNullable}}{{^openApiNullable}}@Nullable {{/openApiNullable}}{{/isNullable}}{{/required}}{{^required}}{{^useOptional}}{{#openApiNullable}}{{^isNullable}}@Nullable {{/isNullable}}{{/openApiNullable}}{{^openApiNullable}}@Nullable {{/openApiNullable}}{{/useOptional}}{{/required}}{{/lambda.jSpecifyNullable}}{{/useJspecify}} | ||
| {{#lambda.jSpecifyNullable}}{{#required}}{{#isNullable}}{{^openApiNullable}}@Nullable {{/openApiNullable}}{{/isNullable}}{{/required}}{{^required}}{{^useOptional}}{{#openApiNullable}}{{^isNullable}}@Nullable {{/isNullable}}{{/openApiNullable}}{{^openApiNullable}}@Nullable {{/openApiNullable}}{{/useOptional}}{{/required}}{{/lambda.jSpecifyNullable}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isPathParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}{{>paramDoc}} @PathVariable("{{baseName}}"){{>dateTimeParam}}{{#isDeprecated}} @Deprecated{{/isDeprecated}} {{>nullableAnnotation}}{{>optionalDataType}} {{paramName}}{{/isPathParam}} | ||
| {{#isPathParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}{{>paramDoc}} @PathVariable("{{baseName}}"){{>dateTimeParam}}{{#isDeprecated}} @Deprecated{{/isDeprecated}} {{>nullableAnnotation_apiArgument}}{{>optionalDataType}} {{paramName}}{{/isPathParam}} | ||
|
jpfinne marked this conversation as resolved.
Resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isQueryParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}}{{#useBeanValidation}} @Valid{{/useBeanValidation}}{{^isModel}} @RequestParam(value = {{#isMap}}""{{/isMap}}{{^isMap}}"{{baseName}}"{{/isMap}}{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{/isModel}}{{>dateTimeParam}}{{#isDeprecated}} @Deprecated{{/isDeprecated}} {{>nullableAnnotation}}{{>optionalDataType}} {{paramName}}{{/isQueryParam}} | ||
| {{#isQueryParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}}{{#useBeanValidation}} @Valid{{/useBeanValidation}}{{^isModel}} @RequestParam(value = {{#isMap}}""{{/isMap}}{{^isMap}}"{{baseName}}"{{/isMap}}{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{/isModel}}{{>dateTimeParam}}{{#isDeprecated}} @Deprecated{{/isDeprecated}} {{>nullableAnnotation_apiArgument}}{{>optionalDataType}} {{paramName}}{{/isQueryParam}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7224,14 +7224,29 @@ public void testJspecify(String library, int springBootVersion) throws IOExcepti | |
| "javax.annotation.Nullable", | ||
| "jakarta.annotation.Nullable") | ||
| .assertMethod("getRequiredDt").assertMethodAnnotations().containsWithName("NotNull").containsWithName("Valid"); | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
Resolved
|
||
| JavaFileAssert.assertThat(files.get("FooApi.java")) | ||
| JavaFileAssert fooApiAssert = JavaFileAssert.assertThat(files.get("FooApi.java")) | ||
| .assertTypeAnnotations().doesImportAnnotation("org.jspecify.annotations.Nullable").toType() | ||
| .fileContains( | ||
| "java.time.@Nullable Instant dtParam", | ||
| "java.time.@Nullable Instant dtQuery", | ||
| "java.time.@Nullable Instant dtCookie", | ||
| " @RequestParam(value = \"color\", required = false, defaultValue = \"red\") String color" | ||
| ); | ||
| "java.time.@Nullable Instant dtCookie"); | ||
|
|
||
| JavaFileAssert nbleApi = JavaFileAssert.assertThat(files.get("NbleApi.java")); | ||
| // SPRING_HTTP_INTERFACE has other requirements for default in api arguments | ||
| if (SPRING_HTTP_INTERFACE.equals(library)) { | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
Resolved
|
||
| nbleApi.fileContains( | ||
| ") String mandatory", | ||
| ") @Nullable String optional"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: In testJspecify the nbleApi.fileContains(") String mandatory", ") @nullable String optional") block is now byte-for-byte identical in the SPRING_HTTP_INTERFACE branch and the else branch, so the if/else reads as if it varies the NbleApi assertions when only the fooApiAssert color value differs. Hoist the identical nbleApi assertion above the if/else and keep only the differing color assertion inside each branch. Prompt for AI agents |
||
| fooApiAssert.fileContains( | ||
| "@RequestParam(value = \"color\", required = false, defaultValue = \"red\") @Nullable String color"); | ||
| } else { | ||
| nbleApi.fileContains( | ||
| ") String mandatory", | ||
| ") @Nullable String optional"); | ||
| fooApiAssert.fileContains( | ||
| "@RequestParam(value = \"color\", required = false, defaultValue = \"red\") String color"); | ||
| } | ||
|
|
||
| JavaFileAssert.assertThat(files.get("RequiredAndNullable.java")) | ||
| .fileContains( | ||
| "private @Nullable String str = null;", | ||
|
|
@@ -7314,13 +7329,7 @@ public void testJspecify_openapiNullable(String library, int springBootVersion) | |
| "javax.annotation.Nullable", | ||
| "jakarta.annotation.Nullable") | ||
| .assertMethod("getRequiredDt").assertMethodAnnotations().containsWithName("NotNull").containsWithName("Valid"); | ||
| JavaFileAssert.assertThat(files.get("FooApi.java")) | ||
| .assertTypeAnnotations().doesImportAnnotation("org.jspecify.annotations.Nullable").toType() | ||
| .fileContains( | ||
| "java.time.@Nullable Instant dtParam", | ||
| "java.time.@Nullable Instant dtQuery", | ||
| "java.time.@Nullable Instant dtCookie" | ||
| ); | ||
|
|
||
| JavaFileAssert.assertThat(files.get("RequiredAndNullable.java")) | ||
| .fileContains( | ||
| "private JsonNullable<String> str = JsonNullable.<String>undefined();", | ||
|
|
@@ -7344,6 +7353,23 @@ public void testJspecify_openapiNullable(String library, int springBootVersion) | |
| .doesNotContainWithName("Nullable") | ||
| .doesImportAnnotation("org.jspecify.annotations.Nullable"); | ||
| } | ||
| JavaFileAssert.assertThat(files.get("FooApi.java")) | ||
| .assertTypeAnnotations().doesImportAnnotation("org.jspecify.annotations.Nullable").toType() | ||
| .fileContains( | ||
| "java.time.@Nullable Instant dtParam", | ||
| "java.time.@Nullable Instant dtQuery", | ||
| "java.time.@Nullable Instant dtCookie"); | ||
| JavaFileAssert nbleApi = JavaFileAssert.assertThat(files.get("NbleApi.java")); | ||
| if (SPRING_HTTP_INTERFACE.equals(library)) { | ||
| nbleApi .fileContains( | ||
| "@RequestParam(value = \"mandatory\", required = true) String mandatory", | ||
| "@RequestParam(value = \"optional\", required = false) @Nullable String optional"); | ||
| } else { | ||
| // incorrect generation for required=false, nullable=true? | ||
| nbleApi .fileContains( | ||
| "@RequestParam(value = \"mandatory\", required = true) String mandatory", | ||
| "@RequestParam(value = \"optional\", required = false) String optional"); | ||
| } | ||
| } | ||
|
|
||
| @DataProvider(name = "jspecifyLibrariesUseOptional") | ||
|
|
@@ -7439,7 +7465,10 @@ public void testJspecify_useOptional(String library, int springBootVersion, bool | |
| .doesNotContainWithName("Nullable") | ||
| .doesImportAnnotation("org.jspecify.annotations.Nullable"); | ||
| } | ||
| } | ||
| JavaFileAssert.assertThat(files.get("NbleApi.java")).fileContains( | ||
| "@RequestParam(value = \"mandatory\", required = true) String mandatory", | ||
| "@RequestParam(value = \"optional\", required = false) Optional<String> optional"); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------- | ||
| // autoXSpringPaginated tests | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,10 +47,29 @@ paths: | |
| application/json: | ||
| schema: | ||
| $ref: '#/components/schemas/Foo' | ||
| /requiredAndNullable: | ||
| /nble: | ||
| get: | ||
| tags: | ||
| - nble | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: Operations are now tagged Prompt for AI agents |
||
| parameters: | ||
| - name: optional | ||
| in: query | ||
| required: false | ||
| schema: | ||
| type: string | ||
| nullable: true | ||
| - name: mandatory | ||
| in: query | ||
| required: true | ||
| schema: | ||
| type: string | ||
| nullable: true | ||
| responses: | ||
| default: | ||
| description: OK | ||
| post: | ||
| tags: | ||
| - requiredAndNullable | ||
| - nble | ||
| requestBody: | ||
| required: true | ||
| description: bodyWithRequiredAndNullableAttributes | ||
|
|
@@ -65,6 +84,7 @@ paths: | |
| application/json: | ||
| schema: | ||
| $ref: '#/components/schemas/RequiredAndNullable' | ||
|
|
||
| /upload: | ||
| post: | ||
| tags: | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.