From 0eecbf5d7c4c5503627fcfffb4eb8b1f03e36203 Mon Sep 17 00:00:00 2001 From: altro3 Date: Wed, 4 Sep 2024 21:13:29 +0700 Subject: [PATCH] Fix process additionalProperties = false (#1748) See: https://github.com/swagger-api/swagger-core/issues/4316 --- .../visitor/SchemaDefinitionUtils.java | 6 +- .../visitor/OpenApiSchemaFieldSpec.groovy | 67 +++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/openapi/src/main/java/io/micronaut/openapi/visitor/SchemaDefinitionUtils.java b/openapi/src/main/java/io/micronaut/openapi/visitor/SchemaDefinitionUtils.java index 41118d3157..eb745ccd1d 100644 --- a/openapi/src/main/java/io/micronaut/openapi/visitor/SchemaDefinitionUtils.java +++ b/openapi/src/main/java/io/micronaut/openapi/visitor/SchemaDefinitionUtils.java @@ -1265,9 +1265,11 @@ public static Map toValueMap(Map val } else if (key.equals(PROP_ADDITIONAL_PROPERTIES)) { if (io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.TRUE.toString().equals(value.toString())) { newValues.put(PROP_ADDITIONAL_PROPERTIES, true); + } else if (io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.FALSE.toString().equals(value.toString())) { + newValues.put(PROP_ADDITIONAL_PROPERTIES, false); + } // TODO // } else if (AdditionalPropertiesValue.USE_ADDITIONAL_PROPERTIES_ANNOTATION.toString().equals(value.toString())) { - } } else if (key.equals(PROP_ONE_TYPES) && isOpenapi31()) { newValues.put(PROP_TYPE, value); } else if (key.equals(PROP_DISCRIMINATOR_PROPERTY)) { @@ -1939,7 +1941,7 @@ private static void processSchemaAnn(Schema schemaToBind, VisitorContext context if (schemaAdditionalProperties == io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.TRUE) { schemaToBind.additionalProperties(true); } else if (schemaAdditionalProperties == io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.FALSE) { - schemaToBind.additionalProperties(null); + schemaToBind.additionalProperties(false); } } diff --git a/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiSchemaFieldSpec.groovy b/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiSchemaFieldSpec.groovy index 5313aacfcf..14426cb52d 100644 --- a/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiSchemaFieldSpec.groovy +++ b/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiSchemaFieldSpec.groovy @@ -1189,4 +1189,71 @@ class MyBean {} schemas.Car.properties.resourceType schemas.Car.properties.selected } + + void "test schema additionalProperties = false"() { + + when: + buildBeanDefinition('test.MyBean', ''' +package test; + +import io.micronaut.core.annotation.Nullable;import io.micronaut.http.annotation.Body; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Post; +import io.micronaut.http.annotation.QueryValue; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import jakarta.validation.Valid; +import java.io.Serializable; +import java.util.List; + +@Controller +class HelloController { + + @Post(value = "/search", consumes = "application/json", produces = "application/json") + @Operation(summary = "Returns List of Audit Log records based on the matching search criteria", description = "Returns list of Audit Log records matching the search critera. SLA:500", responses = { + @ApiResponse(responseCode = "200", description = "Successful retrieval of list of Audit Log records matching the search criteria", content = { + @Content(mediaType = "application/json", schema = @Schema(implementation = AuditLogDTO.class)) }), + @ApiResponse(responseCode = "400", description = "Invalid input provided", content = { @Content(mediaType = "application/json")}), + @ApiResponse(responseCode = "401", description = "Unauthorized", content = { @Content(mediaType = "application/json")}),}) + public List searchAuditLog( + @Parameter(description = "Page number for the search results", example = "1", required = false) @QueryValue(value = "page", defaultValue = "1") @Nullable Integer page, + @Parameter(description = "Size of the page", example = "1", required = false) @QueryValue(value = "size", defaultValue = "100") @Nullable Integer size, + @Parameter(description = "Audit Search criteria", example = "1", required = true) @Body @Valid AuditSearchCriteria auditSearchCriteria) { + return null; + } + +} + +enum TestEnum { + VAL1, VAL2 +} + +@Schema(additionalProperties = Schema.AdditionalPropertiesValue.FALSE) +class AuditSearchCriteria implements Serializable { + +} + +record AuditLogDTO( + TestEnum field1, + @io.swagger.v3.oas.annotations.media.Schema(deprecated = true) TestEnum field2 +) { +} + +@jakarta.inject.Singleton +class MyBean {} +''') + then: "the state is correct" + Utils.testReference != null + + when: "The OpenAPI is retrieved" + def openApi = Utils.testReference + def schemas = openApi.components.schemas + + then: "the components are valid" + schemas.AuditSearchCriteria.additionalProperties != null + schemas.AuditSearchCriteria.additionalProperties == false + } }