diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index cb32ed5a0266..4621879cc917 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -17,6 +17,7 @@ package org.openapitools.codegen.languages; +import com.fasterxml.jackson.databind.JsonNode; import com.github.javaparser.StaticJavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.MethodDeclaration; @@ -93,6 +94,16 @@ public class SpringCodegen extends AbstractJavaCodegen public static final String SKIP_DEFAULT_INTERFACE = "skipDefaultInterface"; public static final String GENERATE_CONSTRUCTOR_WITH_REQUIRED_ARGS = "generatedConstructorWithRequiredArgs"; + @Override + public String toDefaultParameterValue(Schema schema) { + Schema effectiveSchema = schema.get$ref() != null ? ModelUtils.getReferencedSchema(openAPI, schema) : schema; + Object defaultValue = schema.getDefault() != null ? schema.getDefault() : effectiveSchema.getDefault(); + if (defaultValue instanceof JsonNode && ((JsonNode) defaultValue).isNull()) { + return null; + } + return super.toDefaultParameterValue(schema); + } + public static final String RESOURCE_FOLDER = "resourceFolder"; public static final String RESOURCE_FOLDER_DESC = "resource folder for generated resources"; diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java index 144bb6927b96..398850ed9b5b 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java @@ -3029,6 +3029,58 @@ public void shouldIgnorePageableForSpringHttpInterface_issue24720() throws IOExc .doesNotHaveParameter("pageable"); } + @Test + public void nullSchemaDefaultIsNotRenderedAsSpringRequestParamDefault() throws IOException { + Map additionalProperties = new HashMap<>(); + additionalProperties.put(INTERFACE_ONLY, true); + additionalProperties.put(SKIP_DEFAULT_INTERFACE, true); + additionalProperties.put(USE_SPRING_BOOT4, true); + additionalProperties.put("useJackson3", true); + additionalProperties.put(USE_JSPECIFY, true); + additionalProperties.put(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, true); + additionalProperties.put(AbstractJavaCodegen.CONTAINER_DEFAULT_TO_NULL, true); + additionalProperties.put(GENERATE_JSON_INCLUDE_ANNOTATIONS, true); + additionalProperties.put(PERFORM_BEANVALIDATION, true); + additionalProperties.put(AbstractJavaCodegen.OPENAPI_NULLABLE, false); + + Map files = generateFromContract( + "src/test/resources/3_1/spring/optional-query-null-default.yaml", SPRING_HTTP_INTERFACE, additionalProperties); + + JavaFileAssert api = JavaFileAssert.assertThat(files.get("PlacesApi.java")); + api.assertMethod("getPlaces") + .assertParameter("ids").hasType("List") + .assertParameterAnnotations() + .containsWithNameAndDoesNotContainAttributes("RequestParam", List.of("defaultValue")); + api.assertMethod("getPlaces") + .assertParameter("search") + .assertParameterAnnotations() + .containsWithNameAndDoesNotContainAttributes("RequestParam", List.of("defaultValue")); + api.assertMethod("getPlaces") + .assertParameter("limit") + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"10\"")); + api.assertMethod("getPlaces") + .assertParameter("requiredIds") + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("required", "true")); + api.assertMethod("getPlaces") + .assertParameter("defaultIds") + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"a,b\"")); + api.assertMethod("getPlaces") + .assertParameter("literalNull") + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"null\"")); + api.assertMethod("getPlaces") + .assertParameter("referencedLiteralNull") + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"null\"")); + api.assertMethod("getPlaces") + .assertParameter("referencedNullDefault") + .assertParameterAnnotations() + .containsWithNameAndDoesNotContainAttributes("RequestParam", List.of("defaultValue")); + } + @Test public void explicitXSpringPaginatedFalseKeepsQueryParamsForSpringCloud_issue24720() throws IOException { // Regression #24720: x-spring-paginated: false on a spring-cloud operation must NOT be diff --git a/modules/openapi-generator/src/test/resources/3_1/spring/optional-query-null-default.yaml b/modules/openapi-generator/src/test/resources/3_1/spring/optional-query-null-default.yaml new file mode 100644 index 000000000000..7fd268572cf2 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_1/spring/optional-query-null-default.yaml @@ -0,0 +1,68 @@ +openapi: 3.1.0 +info: + title: Optional query null default + version: 1.0.0 +paths: + /places: + get: + operationId: getPlaces + parameters: + - name: ids + in: query + required: false + schema: + type: array + items: + type: string + default: null + - name: search + in: query + required: false + schema: + type: string + - name: limit + in: query + required: false + schema: + type: integer + default: 10 + - name: requiredIds + in: query + required: true + schema: + type: array + items: + type: string + - name: defaultIds + in: query + required: false + schema: + type: array + items: + type: string + default: [a, b] + - name: literalNull + in: query + required: false + schema: + type: string + default: "null" + - name: referencedLiteralNull + in: query + required: false + schema: + $ref: '#/components/schemas/stringWithNullDefault' + default: "null" + - name: referencedNullDefault + in: query + required: false + schema: + $ref: '#/components/schemas/stringWithNullDefault' + responses: + "200": + description: OK +components: + schemas: + stringWithNullDefault: + type: string + default: null