From ed2cfb176831fb3c1415d470b1fe1495b6f21239 Mon Sep 17 00:00:00 2001 From: jenkins Date: Mon, 1 Apr 2024 16:00:38 +0000 Subject: [PATCH 01/33] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- springdoc-openapi-starter-common/pom.xml | 2 +- springdoc-openapi-starter-webflux-api/pom.xml | 2 +- springdoc-openapi-starter-webflux-ui/pom.xml | 2 +- springdoc-openapi-starter-webmvc-api/pom.xml | 2 +- springdoc-openapi-starter-webmvc-ui/pom.xml | 2 +- springdoc-openapi-tests/pom.xml | 2 +- .../springdoc-openapi-actuator-webflux-tests/pom.xml | 2 +- .../springdoc-openapi-actuator-webmvc-tests/pom.xml | 2 +- .../springdoc-openapi-data-rest-tests/pom.xml | 2 +- .../springdoc-openapi-function-webflux-tests/pom.xml | 2 +- .../springdoc-openapi-function-webmvc-tests/pom.xml | 2 +- .../springdoc-openapi-groovy-tests/pom.xml | 2 +- .../springdoc-openapi-hateoas-tests/pom.xml | 2 +- .../springdoc-openapi-javadoc-tests/pom.xml | 2 +- .../springdoc-openapi-kotlin-webflux-tests/pom.xml | 2 +- .../springdoc-openapi-kotlin-webmvc-tests/pom.xml | 2 +- .../springdoc-openapi-security-tests/pom.xml | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/pom.xml b/pom.xml index a5c49cdbb..11339c18a 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.springdoc springdoc-openapi - 2.5.0 + 2.5.1-SNAPSHOT pom Spring openapi documentation Spring openapi documentation @@ -35,7 +35,7 @@ scm:git:git@github.com:springdoc/springdoc-openapi.git scm:git:git@github.com:springdoc/springdoc-openapi.git - v2.5.0 + HEAD diff --git a/springdoc-openapi-starter-common/pom.xml b/springdoc-openapi-starter-common/pom.xml index 958f25193..dd6ede53a 100644 --- a/springdoc-openapi-starter-common/pom.xml +++ b/springdoc-openapi-starter-common/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi - 2.5.0 + 2.5.1-SNAPSHOT springdoc-openapi-starter-common diff --git a/springdoc-openapi-starter-webflux-api/pom.xml b/springdoc-openapi-starter-webflux-api/pom.xml index b802dee83..d83221c8c 100644 --- a/springdoc-openapi-starter-webflux-api/pom.xml +++ b/springdoc-openapi-starter-webflux-api/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi - 2.5.0 + 2.5.1-SNAPSHOT springdoc-openapi-starter-webflux-api diff --git a/springdoc-openapi-starter-webflux-ui/pom.xml b/springdoc-openapi-starter-webflux-ui/pom.xml index 0b4aa79fb..26ddadf7a 100644 --- a/springdoc-openapi-starter-webflux-ui/pom.xml +++ b/springdoc-openapi-starter-webflux-ui/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi - 2.5.0 + 2.5.1-SNAPSHOT springdoc-openapi-starter-webflux-ui diff --git a/springdoc-openapi-starter-webmvc-api/pom.xml b/springdoc-openapi-starter-webmvc-api/pom.xml index 9b8ac4d47..8ffe7c7db 100644 --- a/springdoc-openapi-starter-webmvc-api/pom.xml +++ b/springdoc-openapi-starter-webmvc-api/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi - 2.5.0 + 2.5.1-SNAPSHOT springdoc-openapi-starter-webmvc-api diff --git a/springdoc-openapi-starter-webmvc-ui/pom.xml b/springdoc-openapi-starter-webmvc-ui/pom.xml index d987eb1c8..1f1c56b89 100644 --- a/springdoc-openapi-starter-webmvc-ui/pom.xml +++ b/springdoc-openapi-starter-webmvc-ui/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi - 2.5.0 + 2.5.1-SNAPSHOT springdoc-openapi-starter-webmvc-ui diff --git a/springdoc-openapi-tests/pom.xml b/springdoc-openapi-tests/pom.xml index 83ac3f9a5..f62280958 100644 --- a/springdoc-openapi-tests/pom.xml +++ b/springdoc-openapi-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi org.springdoc - 2.5.0 + 2.5.1-SNAPSHOT pom 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml index 40ce8b31b..933aadce0 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.0 + 2.5.1-SNAPSHOT 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml index 120f11ccd..e719c73cf 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.0 + 2.5.1-SNAPSHOT 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml index 00f4a96f2..c937bd6fe 100644 --- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.0 + 2.5.1-SNAPSHOT 4.0.0 springdoc-openapi-data-rest-tests diff --git a/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml index 07d7babc8..24f81f82c 100644 --- a/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.0 + 2.5.1-SNAPSHOT 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml index 5e46d7d54..34d734fdb 100644 --- a/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.0 + 2.5.1-SNAPSHOT 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml index d89bef434..4435adfad 100644 --- a/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi-tests - 2.5.0 + 2.5.1-SNAPSHOT springdoc-openapi-groovy-tests diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml index fc5b3cb86..ca833c0ec 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.0 + 2.5.1-SNAPSHOT 4.0.0 springdoc-openapi-hateoas-tests diff --git a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml index e3c0655f7..a657bd3df 100644 --- a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml @@ -2,7 +2,7 @@ org.springdoc springdoc-openapi-tests - 2.5.0 + 2.5.1-SNAPSHOT 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml index 0b104114e..214de16ee 100644 --- a/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.0 + 2.5.1-SNAPSHOT 4.0.0 springdoc-openapi-kotlin-webflux-tests diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml index 58eb8b1e3..745ee023f 100644 --- a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.0 + 2.5.1-SNAPSHOT 4.0.0 springdoc-openapi-kotlin-webmvc-tests diff --git a/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml index 9beae556a..2b8da2454 100644 --- a/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi-tests - 2.5.0 + 2.5.1-SNAPSHOT springdoc-openapi-security-tests From 679fb4de835a4cae0816259a31d9ae12eba10b75 Mon Sep 17 00:00:00 2001 From: footaku <18702821+footaku@users.noreply.github.com> Date: Wed, 3 Apr 2024 17:56:42 +0900 Subject: [PATCH 02/33] Add components parameter when calling AnnotationsUtils. The swagger-core's AnnotationsUtils has added an overload of the getHeaders method. A scenario where an NPE occurs if the components is not added as an argument has emerged. --- .../java/org/springdoc/core/service/OperationService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OperationService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OperationService.java index e673e6b1c..5a539b6b8 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OperationService.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OperationService.java @@ -3,7 +3,7 @@ * * * * * * * * * - * * * * * Copyright 2019-2022 the original author or authors. + * * * * * Copyright 2019-2024 the original author or authors. * * * * * * * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * * * * you may not use this file except in compliance with the License. @@ -412,7 +412,7 @@ private Optional getApiResponses( buildResponseContent(methodAttributes, components, classProduces, methodProduces, apiResponsesOp, response, apiResponseObject); - AnnotationsUtils.getHeaders(response.headers(), null, propertyResolverUtils.isOpenapi31()).ifPresent(apiResponseObject::headers); + AnnotationsUtils.getHeaders(response.headers(), components, null, propertyResolverUtils.isOpenapi31()).ifPresent(apiResponseObject::headers); // Make schema as string if empty calculateHeader(apiResponseObject); if (isResponseObject(apiResponseObject)) { From 7e78f059bd73b2c2bb8d890c00217f52f25515ed Mon Sep 17 00:00:00 2001 From: footaku <18702821+footaku@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:08:17 +0900 Subject: [PATCH 03/33] Testing pattern with specifying Schema in response headers. Confirm that setting Header annotations specified in the Schema attribute in ApiResponse's headers attribute does not result in errors. --- .../api/v30/app218/HelloController.java | 63 +++++++++++++++++++ .../api/v30/app218/SpringDocApp218Test.java | 36 +++++++++++ .../test/resources/results/3.0.1/app218.json | 48 ++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/SpringDocApp218Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app218.json diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/HelloController.java new file mode 100644 index 000000000..6749896a4 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/HelloController.java @@ -0,0 +1,63 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2024 the original author or authors. + * * * * + * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * you may not use this file except in compliance with the License. + * * * * You may obtain a copy of the License at + * * * * + * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * + * * * * Unless required by applicable law or agreed to in writing, software + * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * See the License for the specific language governing permissions and + * * * * limitations under the License. + * * * + * * + * + */ + +package test.org.springdoc.api.v30.app218; + + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import org.springframework.http.HttpHeaders; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.net.URI; + + +@RestController +@RequestMapping("/") +public class HelloController { + + @Operation( + summary = "Summary", + description = "This is description.", + tags = {"Sample"}, + responses = { + @ApiResponse( + responseCode = "201", + description = "201 (Created)", + headers = + @Header( + name = HttpHeaders.LOCATION, + description = "Sample endpoint", + schema = @Schema(implementation = URI.class) + ) + ) + } + ) + @GetMapping + public String get() { + return "Hello World!"; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/SpringDocApp218Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/SpringDocApp218Test.java new file mode 100644 index 000000000..24b9d92b4 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/SpringDocApp218Test.java @@ -0,0 +1,36 @@ +/* + * + * * Copyright 2019-2024 the original author or authors. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * https://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package test.org.springdoc.api.v30.app218; + +import org.springdoc.core.customizers.SpecPropertiesCustomizer; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +/** + *

+ * A test for {@link SpecPropertiesCustomizer} + */ +@SpringBootTest +public class SpringDocApp218Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} + +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app218.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app218.json new file mode 100644 index 000000000..4aeec31eb --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app218.json @@ -0,0 +1,48 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/": { + "get": { + "tags": [ + "Sample" + ], + "summary": "Summary", + "description": "This is description.", + "operationId": "get", + "responses": { + "201": { + "description": "201 (Created)", + "headers": { + "Location": { + "description": "Sample endpoint", + "style": "simple", + "schema": { + "type": "string", + "format": "uri" + } + } + }, + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} From 5f3fe3ac6981f3ab5ab7247d5e19707bc2e2ea86 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Tue, 9 Apr 2024 10:59:08 +0200 Subject: [PATCH 04/33] code review --- .../java/org/springdoc/core/service/GenericResponseService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java index c54898caf..b3ad7e3df 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java @@ -397,7 +397,7 @@ private Map computeResponseFromDoc(Components components, M apiResponse.extensions(extensions); } } - AnnotationsUtils.getHeaders(apiResponseAnnotations.headers(), methodAttributes.getJsonViewAnnotation(), openapi31) + AnnotationsUtils.getHeaders(apiResponseAnnotations.headers(), components, methodAttributes.getJsonViewAnnotation(), openapi31) .ifPresent(apiResponse::headers); apiResponsesOp.addApiResponse(httpCode, apiResponse); } From 5a04f307f9c6201157caed37d1cb99beed2e333f Mon Sep 17 00:00:00 2001 From: Michael Schout Date: Thu, 18 Apr 2024 12:13:32 -0500 Subject: [PATCH 05/33] Fix missing exception response types in OpenAPI spec Since e893628d5494808fcc8a9ee9be0c1d446a805f47, some error response types referenced by the schema in `$ref`'s were missing from the spec. --- .../org/springdoc/core/service/GenericResponseService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java index c54898caf..c46468783 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java @@ -66,6 +66,7 @@ import org.springdoc.core.parsers.ReturnTypeParser; import org.springdoc.core.properties.SpringDocConfigProperties; import org.springdoc.core.providers.JavadocProvider; +import org.springdoc.core.providers.ObjectMapperProvider; import org.springdoc.core.utils.PropertyResolverUtils; import org.springdoc.core.utils.SpringDocAnnotationsUtils; @@ -736,7 +737,7 @@ private Map getGenericMapResponse(HandlerMethod handlerMeth LinkedHashMap genericApiResponsesClone; try { - ObjectMapper objectMapper = new ObjectMapper(); + ObjectMapper objectMapper = ObjectMapperProvider.createJson(springDocConfigProperties); genericApiResponsesClone = objectMapper.readValue(objectMapper.writeValueAsString(genericApiResponseMap), ApiResponses.class); return genericApiResponsesClone; } From e2df1525876f40d4840bde0b6eb2c2db2920225e Mon Sep 17 00:00:00 2001 From: James Bradlee Date: Fri, 19 Apr 2024 22:12:37 +0200 Subject: [PATCH 06/33] fix: add support for leading tab characters with `trim-kotlin-indent`. --- .../java/org/springdoc/core/utils/PropertyResolverUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/PropertyResolverUtils.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/PropertyResolverUtils.java index e70e9666e..dfa282e82 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/PropertyResolverUtils.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/PropertyResolverUtils.java @@ -143,7 +143,7 @@ private int resolveMinIndent(String[] lines) { private int countLeadingSpaces(String line) { int count = 0; for (char ch : line.toCharArray()) { - if (ch != ' ') break; + if (ch != ' ' && ch != '\t') break; count++; } return count; @@ -222,4 +222,4 @@ public Map resolveExtensions(Locale locale, Map else return extensions; } -} \ No newline at end of file +} From bf2bd2fe5bd57f76457290e8d95dc3078fc4d081 Mon Sep 17 00:00:00 2001 From: Marcelo Boveto Shima Date: Mon, 6 May 2024 14:41:21 -0300 Subject: [PATCH 07/33] pass HttpRequest to ServerBaseUrlCustomizer --- .../customizers/ServerBaseUrlCustomizer.java | 5 ++++- .../core/service/OpenAPIService.java | 5 +++-- .../api/AbstractOpenApiResourceTest.java | 21 ++++++++++--------- .../webflux/api/OpenApiActuatorResource.java | 2 +- .../webflux/api/OpenApiResource.java | 2 +- .../springdoc/webmvc/api/OpenApiResource.java | 4 +++- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/ServerBaseUrlCustomizer.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/ServerBaseUrlCustomizer.java index b209ba72e..47c5d3891 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/ServerBaseUrlCustomizer.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/ServerBaseUrlCustomizer.java @@ -24,6 +24,8 @@ package org.springdoc.core.customizers; +import org.springframework.http.HttpRequest; + /** * The interface Server Base URL customiser. * @author skylar -stark @@ -35,7 +37,8 @@ public interface ServerBaseUrlCustomizer { * Customise. * * @param serverBaseUrl the serverBaseUrl. + * @param request the request. * @return the customised serverBaseUrl */ - String customize(String serverBaseUrl); + String customize(String serverBaseUrl, HttpRequest request); } diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OpenAPIService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OpenAPIService.java index 4a3fe8ad8..bb69b1a6c 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OpenAPIService.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OpenAPIService.java @@ -81,6 +81,7 @@ import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.http.HttpRequest; import org.springframework.stereotype.Controller; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.ControllerAdvice; @@ -490,12 +491,12 @@ public Schema resolveProperties(Schema schema, Locale locale) { * * @param serverBaseUrl the server base url */ - public void setServerBaseUrl(String serverBaseUrl) { + public void setServerBaseUrl(String serverBaseUrl, HttpRequest httpRequest) { String customServerBaseUrl = serverBaseUrl; if (serverBaseUrlCustomizers.isPresent()) { for (ServerBaseUrlCustomizer customizer : serverBaseUrlCustomizers.get()) { - customServerBaseUrl = customizer.customize(customServerBaseUrl); + customServerBaseUrl = customizer.customize(customServerBaseUrl, httpRequest); } } diff --git a/springdoc-openapi-starter-common/src/test/java/org/springdoc/api/AbstractOpenApiResourceTest.java b/springdoc-openapi-starter-common/src/test/java/org/springdoc/api/AbstractOpenApiResourceTest.java index fdf75d7b0..f670da701 100644 --- a/springdoc-openapi-starter-common/src/test/java/org/springdoc/api/AbstractOpenApiResourceTest.java +++ b/springdoc-openapi-starter-common/src/test/java/org/springdoc/api/AbstractOpenApiResourceTest.java @@ -62,6 +62,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.mock.http.client.MockClientHttpRequest; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; @@ -190,7 +191,7 @@ void preLoadingModeShouldNotOverwriteServers() throws InterruptedException { doCallRealMethod().when(openAPIService).updateServers(any()); when(openAPIService.getCachedOpenAPI(any())).thenCallRealMethod(); doAnswer(new CallsRealMethods()).when(openAPIService).setServersPresent(true); - doAnswer(new CallsRealMethods()).when(openAPIService).setServerBaseUrl(any()); + doAnswer(new CallsRealMethods()).when(openAPIService).setServerBaseUrl(any(), any()); doAnswer(new CallsRealMethods()).when(openAPIService).setCachedOpenAPI(any(), any()); String customUrl = "https://custom.com"; @@ -212,7 +213,7 @@ properties, springDocProviders, new SpringDocCustomizers(Optional.of(singletonLi Thread.sleep(1_000); // emulate generating base url - openAPIService.setServerBaseUrl(generatedUrl); + openAPIService.setServerBaseUrl(generatedUrl, new MockClientHttpRequest()); openAPIService.updateServers(openAPI); Locale locale = Locale.US; OpenAPI after = resource.getOpenApi(locale); @@ -224,7 +225,7 @@ properties, springDocProviders, new SpringDocCustomizers(Optional.of(singletonLi void serverBaseUrlCustomisersTest() throws InterruptedException { doCallRealMethod().when(openAPIService).updateServers(any()); when(openAPIService.getCachedOpenAPI(any())).thenCallRealMethod(); - doAnswer(new CallsRealMethods()).when(openAPIService).setServerBaseUrl(any()); + doAnswer(new CallsRealMethods()).when(openAPIService).setServerBaseUrl(any(), any()); doAnswer(new CallsRealMethods()).when(openAPIService).setCachedOpenAPI(any(), any()); SpringDocConfigProperties properties = new SpringDocConfigProperties(); @@ -247,37 +248,37 @@ springDocProviders, new SpringDocCustomizers(Optional.empty(),Optional.empty(),O // Test that setting generated URL works fine with no customizers present String generatedUrl = "https://generated-url.com/context-path"; - openAPIService.setServerBaseUrl(generatedUrl); + openAPIService.setServerBaseUrl(generatedUrl, new MockClientHttpRequest()); openAPIService.updateServers(openAPI); OpenAPI after = resource.getOpenApi(locale); assertThat(after.getServers().get(0).getUrl(), is(generatedUrl)); // Test that adding a serverBaseUrlCustomizer has the desired effect - ServerBaseUrlCustomizer serverBaseUrlCustomizer = serverBaseUrl -> serverBaseUrl.replace("/context-path", ""); + ServerBaseUrlCustomizer serverBaseUrlCustomizer = (serverBaseUrl, request) -> serverBaseUrl.replace("/context-path", ""); List serverBaseUrlCustomizerList = new ArrayList<>(); serverBaseUrlCustomizerList.add(serverBaseUrlCustomizer); ReflectionTestUtils.setField(openAPIService, "serverBaseUrlCustomizers", Optional.of(serverBaseUrlCustomizerList)); - openAPIService.setServerBaseUrl(generatedUrl); + openAPIService.setServerBaseUrl(generatedUrl, new MockClientHttpRequest()); openAPIService.updateServers(openAPI); after = resource.getOpenApi(locale); assertThat(after.getServers().get(0).getUrl(), is("https://generated-url.com")); // Test that serverBaseUrlCustomisers are performed in order generatedUrl = "https://generated-url.com/context-path/second-path"; - ServerBaseUrlCustomizer serverBaseUrlCustomiser2 = serverBaseUrl -> serverBaseUrl.replace("/context-path/second-path", ""); + ServerBaseUrlCustomizer serverBaseUrlCustomiser2 = (serverBaseUrl, request) -> serverBaseUrl.replace("/context-path/second-path", ""); serverBaseUrlCustomizerList.add(serverBaseUrlCustomiser2); - openAPIService.setServerBaseUrl(generatedUrl); + openAPIService.setServerBaseUrl(generatedUrl, new MockClientHttpRequest()); openAPIService.updateServers(openAPI); after = resource.getOpenApi(locale); assertThat(after.getServers().get(0).getUrl(), is("https://generated-url.com/second-path")); // Test that all serverBaseUrlCustomisers in the List are performed - ServerBaseUrlCustomizer serverBaseUrlCustomiser3 = serverBaseUrl -> serverBaseUrl.replace("/second-path", ""); + ServerBaseUrlCustomizer serverBaseUrlCustomiser3 = (serverBaseUrl, request) -> serverBaseUrl.replace("/second-path", ""); serverBaseUrlCustomizerList.add(serverBaseUrlCustomiser3); - openAPIService.setServerBaseUrl(generatedUrl); + openAPIService.setServerBaseUrl(generatedUrl, new MockClientHttpRequest()); openAPIService.updateServers(openAPI); after = resource.getOpenApi(locale); assertThat(after.getServers().get(0).getUrl(), is("https://generated-url.com")); diff --git a/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/api/OpenApiActuatorResource.java b/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/api/OpenApiActuatorResource.java index 75ad34354..3bee371a5 100644 --- a/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/api/OpenApiActuatorResource.java +++ b/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/api/OpenApiActuatorResource.java @@ -131,7 +131,7 @@ public Mono openapiYaml(ServerHttpRequest serverHttpRequest, Locale loca protected void calculateServerUrl(ServerHttpRequest serverHttpRequest, String apiDocsUrl, Locale locale) { super.initOpenAPIBuilder(locale); URI uri = getActuatorURI(serverHttpRequest.getURI().getScheme(), serverHttpRequest.getURI().getHost()); - openAPIService.setServerBaseUrl(uri.toString()); + openAPIService.setServerBaseUrl(uri.toString(), serverHttpRequest); } @Override diff --git a/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/api/OpenApiResource.java b/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/api/OpenApiResource.java index acbefce90..0b29503d1 100644 --- a/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/api/OpenApiResource.java +++ b/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/api/OpenApiResource.java @@ -229,7 +229,7 @@ protected void getWebFluxRouterFunctionPaths(Locale locale, OpenAPI openAPI) { protected void calculateServerUrl(ServerHttpRequest serverHttpRequest, String apiDocsUrl, Locale locale) { initOpenAPIBuilder(locale); String serverUrl = getServerUrl(serverHttpRequest, apiDocsUrl); - openAPIService.setServerBaseUrl(serverUrl); + openAPIService.setServerBaseUrl(serverUrl, serverHttpRequest); } /** diff --git a/springdoc-openapi-starter-webmvc-api/src/main/java/org/springdoc/webmvc/api/OpenApiResource.java b/springdoc-openapi-starter-webmvc-api/src/main/java/org/springdoc/webmvc/api/OpenApiResource.java index 4b5fd61a7..288496a80 100644 --- a/springdoc-openapi-starter-webmvc-api/src/main/java/org/springdoc/webmvc/api/OpenApiResource.java +++ b/springdoc-openapi-starter-webmvc-api/src/main/java/org/springdoc/webmvc/api/OpenApiResource.java @@ -55,6 +55,7 @@ import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.ObjectFactory; +import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.util.CollectionUtils; import org.springframework.util.MimeType; import org.springframework.web.bind.annotation.RequestMethod; @@ -244,7 +245,8 @@ private Comparator byReversedRequestMappingInfos() { protected void calculateServerUrl(HttpServletRequest request, String apiDocsUrl, Locale locale) { super.initOpenAPIBuilder(locale); String calculatedUrl = getServerUrl(request, apiDocsUrl); - openAPIService.setServerBaseUrl(calculatedUrl); + ServletServerHttpRequest serverRequest = request != null ? new ServletServerHttpRequest(request) : null; + openAPIService.setServerBaseUrl(calculatedUrl, serverRequest); } /** From 8367ba9d61ad8582e295a33d2e7fd392c1eeb9b1 Mon Sep 17 00:00:00 2001 From: jsieczczynski Date: Fri, 24 May 2024 09:06:26 +0200 Subject: [PATCH 08/33] Add failing test case --- .../api/v30/app219/HelloController.java | 42 ++++++++++++++++ .../api/v30/app219/SpringDocApp219Test.java | 36 ++++++++++++++ .../springdoc/api/v30/app219/TestObject.java | 49 +++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/SpringDocApp219Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/TestObject.java diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/HelloController.java new file mode 100644 index 000000000..0b2b37d5c --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/HelloController.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * Copyright 2019-2022 the original author or authors. + * * * * * + * * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * * you may not use this file except in compliance with the License. + * * * * * You may obtain a copy of the License at + * * * * * + * * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * * + * * * * * Unless required by applicable law or agreed to in writing, software + * * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * * See the License for the specific language governing permissions and + * * * * * limitations under the License. + * * * * + * * * + * * + * + */ + +package test.org.springdoc.api.v30.app219; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping(value = "/api", produces = {"application/xml"}, consumes = {"application/json"}) +public class HelloController { + + @RequestMapping(value = "/testpost", method = RequestMethod.POST, produces = {"application/json"}, + consumes = {"application/json;charset=UTF-8", "application/json; charset=UTF-8"}) + public ResponseEntity testpost(@RequestBody TestObject dto) { + return ResponseEntity.ok(dto); + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/SpringDocApp219Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/SpringDocApp219Test.java new file mode 100644 index 000000000..a6ec97f84 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/SpringDocApp219Test.java @@ -0,0 +1,36 @@ +/* + * + * * + * * * + * * * * + * * * * * Copyright 2019-2022 the original author or authors. + * * * * * + * * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * * you may not use this file except in compliance with the License. + * * * * * You may obtain a copy of the License at + * * * * * + * * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * * + * * * * * Unless required by applicable law or agreed to in writing, software + * * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * * See the License for the specific language governing permissions and + * * * * * limitations under the License. + * * * * + * * * + * * + * + */ + +package test.org.springdoc.api.v30.app219; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.test.context.ActiveProfiles; +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +@ActiveProfiles("219") +public class SpringDocApp219Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/TestObject.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/TestObject.java new file mode 100644 index 000000000..ca336cca3 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/TestObject.java @@ -0,0 +1,49 @@ +/* + * + * * + * * * + * * * * + * * * * * Copyright 2019-2022 the original author or authors. + * * * * * + * * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * * you may not use this file except in compliance with the License. + * * * * * You may obtain a copy of the License at + * * * * * + * * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * * + * * * * * Unless required by applicable law or agreed to in writing, software + * * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * * See the License for the specific language governing permissions and + * * * * * limitations under the License. + * * * * + * * * + * * + * + */ + +package test.org.springdoc.api.v30.app219; + +import java.time.LocalDateTime; + +public class TestObject { + public String stringValue; + + public LocalDateTime localDateTime; + + public String getStringValue() { + return stringValue; + } + + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + public LocalDateTime getLocalDateTime() { + return localDateTime; + } + + public void setLocalDateTime(LocalDateTime localDateTime) { + this.localDateTime = localDateTime; + } +} From d6da952030fc86992ca6a32b7127cfd2e5c24b8f Mon Sep 17 00:00:00 2001 From: jsieczczynski Date: Fri, 24 May 2024 09:06:44 +0200 Subject: [PATCH 09/33] Correctly calculate consumes and produces --- .../core/models/MethodAttributes.java | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java index bb2e4b69a..dbb545a98 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java @@ -25,6 +25,8 @@ package org.springdoc.core.models; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; @@ -32,11 +34,13 @@ import com.fasterxml.jackson.annotation.JsonView; import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponses; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.Nullable; import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -275,28 +279,38 @@ else if (reqMappingClass != null) { * @param headers the headers */ private void fillMethods(String[] produces, String[] consumes, String[] headers) { - if (ArrayUtils.isEmpty(methodProduces)) { - if (ArrayUtils.isNotEmpty(produces)) - methodProduces = produces; - else if (ArrayUtils.isNotEmpty(classProduces)) - methodProduces = classProduces; - else - methodProduces = new String[] { defaultProducesMediaType }; - } - - if (ArrayUtils.isEmpty(methodConsumes)) { - if (ArrayUtils.isNotEmpty(consumes)) - methodConsumes = consumes; - else if (ArrayUtils.isNotEmpty(classConsumes)) - methodConsumes = classConsumes; - else - methodConsumes = new String[] { defaultConsumesMediaType }; - } - - if (CollectionUtils.isEmpty(this.headers)) - setHeaders(headers); + if (ArrayUtils.isNotEmpty(produces)) { + methodProduces = mergeArrays(methodProduces, produces); + } else if (ArrayUtils.isNotEmpty(classProduces)) { + methodProduces = mergeArrays(methodProduces, classProduces); + } else if (ArrayUtils.isEmpty(methodProduces)) { + methodProduces = new String[] {defaultProducesMediaType}; + } + + if (ArrayUtils.isNotEmpty(consumes)) { + methodConsumes = mergeArrays(methodConsumes, consumes); + } else if (ArrayUtils.isNotEmpty(classConsumes)) { + methodConsumes = mergeArrays(methodConsumes, classConsumes); + } else if (ArrayUtils.isEmpty(methodConsumes)) { + methodConsumes = new String[] {defaultConsumesMediaType}; + } + + setHeaders(headers); } + /** + * Merge string arrays into one array with unique values + * + * @param array1 the array1 + * @param array2 the array2 + * @return the string [ ] + */ + private String[] mergeArrays(@Nullable String[] array1, String[] array2) { + Set uniqueValues = array1 == null ? new HashSet<>() : Arrays.stream(array1).collect(Collectors.toSet()); + uniqueValues.addAll(Arrays.asList(array2)); + return uniqueValues.toArray(new String[0]); + } + /** * Is method overloaded boolean. * From adffea0f7a528b4adb68c9fd2ea3c8fe91ea391e Mon Sep 17 00:00:00 2001 From: Claudio Nave Date: Fri, 14 Jun 2024 00:08:31 +0200 Subject: [PATCH 10/33] Upgrade spring boot parent version to 3.3.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 11339c18a..19bd4b57c 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.4 + 3.3.0 From a9bd320d7c665126539b56de195852deb6a87ee1 Mon Sep 17 00:00:00 2001 From: Claudio Nave Date: Fri, 14 Jun 2024 00:37:46 +0200 Subject: [PATCH 11/33] Add actuator sbom to test cases --- .../src/test/resources/results/app146-1.json | 62 +++++++++++++++++++ .../src/test/resources/results/app147-1.json | 62 +++++++++++++++++++ .../src/test/resources/results/app148-2.json | 62 +++++++++++++++++++ .../src/test/resources/results/app186.json | 62 +++++++++++++++++++ .../src/test/resources/results/app147-1.json | 62 +++++++++++++++++++ .../src/test/resources/results/app148-2.json | 62 +++++++++++++++++++ .../src/test/resources/results/app186.json | 62 +++++++++++++++++++ 7 files changed, 434 insertions(+) diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app146-1.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app146-1.json index 4d21f4405..dc3884dd2 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app146-1.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app146-1.json @@ -217,6 +217,68 @@ } } }, + "/application/sbom": { + "get": { + "operationId": "sbom", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom'", + "tags": [ + "Actuator" + ] + } + }, + "/application/sbom/{id}": { + "get": { + "operationId": "sbom-id", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom-id'", + "tags": [ + "Actuator" + ] + } + }, "/application/metrics": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-1.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-1.json index cbcf7fd50..2140650d2 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-1.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-1.json @@ -217,6 +217,68 @@ } } }, + "/application/sbom": { + "get": { + "operationId": "sbom", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom'", + "tags": [ + "Actuator" + ] + } + }, + "/application/sbom/{id}": { + "get": { + "operationId": "sbom-id", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom-id'", + "tags": [ + "Actuator" + ] + } + }, "/application/metrics": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app148-2.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app148-2.json index 837455a90..ab8724aca 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app148-2.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app148-2.json @@ -217,6 +217,68 @@ } } }, + "/application/sbom": { + "get": { + "operationId": "sbom", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom'", + "tags": [ + "Actuator" + ] + } + }, + "/application/sbom/{id}": { + "get": { + "operationId": "sbom-id", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom-id'", + "tags": [ + "Actuator" + ] + } + }, "/application/metrics": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app186.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app186.json index 6f5111c7a..dc6ace088 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app186.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app186.json @@ -217,6 +217,68 @@ } } }, + "/actuator/sbom": { + "get": { + "operationId": "sbom", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom'", + "tags": [ + "Actuator" + ] + } + }, + "/actuator/sbom/{id}": { + "get": { + "operationId": "sbom-id", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom-id'", + "tags": [ + "Actuator" + ] + } + }, "/actuator/metrics": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app147-1.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app147-1.json index 601c304ca..5cd279fa0 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app147-1.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app147-1.json @@ -297,6 +297,68 @@ } } }, + "/application/sbom": { + "get": { + "operationId": "sbom", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom'", + "tags": [ + "Actuator" + ] + } + }, + "/application/sbom/{id}": { + "get": { + "operationId": "sbom-id", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom-id'", + "tags": [ + "Actuator" + ] + } + }, "/application/mappings": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app148-2.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app148-2.json index 1d726c0ba..210744fd1 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app148-2.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app148-2.json @@ -297,6 +297,68 @@ } } }, + "/application/sbom": { + "get": { + "operationId": "sbom", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom'", + "tags": [ + "Actuator" + ] + } + }, + "/application/sbom/{id}": { + "get": { + "operationId": "sbom-id", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom-id'", + "tags": [ + "Actuator" + ] + } + }, "/application/mappings": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app186.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app186.json index c136df41f..77e236426 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app186.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app186.json @@ -297,6 +297,68 @@ } } }, + "/actuator/sbom": { + "get": { + "operationId": "sbom", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom'", + "tags": [ + "Actuator" + ] + } + }, + "/actuator/sbom/{id}": { + "get": { + "operationId": "sbom-id", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + }, + "description": "OK" + } + }, + "summary": "Actuator web endpoint 'sbom-id'", + "tags": [ + "Actuator" + ] + } + }, "/actuator/mappings": { "get": { "tags": [ From dd30b9d0c8c707dae5de90cfbdc5d6b99ccaee3e Mon Sep 17 00:00:00 2001 From: Claudio Nave Date: Fri, 14 Jun 2024 00:06:48 +0200 Subject: [PATCH 12/33] Replace Page with PagedModel when pageSerializationMode is set to VIA_DTO --- .../SpringDocPageConfiguration.java | 96 ++++ .../core/converters/PageOpenAPIConverter.java | 108 +++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../test/org/springdoc/api/app10/Dummy.java | 34 ++ .../springdoc/api/app10/HelloController.java | 75 ++++ .../api/app10/SpringDocApp10DirectTest.java | 53 +++ .../app10/SpringDocApp10NotSpecifiedTest.java | 52 +++ .../api/app10/SpringDocApp10ViaDtoTest.java | 54 +++ .../test/resources/results/app10-direct.json | 409 ++++++++++++++++++ .../test/resources/results/app10-via_dto.json | 213 +++++++++ 10 files changed, 1095 insertions(+) create mode 100644 springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageConfiguration.java create mode 100644 springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java create mode 100644 springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/Dummy.java create mode 100644 springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/HelloController.java create mode 100644 springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10DirectTest.java create mode 100644 springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java create mode 100644 springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10ViaDtoTest.java create mode 100644 springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/app10-direct.json create mode 100644 springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/app10-via_dto.json diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageConfiguration.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageConfiguration.java new file mode 100644 index 000000000..6df0b467a --- /dev/null +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageConfiguration.java @@ -0,0 +1,96 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2024 the original author or authors. + * * * * + * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * you may not use this file except in compliance with the License. + * * * * You may obtain a copy of the License at + * * * * + * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * + * * * * Unless required by applicable law or agreed to in writing, software + * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * See the License for the specific language governing permissions and + * * * * limitations under the License. + * * * + * * + * + */ + +package org.springdoc.core.configuration; + +import org.springdoc.core.converters.PageOpenAPIConverter; +import org.springdoc.core.converters.SortOpenAPIConverter; +import org.springdoc.core.converters.models.SortObject; +import org.springdoc.core.customizers.DataRestDelegatingMethodParameterCustomizer; +import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer; +import org.springdoc.core.providers.ObjectMapperProvider; +import org.springdoc.core.providers.RepositoryRestConfigurationProvider; +import org.springdoc.core.providers.SpringDataWebPropertiesProvider; +import org.springframework.boot.autoconfigure.condition.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PagedModel; +import org.springframework.data.web.config.EnableSpringDataWebSupport; +import org.springframework.data.web.config.SpringDataWebSettings; + +import java.util.Optional; + +import static org.springdoc.core.utils.Constants.SPRINGDOC_ENABLED; +import static org.springdoc.core.utils.Constants.SPRINGDOC_SORT_CONVERTER_ENABLED; +import static org.springdoc.core.utils.SpringDocUtils.getConfig; + +/** + * The type Spring doc page configuration. + * + * @author Claudio Nave + */ +@Lazy(false) +@Configuration(proxyBeanMethods = false) +@ConditionalOnProperty(name = SPRINGDOC_ENABLED, matchIfMissing = true) +@ConditionalOnClass({ Page.class, PagedModel.class }) +@ConditionalOnWebApplication +@ConditionalOnBean(SpringDocConfiguration.class) +public class SpringDocPageConfiguration { + + /** + * Page open api converter. + * @param objectMapperProvider the object mapper provider + * @return the page open api converter + */ + @Bean + @ConditionalOnMissingBean + @ConditionalOnBean(SpringDataWebSettings.class) + @Lazy(false) + PageOpenAPIConverter pageOpenAPIConverter(SpringDataWebSettings settings, + ObjectMapperProvider objectMapperProvider) { + return new PageOpenAPIConverter( + settings.pageSerializationMode() == EnableSpringDataWebSupport.PageSerializationMode.VIA_DTO, + objectMapperProvider); + } + + /** + * Delegating method parameter customizer delegating method parameter customizer. + * @param optionalSpringDataWebPropertiesProvider the optional spring data web + * properties + * @param optionalRepositoryRestConfiguration the optional repository rest + * configuration + * @return the delegating method parameter customizer + */ + @Bean + @ConditionalOnMissingBean + @Lazy(false) + DelegatingMethodParameterCustomizer delegatingMethodParameterCustomizer( + Optional optionalSpringDataWebPropertiesProvider, + Optional optionalRepositoryRestConfiguration) { + return new DataRestDelegatingMethodParameterCustomizer(optionalSpringDataWebPropertiesProvider, + optionalRepositoryRestConfiguration); + } + +} \ No newline at end of file diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java new file mode 100644 index 000000000..3fcada041 --- /dev/null +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java @@ -0,0 +1,108 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2024 the original author or authors. + * * * * + * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * you may not use this file except in compliance with the License. + * * * * You may obtain a copy of the License at + * * * * + * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * + * * * * Unless required by applicable law or agreed to in writing, software + * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * See the License for the specific language governing permissions and + * * * * limitations under the License. + * * * + * * + * + */ + +package org.springdoc.core.converters; + +import com.fasterxml.jackson.databind.JavaType; +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverter; +import io.swagger.v3.core.converter.ModelConverterContext; +import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.StringUtils; +import org.springdoc.core.providers.ObjectMapperProvider; +import org.springframework.core.ResolvableType; +import org.springframework.data.web.PagedModel; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Iterator; + +/** + * The Spring Data Page type model converter. + * + * @author Claudio Nave + */ +public class PageOpenAPIConverter implements ModelConverter { + + private static final String PAGE_TO_REPLACE = "org.springframework.data.domain.Page"; + + /** + * The constant PAGED_MODEL. + */ + private static final AnnotatedType PAGED_MODEL = new AnnotatedType(PagedModel.class).resolveAsRef(true); + + /** + * The Spring doc object mapper. + */ + private final ObjectMapperProvider springDocObjectMapper; + /** + * Flag to replace Page with PagedModel or not. + */ + private final boolean replacePageWithPagedModel; + + /** + * Instantiates a new Page open api converter. + * @param replacePageWithPagedModel flag to replace Page with PagedModel or not + * @param springDocObjectMapper the spring doc object mapper + */ + public PageOpenAPIConverter(boolean replacePageWithPagedModel, ObjectMapperProvider springDocObjectMapper) { + this.replacePageWithPagedModel = replacePageWithPagedModel; + this.springDocObjectMapper = springDocObjectMapper; + } + + /** + * Resolve schema. + * @param type the type + * @param context the context + * @param chain the chain + * @return the schema + */ + @Override + public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator chain) { + JavaType javaType = springDocObjectMapper.jsonMapper().constructType(type.getType()); + if (javaType != null) { + Class cls = javaType.getRawClass(); + if (replacePageWithPagedModel && PAGE_TO_REPLACE.equals(cls.getCanonicalName())) { + if (!type.isSchemaProperty()) + type = resolvePagedModelType(type); + else + type.name(cls.getSimpleName() + StringUtils.capitalize(type.getParent().getType())); + } + } + return (chain.hasNext()) ? chain.next().resolve(type, context, chain) : null; + } + + private AnnotatedType resolvePagedModelType(AnnotatedType type) { + Type pageType = type.getType(); + if (pageType instanceof ParameterizedType) { + Type argumentType = ((ParameterizedType) type.getType()).getActualTypeArguments()[0]; + Type pagedModelType = ResolvableType + .forClassWithGenerics(PagedModel.class, ResolvableType.forType(argumentType)) + .getType(); + return new AnnotatedType(pagedModelType).resolveAsRef(true); + } + else { + return PAGED_MODEL; + } + } + +} \ No newline at end of file diff --git a/springdoc-openapi-starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/springdoc-openapi-starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 12694c003..ad61f1fa5 100644 --- a/springdoc-openapi-starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/springdoc-openapi-starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -7,6 +7,7 @@ org.springdoc.core.configuration.SpringDocFunctionCatalogConfiguration org.springdoc.core.configuration.SpringDocHateoasConfiguration org.springdoc.core.configuration.SpringDocPageableConfiguration org.springdoc.core.configuration.SpringDocSortConfiguration +org.springdoc.core.configuration.SpringDocPageConfiguration org.springdoc.core.configuration.SpringDocSpecPropertiesConfiguration org.springdoc.core.configuration.SpringDocDataRestConfiguration org.springdoc.core.configuration.SpringDocKotlinConfiguration diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/Dummy.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/Dummy.java new file mode 100644 index 000000000..761794ae2 --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/Dummy.java @@ -0,0 +1,34 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2024 the original author or authors. + * * * * + * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * you may not use this file except in compliance with the License. + * * * * You may obtain a copy of the License at + * * * * + * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * + * * * * Unless required by applicable law or agreed to in writing, software + * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * See the License for the specific language governing permissions and + * * * * limitations under the License. + * * * + * * + * + */ + +package test.org.springdoc.api.app10; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Dummy { + + private T value; + +} diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/HelloController.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/HelloController.java new file mode 100644 index 000000000..0597d1fd4 --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/HelloController.java @@ -0,0 +1,75 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2024 the original author or authors. + * * * * + * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * you may not use this file except in compliance with the License. + * * * * You may obtain a copy of the License at + * * * * + * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * + * * * * Unless required by applicable law or agreed to in writing, software + * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * See the License for the specific language governing permissions and + * * * * limitations under the License. + * * * + * * + * + */ + +package test.org.springdoc.api.app10; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.web.PagedModel; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@SuppressWarnings("rawtypes") +@RestController +public class HelloController { + + @GetMapping("/page-simple") + public Page pageSimple() { + return pageImpl("test"); + } + + @GetMapping("/paged-model-simple") + public PagedModel pagedModelSimple() { + return pagedModel("test"); + } + + @GetMapping("/page-complex") + public Page>> pageComplex() { + return pageImpl(new Dummy<>(List.of("test"))); + } + + @GetMapping("/paged-model-complex") + public PagedModel>> pagedModelComplex() { + return pagedModel(new Dummy<>(List.of("test"))); + } + + @GetMapping("/page-raw") + public Page pageRaw() { + return pageSimple(); + } + + @GetMapping("/paged-model-raw") + public PagedModel pagedModelRaw() { + return pagedModelSimple(); + } + + private PagedModel pagedModel(T value) { + return new PagedModel<>(pageImpl(value)); + } + + private Page pageImpl(T value) { + return new PageImpl<>(List.of(value)); + } + +} diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10DirectTest.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10DirectTest.java new file mode 100644 index 000000000..6ced6708d --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10DirectTest.java @@ -0,0 +1,53 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2024 the original author or authors. + * * * * + * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * you may not use this file except in compliance with the License. + * * * * You may obtain a copy of the License at + * * * * + * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * + * * * * Unless required by applicable law or agreed to in writing, software + * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * See the License for the specific language governing permissions and + * * * * limitations under the License. + * * * + * * + * + */ + +package test.org.springdoc.api.app10; + +import org.junit.jupiter.api.Test; +import org.springdoc.core.utils.Constants; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.web.config.EnableSpringDataWebSupport; +import test.org.springdoc.api.AbstractSpringDocTest; + +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +public class SpringDocApp10DirectTest extends AbstractSpringDocTest { + + @Override + @Test + public void testApp() throws Exception { + mockMvc.perform(get(Constants.DEFAULT_API_DOCS_URL)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.openapi", is("3.0.1"))) + .andExpect(content().json(getContent("results/app10-direct.json"), true)); + } + + @SpringBootApplication + @EnableSpringDataWebSupport(pageSerializationMode = EnableSpringDataWebSupport.PageSerializationMode.DIRECT) + public static class SpringDocTestApp { + + } + +} diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java new file mode 100644 index 000000000..c6f6856dd --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java @@ -0,0 +1,52 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2024 the original author or authors. + * * * * + * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * you may not use this file except in compliance with the License. + * * * * You may obtain a copy of the License at + * * * * + * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * + * * * * Unless required by applicable law or agreed to in writing, software + * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * See the License for the specific language governing permissions and + * * * * limitations under the License. + * * * + * * + * + */ + +package test.org.springdoc.api.app10; + +import org.junit.jupiter.api.Test; +import org.springdoc.core.utils.Constants; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.web.config.EnableSpringDataWebSupport; +import test.org.springdoc.api.AbstractSpringDocTest; + +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +public class SpringDocApp10NotSpecifiedTest extends AbstractSpringDocTest { + + @Override + @Test + public void testApp() throws Exception { + mockMvc.perform(get(Constants.DEFAULT_API_DOCS_URL)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.openapi", is("3.0.1"))) + .andExpect(content().json(getContent("results/app10-direct.json"), true)); + } + + @SpringBootApplication + public static class SpringDocTestApp { + + } + +} diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10ViaDtoTest.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10ViaDtoTest.java new file mode 100644 index 000000000..7d37e9f38 --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10ViaDtoTest.java @@ -0,0 +1,54 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2024 the original author or authors. + * * * * + * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * you may not use this file except in compliance with the License. + * * * * You may obtain a copy of the License at + * * * * + * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * + * * * * Unless required by applicable law or agreed to in writing, software + * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * See the License for the specific language governing permissions and + * * * * limitations under the License. + * * * + * * + * + */ + +package test.org.springdoc.api.app10; + +import org.junit.jupiter.api.Test; +import org.springdoc.core.utils.Constants; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.data.web.config.EnableSpringDataWebSupport; +import test.org.springdoc.api.AbstractSpringDocTest; + +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +public class SpringDocApp10ViaDtoTest extends AbstractSpringDocTest { + + @Override + @Test + public void testApp() throws Exception { + mockMvc.perform(get(Constants.DEFAULT_API_DOCS_URL)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.openapi", is("3.0.1"))) + .andExpect(content().json(getContent("results/app10-via_dto.json"), true)); + } + + @SpringBootApplication + @EnableSpringDataWebSupport(pageSerializationMode = EnableSpringDataWebSupport.PageSerializationMode.VIA_DTO) + public static class SpringDocTestApp { + + } + +} diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/app10-direct.json b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/app10-direct.json new file mode 100644 index 000000000..886b96496 --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/app10-direct.json @@ -0,0 +1,409 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/paged-model-simple": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pagedModelSimple", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PagedModelString" + } + } + } + } + } + } + }, + "/paged-model-raw": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pagedModelRaw", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PagedModel" + } + } + } + } + } + } + }, + "/paged-model-complex": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pagedModelComplex", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PagedModelDummyListString" + } + } + } + } + } + } + }, + "/page-simple": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pageSimple", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PageString" + } + } + } + } + } + } + }, + "/page-raw": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pageRaw", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Page" + } + } + } + } + } + } + }, + "/page-complex": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pageComplex", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PageDummyListString" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "PageMetadata": { + "type": "object", + "properties": { + "size": { + "type": "integer", + "format": "int64" + }, + "number": { + "type": "integer", + "format": "int64" + }, + "totalElements": { + "type": "integer", + "format": "int64" + }, + "totalPages": { + "type": "integer", + "format": "int64" + } + } + }, + "PagedModelString": { + "type": "object", + "properties": { + "content": { + "type": "array", + "items": { + "type": "string" + } + }, + "page": { + "$ref": "#/components/schemas/PageMetadata" + } + } + }, + "PagedModel": { + "type": "object", + "properties": { + "content": { + "type": "array", + "items": { + "type": "object" + } + }, + "page": { + "$ref": "#/components/schemas/PageMetadata" + } + } + }, + "DummyListString": { + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PagedModelDummyListString": { + "type": "object", + "properties": { + "content": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DummyListString" + } + }, + "page": { + "$ref": "#/components/schemas/PageMetadata" + } + } + }, + "PageString": { + "type": "object", + "properties": { + "totalPages": { + "type": "integer", + "format": "int32" + }, + "totalElements": { + "type": "integer", + "format": "int64" + }, + "pageable": { + "$ref": "#/components/schemas/PageableObject" + }, + "first": { + "type": "boolean" + }, + "last": { + "type": "boolean" + }, + "size": { + "type": "integer", + "format": "int32" + }, + "content": { + "type": "array", + "items": { + "type": "string" + } + }, + "number": { + "type": "integer", + "format": "int32" + }, + "sort": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortObject" + } + }, + "numberOfElements": { + "type": "integer", + "format": "int32" + }, + "empty": { + "type": "boolean" + } + } + }, + "PageableObject": { + "type": "object", + "properties": { + "paged": { + "type": "boolean" + }, + "pageNumber": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "offset": { + "type": "integer", + "format": "int64" + }, + "sort": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortObject" + } + }, + "unpaged": { + "type": "boolean" + } + } + }, + "SortObject": { + "type": "object", + "properties": { + "direction": { + "type": "string" + }, + "nullHandling": { + "type": "string" + }, + "ascending": { + "type": "boolean" + }, + "property": { + "type": "string" + }, + "ignoreCase": { + "type": "boolean" + } + } + }, + "Page": { + "type": "object", + "properties": { + "totalPages": { + "type": "integer", + "format": "int32" + }, + "totalElements": { + "type": "integer", + "format": "int64" + }, + "pageable": { + "$ref": "#/components/schemas/PageableObject" + }, + "first": { + "type": "boolean" + }, + "last": { + "type": "boolean" + }, + "size": { + "type": "integer", + "format": "int32" + }, + "content": { + "type": "array", + "items": { + "type": "object" + } + }, + "number": { + "type": "integer", + "format": "int32" + }, + "sort": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortObject" + } + }, + "numberOfElements": { + "type": "integer", + "format": "int32" + }, + "empty": { + "type": "boolean" + } + } + }, + "PageDummyListString": { + "type": "object", + "properties": { + "totalPages": { + "type": "integer", + "format": "int32" + }, + "totalElements": { + "type": "integer", + "format": "int64" + }, + "pageable": { + "$ref": "#/components/schemas/PageableObject" + }, + "first": { + "type": "boolean" + }, + "last": { + "type": "boolean" + }, + "size": { + "type": "integer", + "format": "int32" + }, + "content": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DummyListString" + } + }, + "number": { + "type": "integer", + "format": "int32" + }, + "sort": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortObject" + } + }, + "numberOfElements": { + "type": "integer", + "format": "int32" + }, + "empty": { + "type": "boolean" + } + } + } + } + } +} \ No newline at end of file diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/app10-via_dto.json b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/app10-via_dto.json new file mode 100644 index 000000000..32cad61c1 --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/app10-via_dto.json @@ -0,0 +1,213 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/paged-model-simple": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pagedModelSimple", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PagedModelString" + } + } + } + } + } + } + }, + "/paged-model-raw": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pagedModelRaw", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PagedModel" + } + } + } + } + } + } + }, + "/paged-model-complex": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pagedModelComplex", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PagedModelDummyListString" + } + } + } + } + } + } + }, + "/page-simple": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pageSimple", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PagedModelString" + } + } + } + } + } + } + }, + "/page-raw": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pageRaw", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PagedModel" + } + } + } + } + } + } + }, + "/page-complex": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "pageComplex", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/PagedModelDummyListString" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "PageMetadata": { + "type": "object", + "properties": { + "size": { + "type": "integer", + "format": "int64" + }, + "number": { + "type": "integer", + "format": "int64" + }, + "totalElements": { + "type": "integer", + "format": "int64" + }, + "totalPages": { + "type": "integer", + "format": "int64" + } + } + }, + "PagedModelString": { + "type": "object", + "properties": { + "content": { + "type": "array", + "items": { + "type": "string" + } + }, + "page": { + "$ref": "#/components/schemas/PageMetadata" + } + } + }, + "PagedModel": { + "type": "object", + "properties": { + "content": { + "type": "array", + "items": { + "type": "object" + } + }, + "page": { + "$ref": "#/components/schemas/PageMetadata" + } + } + }, + "DummyListString": { + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PagedModelDummyListString": { + "type": "object", + "properties": { + "content": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DummyListString" + } + }, + "page": { + "$ref": "#/components/schemas/PageMetadata" + } + } + } + } + } +} \ No newline at end of file From 9dda7a981c2bc2ce8433d564db11d7bec7405c27 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sat, 15 Jun 2024 17:46:27 +0200 Subject: [PATCH 13/33] Upgrade spring-boot to 3.3.0 Upgrade swagger-core to 2.2.22 Upgrade swagger-ui to 5.17.14 Upgrade spring-cloud-function to 4.1.2 Upgrade spring-security-oauth2-authorization-server to 1.3.0 --- pom.xml | 12 +- .../SpringDocSecurityOAuth2Customizer.java | 24 +- .../src/test/resources/logback-test.xml | 1 - .../test/resources/results/3.0.1/app38.json | 7 +- .../org/springdoc/api/AbstractCommonTest.java | 19 + .../api/AbstractSpringDocActuatorTest.java | 18 + .../springdoc/api/AbstractSpringDocTest.java | 31 +- .../api/app146/SpringDocApp146Test.java | 26 +- .../api/app147/SpringDocApp147Test.java | 21 +- .../api/app148/SpringDocApp148Test.java | 10 +- .../api/app186/SpringDocApp186Test.java | 6 +- .../api/app76/SpringDocApp76Test.java | 7 +- .../src/test/resources/logback-test.xml | 1 - .../src/test/resources/results/app146-1.json | 62 ++ .../src/test/resources/results/app147-1.json | 62 ++ .../src/test/resources/results/app147-2.json | 835 +++++++++++++++++- .../src/test/resources/results/app148-2.json | 62 ++ .../src/test/resources/results/app186.json | 62 ++ .../api/AbstractSpringDocActuatorTest.java | 20 + .../api/app148/SpringDocApp148Test.java | 9 +- .../resources/application-test.properties | 1 + .../src/test/resources/logback-test.xml | 3 +- .../src/test/resources/results/app147-1.json | 62 ++ .../src/test/resources/results/app148-2.json | 62 ++ .../src/test/resources/results/app186.json | 64 +- .../api/AbstractSpringDocFunctionTest.java | 6 +- .../src/test/resources/logback-test.xml | 1 - .../src/test/resources/results/app1.json | 628 +++++++------ .../src/test/resources/results/app38.json | 9 +- .../springdoc-openapi-security-tests/pom.xml | 10 - 30 files changed, 1676 insertions(+), 465 deletions(-) diff --git a/pom.xml b/pom.xml index 11339c18a..05ca7eee9 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.4 + 3.3.0 @@ -60,15 +60,13 @@ 1.6 2.5.3 1.6.8 - 2.2.21 - 5.13.0 + 2.2.22 + 5.17.14 1.13.1 - 2.1 - 1.1 0.9.1 0.15.0 - 4.0.0 - 1.0.1 + 4.1.2 + 1.3.0 diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityOAuth2Customizer.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityOAuth2Customizer.java index 871ebdbb6..b8cfd52f0 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityOAuth2Customizer.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityOAuth2Customizer.java @@ -55,6 +55,7 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.util.ReflectionUtils; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.http.MediaType.TEXT_HTML_VALUE; @@ -110,7 +111,7 @@ public void customise(OpenAPI openAPI) { * @param securityFilterChain the security filter chain * @param openapi31 the openapi 31 */ - private void getOAuth2TokenRevocationEndpointFilter(OpenAPI openAPI, SecurityFilterChain securityFilterChain, boolean openapi31) { + private void getOAuth2TokenRevocationEndpointFilter(OpenAPI openAPI, SecurityFilterChain securityFilterChain, boolean openapi31) { Object oAuth2EndpointFilter = new SpringDocSecurityOAuth2EndpointUtils(OAuth2TokenRevocationEndpointFilter.class).findEndpoint(securityFilterChain); if (oAuth2EndpointFilter != null) { @@ -168,14 +169,20 @@ private void getOAuth2TokenIntrospectionEndpointFilter(OpenAPI openAPI, Security * @param openapi31 the openapi 31 */ private void getOAuth2AuthorizationServerMetadataEndpoint(OpenAPI openAPI, SecurityFilterChain securityFilterChain, boolean openapi31) { + ClassauthorizationServerMetadataEndpointClass = OAuth2AuthorizationServerMetadataEndpointFilter.class; Object oAuth2EndpointFilter = - new SpringDocSecurityOAuth2EndpointUtils(OAuth2AuthorizationServerMetadataEndpointFilter.class).findEndpoint(securityFilterChain); + new SpringDocSecurityOAuth2EndpointUtils(authorizationServerMetadataEndpointClass).findEndpoint(securityFilterChain); if (oAuth2EndpointFilter != null) { ApiResponses apiResponses = new ApiResponses(); buildApiResponsesOnSuccess(apiResponses, AnnotationsUtils.resolveSchemaFromType(SpringDocOAuth2AuthorizationServerMetadata.class, openAPI.getComponents(), null, openapi31)); buildApiResponsesOnInternalServerError(apiResponses); Operation operation = buildOperation(apiResponses); - buildPath(oAuth2EndpointFilter, REQUEST_MATCHER, openAPI, operation, HttpMethod.GET); + Field field = ReflectionUtils.findField(authorizationServerMetadataEndpointClass, "DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI"); + if (field != null) { + ReflectionUtils.makeAccessible(field); + String defaultOauth2MetadataUri = (String) ReflectionUtils.getField(field, null); + openAPI.getPaths().addPathItem(defaultOauth2MetadataUri , new PathItem().get(operation)); + } } } @@ -288,15 +295,22 @@ private void getOAuth2AuthorizationEndpoint(OpenAPI openAPI, SecurityFilterChain * @param openapi31 the openapi 31 */ private void getOidcProviderConfigurationEndpoint(OpenAPI openAPI, SecurityFilterChain securityFilterChain, boolean openapi31) { + Class oidcProviderConfigurationEndpointFilterClass = OidcProviderConfigurationEndpointFilter.class; Object oAuth2EndpointFilter = - new SpringDocSecurityOAuth2EndpointUtils(OidcProviderConfigurationEndpointFilter.class).findEndpoint(securityFilterChain); + new SpringDocSecurityOAuth2EndpointUtils(oidcProviderConfigurationEndpointFilterClass).findEndpoint(securityFilterChain); if (oAuth2EndpointFilter != null) { ApiResponses apiResponses = new ApiResponses(); buildApiResponsesOnSuccess(apiResponses, AnnotationsUtils.resolveSchemaFromType(SpringDocOidcProviderConfiguration.class, openAPI.getComponents(), null, openapi31)); buildApiResponsesOnInternalServerError(apiResponses); Operation operation = buildOperation(apiResponses); - buildPath(oAuth2EndpointFilter, REQUEST_MATCHER, openAPI, operation, HttpMethod.GET); + + Field field = ReflectionUtils.findField(oidcProviderConfigurationEndpointFilterClass, "DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI"); + if (field != null) { + ReflectionUtils.makeAccessible(field); + String defaultOidcConfigUri = (String) ReflectionUtils.getField(field, null); + openAPI.getPaths().addPathItem(defaultOidcConfigUri , new PathItem().get(operation)); + } } } diff --git a/springdoc-openapi-starter-webflux-api/src/test/resources/logback-test.xml b/springdoc-openapi-starter-webflux-api/src/test/resources/logback-test.xml index 24cd4646e..3fd46cfab 100644 --- a/springdoc-openapi-starter-webflux-api/src/test/resources/logback-test.xml +++ b/springdoc-openapi-starter-webflux-api/src/test/resources/logback-test.xml @@ -1,6 +1,5 @@ - \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app38.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app38.json index e28206a0b..0de67a730 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app38.json +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app38.json @@ -23,11 +23,8 @@ "content": { "*/*": { "schema": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } + "type": "string", + "format": "byte" } } } diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractCommonTest.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractCommonTest.java index 17446b334..14e357531 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractCommonTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractCommonTest.java @@ -7,13 +7,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springdoc.core.utils.Constants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.TestPropertySource; +import org.springframework.test.web.reactive.server.EntityExchangeResult; import org.springframework.test.web.reactive.server.WebTestClient; +import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; + @AutoConfigureWebTestClient(timeout = "3600000") @ActiveProfiles("test") @TestPropertySource(properties = { "management.endpoints.enabled-by-default=false" }) @@ -34,4 +38,19 @@ protected String getContent(String fileName) { throw new RuntimeException("Failed to read file: " + fileName, e); } } + + protected void testApp(String testId, String groupName) throws Exception{ + String result = null; + try { + EntityExchangeResult getResult = webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/" + groupName).exchange() + .expectStatus().isOk().expectBody().returnResult(); + result = new String(getResult.getResponseBody()); + String expected = getContent("results/app" + testId + ".json"); + assertEquals(expected, result, true); + } + catch (AssertionError e) { + LOGGER.error(result); + throw e; + } + } } diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java index b2a483d38..029d5ff0c 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java @@ -25,11 +25,15 @@ package test.org.springdoc.api; import jakarta.annotation.PostConstruct; +import org.springdoc.core.utils.Constants; import org.springframework.boot.test.web.server.LocalManagementPort; import org.springframework.test.context.TestPropertySource; +import org.springframework.test.web.reactive.server.EntityExchangeResult; import org.springframework.web.reactive.function.client.WebClient; +import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; + @TestPropertySource(properties = { "management.endpoints.enabled-by-default=true" }) public abstract class AbstractSpringDocActuatorTest extends AbstractCommonTest { @@ -43,4 +47,18 @@ void init() { webClient = WebClient.builder().baseUrl("http://localhost:" + this.managementPort) .build(); } + + protected void testWithWebClient(String testId, String uri) throws Exception{ + String result = null; + try { + result = webClient.get().uri(uri).retrieve() + .bodyToMono(String.class).block(); + String expected = getContent("results/app"+testId+".json"); + assertEquals(expected, result, true); + } + catch (AssertionError e) { + LOGGER.error(result); + throw e; + } + } } diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocTest.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocTest.java index 4b1df181d..b93e551df 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocTest.java @@ -18,41 +18,20 @@ package test.org.springdoc.api; +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; -import org.springdoc.core.utils.Constants; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; -import org.springframework.test.web.reactive.server.EntityExchangeResult; -import org.springframework.web.reactive.function.server.HandlerFunction; -import org.springframework.web.reactive.function.server.ServerResponse; - -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; @WebFluxTest public abstract class AbstractSpringDocTest extends AbstractCommonTest { - public static final HandlerFunction HANDLER_FUNCTION = request -> ServerResponse.ok().build(); - - protected String groupName = ""; - - @Test public void testApp() throws Exception { - String result = null; - try { - EntityExchangeResult getResult = webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + groupName).exchange() - .expectStatus().isOk().expectBody().returnResult(); - - result = new String(getResult.getResponseBody()); - String className = getClass().getSimpleName(); - String testNumber = className.replaceAll("[^0-9]", ""); - String expected = getContent("results/app" + testNumber + ".json"); - assertEquals(expected, result, true); - } - catch (AssertionError e) { - LOGGER.error(result); - throw e; - } + String className = getClass().getSimpleName(); + String testId = className.replaceAll("[^0-9]", ""); + testApp(testId, StringUtils.EMPTY); } + } diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app146/SpringDocApp146Test.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app146/SpringDocApp146Test.java index 42a72b1d5..53a87de9f 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app146/SpringDocApp146Test.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app146/SpringDocApp146Test.java @@ -24,10 +24,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.web.reactive.server.EntityExchangeResult; - -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; - +import org.springframework.context.annotation.ComponentScan; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "management.endpoints.web.exposure.include=*", @@ -40,31 +37,16 @@ public class SpringDocApp146Test extends AbstractSpringDocActuatorTest { @Test public void testApp() throws Exception { - EntityExchangeResult getResult = webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/" + Constants.ACTUATOR_DEFAULT_GROUP) - .exchange() - .expectStatus().isOk() - .expectBody() - .jsonPath("$.openapi").isEqualTo("3.0.1") - .returnResult(); - String result = new String(getResult.getResponseBody()); - String expected = getContent("results/app146-1.json"); - assertEquals(expected, result, true); + super.testApp("146-1", Constants.ACTUATOR_DEFAULT_GROUP); } @Test public void testApp1() throws Exception { - EntityExchangeResult getResult = webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/" + Constants.DEFAULT_GROUP_NAME) - .exchange() - .expectStatus().isOk() - .expectBody() - .jsonPath("$.openapi").isEqualTo("3.0.1") - .returnResult(); - String result = new String(getResult.getResponseBody()); - String expected = getContent("results/app146-2.json"); - assertEquals(expected, result, true); + super.testApp("146-2", Constants.DEFAULT_GROUP_NAME); } @SpringBootApplication + @ComponentScan(basePackages = { "org.springdoc", "test.org.springdoc.api.app146" }) static class SpringDocTestApp {} } diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java index 065edeb43..a41644858 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java @@ -40,28 +40,13 @@ public class SpringDocApp147Test extends AbstractSpringDocActuatorTest { @Test public void testApp() throws Exception { - EntityExchangeResult getResult = webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/" + Constants.ACTUATOR_DEFAULT_GROUP) - .exchange() - .expectStatus().isOk() - .expectBody() - .jsonPath("$.openapi").isEqualTo("3.0.1") - .returnResult(); - String result = new String(getResult.getResponseBody()); - String expected = getContent("results/app147-1.json"); - assertEquals(expected, result, true); + super.testApp("147-1", Constants.ACTUATOR_DEFAULT_GROUP); } @Test public void testApp1() throws Exception { - EntityExchangeResult getResult = webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/users") - .exchange() - .expectStatus().isOk() - .expectBody() - .jsonPath("$.openapi").isEqualTo("3.0.1") - .returnResult(); - String result = new String(getResult.getResponseBody()); - String expected = getContent("results/app147-2.json"); - assertEquals(expected, result, true); + super.testApp("147-2", Constants.ACTUATOR_DEFAULT_GROUP); + } @Test diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java index d761b9d25..851b43460 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java @@ -46,18 +46,12 @@ public class SpringDocApp148Test extends AbstractSpringDocActuatorTest { @Test public void testApp() throws Exception { - String result = webClient.get().uri("/test/application/openapi/users").retrieve() - .bodyToMono(String.class).block(); - String expected = getContent("results/app148-1.json"); - assertEquals(expected, result, true); + super.testWithWebClient("148-1","/test/application/openapi/users"); } @Test public void testApp2() throws Exception { - String result = webClient.get().uri("/test/application/openapi/x-actuator").retrieve() - .bodyToMono(String.class).block(); - String expected = getContent("results/app148-2.json"); - assertEquals(expected, result, true); + super.testWithWebClient("148-2","/test/application/openapi/x-actuator"); } @Test diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app186/SpringDocApp186Test.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app186/SpringDocApp186Test.java index 989f9be43..85e94408e 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app186/SpringDocApp186Test.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app186/SpringDocApp186Test.java @@ -59,21 +59,21 @@ public void testApp() throws Exception { } @Test - public void testGroupActuatorAsCodeCheckBackwardsCompatibility() throws Exception { + public void testGroupActuatorAsCodeCheckBackwardsCompatibility() { webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/group-actuator-as-code-check-backwards-compatibility").exchange() .expectStatus().isOk() .expectBody().json(getContent("results/app186.json"), true); } @Test - public void testGroupActuatorAsCode() throws Exception { + public void testGroupActuatorAsCode() { webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/group-actuator-as-code").exchange() .expectStatus().isOk() .expectBody().json(getContent("results/app186.json"), true); } @Test - public void testGroupActuatorAsProperties() throws Exception { + public void testGroupActuatorAsProperties() { webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/group-actuator-as-properties").exchange() .expectStatus().isOk() .expectBody().json(getContent("results/app186.json"), true); diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app76/SpringDocApp76Test.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app76/SpringDocApp76Test.java index b0f4c1508..9f877e497 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app76/SpringDocApp76Test.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app76/SpringDocApp76Test.java @@ -35,14 +35,9 @@ }) public class SpringDocApp76Test extends AbstractSpringDocTest { - public SpringDocApp76Test() { - this.groupName = "/actuator"; - } - - @Test public void testApp() throws Exception { - webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + groupName).exchange().expectStatus().isOk().expectBody() + webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/actuator").exchange().expectStatus().isOk().expectBody() .jsonPath("$.openapi").isEqualTo("3.0.1") .jsonPath("$.paths./actuator/health.get.operationId").exists(); } diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/logback-test.xml b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/logback-test.xml index 24cd4646e..3fd46cfab 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/logback-test.xml +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/logback-test.xml @@ -1,6 +1,5 @@ - \ No newline at end of file diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app146-1.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app146-1.json index 4d21f4405..3b190e590 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app146-1.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app146-1.json @@ -176,6 +176,68 @@ } } }, + "/application/sbom/{id}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom-id'", + "operationId": "sbom-id", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/sbom": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom'", + "operationId": "sbom", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, "/application/metrics/{requiredMetricName}": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-1.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-1.json index cbcf7fd50..ebc856a6f 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-1.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-1.json @@ -176,6 +176,68 @@ } } }, + "/application/sbom/{id}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom-id'", + "operationId": "sbom-id", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/sbom": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom'", + "operationId": "sbom", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, "/application/metrics/{requiredMetricName}": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-2.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-2.json index e7c346c11..ebc856a6f 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-2.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-2.json @@ -6,24 +6,833 @@ }, "servers": [ { - "url": "", + "url": "http://localhost:9297/test", "description": "Generated server url" } ], + "tags": [ + { + "name": "Actuator", + "description": "Monitor and interact", + "externalDocs": { + "description": "Spring Boot Actuator Web API Documentation", + "url": "https://docs.spring.io/spring-boot/docs/current/actuator-api/html/" + } + } + ], "paths": { - "/persons": { + "/application/loggers/{name}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'loggers-name'", + "operationId": "loggers-name", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + }, + "post": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'loggers-name'", + "operationId": "loggers-name_2", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "string", + "enum": [ + "TRACE", + "DEBUG", + "INFO", + "WARN", + "ERROR", + "FATAL", + "OFF" + ] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/threaddump": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'threaddump'", + "operationId": "threaddump", + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain;charset=UTF-8": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/scheduledtasks": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'scheduledtasks'", + "operationId": "scheduledtasks", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/sbom/{id}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom-id'", + "operationId": "sbom-id", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/sbom": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom'", + "operationId": "sbom", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/metrics/{requiredMetricName}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'metrics-requiredMetricName'", + "operationId": "metrics-requiredMetricName", + "parameters": [ + { + "name": "requiredMetricName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/metrics": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'metrics'", + "operationId": "metrics", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/mappings": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'mappings'", + "operationId": "mappings", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/loggers": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'loggers'", + "operationId": "loggers", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/info": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'info'", + "operationId": "info", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/heapdump": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'heapdump'", + "operationId": "heapdump", + "responses": { + "200": { + "description": "OK", + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/health": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'health'", + "operationId": "health", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/env/{toMatch}": { "get": { "tags": [ - "hello-controller" + "Actuator" + ], + "summary": "Actuator web endpoint 'env-toMatch'", + "operationId": "env-toMatch", + "parameters": [ + { + "name": "toMatch", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } ], - "operationId": "persons", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/env": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'env'", + "operationId": "env", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/configprops/{prefix}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'configprops-prefix'", + "operationId": "configprops-prefix", + "parameters": [ + { + "name": "prefix", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/configprops": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'configprops'", + "operationId": "configprops", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/conditions": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'conditions'", + "operationId": "conditions", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/caches/{cache}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'caches-cache'", + "operationId": "caches-cache", + "parameters": [ + { + "name": "cache", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'caches-cache'", + "operationId": "caches-cache_2", + "parameters": [ + { + "name": "cache", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/caches": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'caches'", + "operationId": "caches", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'caches'", + "operationId": "caches_2", "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "type": "string" + "type": "object" + } + } + } + } + } + } + }, + "/application/beans": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'beans'", + "operationId": "beans", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator root web endpoint", + "operationId": "links", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Link" + } + } + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Link" + } + } + } + }, + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Link" + } + } } } } @@ -32,5 +841,19 @@ } } }, - "components": {} + "components": { + "schemas": { + "Link": { + "type": "object", + "properties": { + "href": { + "type": "string" + }, + "templated": { + "type": "boolean" + } + } + } + } + } } diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app148-2.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app148-2.json index 837455a90..ea44fd1c0 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app148-2.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app148-2.json @@ -176,6 +176,68 @@ } } }, + "/application/sbom/{id}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom-id'", + "operationId": "sbom-id", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/sbom": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom'", + "operationId": "sbom", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, "/application/metrics/{requiredMetricName}": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app186.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app186.json index 6f5111c7a..3c91143c4 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app186.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app186.json @@ -176,6 +176,68 @@ } } }, + "/actuator/sbom/{id}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom-id'", + "operationId": "sbom-id", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/sbom": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom'", + "operationId": "sbom", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, "/actuator/metrics/{requiredMetricName}": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java index d76fc9525..4173589c8 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java @@ -25,6 +25,8 @@ package test.org.springdoc.api; import jakarta.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.web.server.LocalManagementPort; @@ -32,9 +34,13 @@ import org.springframework.test.context.TestPropertySource; import org.springframework.web.client.RestTemplate; +import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; + @TestPropertySource(properties = { "management.endpoints.enabled-by-default=true" }) public abstract class AbstractSpringDocActuatorTest extends AbstractCommonTest { + protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractCommonTest.class); + protected RestTemplate actuatorRestTemplate; @LocalManagementPort @@ -48,4 +54,18 @@ void init() { actuatorRestTemplate = restTemplateBuilder .rootUri("http://localhost:" + this.managementPort).build(); } + + protected void testWithRestTemplate(String testId, String uri) throws Exception { + String result = null; + try { + result = actuatorRestTemplate.getForObject(uri, String.class); + String expected = getContent("results/app" + testId + ".json"); + assertEquals(expected, result, true); + } + catch (AssertionError e) { + LOGGER.error(result); + throw e; + } + } + } diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java index 41241a573..3d9c4a593 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java @@ -30,7 +30,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, @@ -48,16 +47,12 @@ public class SpringDocApp148Test extends AbstractSpringDocActuatorTest { @Test public void testApp() throws Exception { - String result = actuatorRestTemplate.getForObject("/test/application/openapi/users", String.class); - String expected = getContent("results/app148-1.json"); - assertEquals(expected, result, true); + super.testWithRestTemplate("148-1","/test/application/openapi/users"); } @Test public void testApp2() throws Exception { - String result = actuatorRestTemplate.getForObject("/test/application/openapi/x-actuator", String.class); - String expected = getContent("results/app148-2.json"); - assertEquals(expected, result, true); + super.testWithRestTemplate("148-2","/test/application/openapi/x-actuator"); } @Test diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/application-test.properties b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/application-test.properties index b88c99251..9d2df2929 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/application-test.properties +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/application-test.properties @@ -1,3 +1,4 @@ spring.main.banner-mode=off logging.level.root=OFF +logging.pattern.console=%m%n spring.main.lazy-initialization=true \ No newline at end of file diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/logback-test.xml b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/logback-test.xml index 608cb302d..3fd46cfab 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/logback-test.xml +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/logback-test.xml @@ -1,4 +1,5 @@ - + + \ No newline at end of file diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app147-1.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app147-1.json index 601c304ca..4df57e3ca 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app147-1.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app147-1.json @@ -225,6 +225,68 @@ } } }, + "/application/sbom": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom'", + "operationId": "sbom", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/sbom/{id}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom-id'", + "operationId": "sbom-id", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, "/application/metrics": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app148-2.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app148-2.json index 1d726c0ba..7b6724300 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app148-2.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app148-2.json @@ -225,6 +225,68 @@ } } }, + "/application/sbom": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom'", + "operationId": "sbom", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/application/sbom/{id}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom-id'", + "operationId": "sbom-id", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, "/application/metrics": { "get": { "tags": [ diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app186.json b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app186.json index c136df41f..b8faa137b 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app186.json +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app186.json @@ -225,6 +225,68 @@ } } }, + "/actuator/sbom": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom'", + "operationId": "sbom", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/sbom/{id}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom-id'", + "operationId": "sbom-id", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, "/actuator/metrics": { "get": { "tags": [ @@ -825,4 +887,4 @@ } } } -} \ No newline at end of file +} diff --git a/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocFunctionTest.java b/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocFunctionTest.java index 9b5b08e9e..78e2db9f8 100644 --- a/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocFunctionTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocFunctionTest.java @@ -24,8 +24,6 @@ import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; import org.springframework.cloud.function.context.test.FunctionalSpringBootTest; import org.springframework.test.web.reactive.server.EntityExchangeResult; -import org.springframework.web.reactive.function.server.HandlerFunction; -import org.springframework.web.reactive.function.server.ServerResponse; import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; @@ -34,13 +32,11 @@ @AutoConfigureWebTestClient(timeout = "3600000") public abstract class AbstractSpringDocFunctionTest extends AbstractCommonTest { - public static final HandlerFunction HANDLER_FUNCTION = request -> ServerResponse.ok().build(); - protected String groupName = ""; @Test - public void testApp() throws Exception { + public void testApp() { String result = null; try { EntityExchangeResult getResult = webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + groupName).exchange() diff --git a/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/src/test/resources/logback-test.xml b/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/src/test/resources/logback-test.xml index 24cd4646e..3fd46cfab 100644 --- a/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/src/test/resources/logback-test.xml +++ b/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/src/test/resources/logback-test.xml @@ -1,6 +1,5 @@ - \ No newline at end of file diff --git a/springdoc-openapi-tests/springdoc-openapi-groovy-tests/src/test/resources/results/app1.json b/springdoc-openapi-tests/springdoc-openapi-groovy-tests/src/test/resources/results/app1.json index 802d051cf..a7376fb6b 100644 --- a/springdoc-openapi-tests/springdoc-openapi-groovy-tests/src/test/resources/results/app1.json +++ b/springdoc-openapi-tests/springdoc-openapi-groovy-tests/src/test/resources/results/app1.json @@ -151,13 +151,13 @@ "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "text": { "type": "string" }, @@ -424,8 +424,9 @@ "void": { "type": "boolean" }, - "typeDescription": { - "type": "string" + "superClassDistance": { + "type": "integer", + "format": "int32" }, "newMetaMethods": { "type": "array", @@ -436,9 +437,8 @@ "callSiteLoader": { "$ref": "#/components/schemas/CallSiteClassLoader" }, - "superClassDistance": { - "type": "integer", - "format": "int32" + "typeDescription": { + "type": "string" } } }, @@ -460,20 +460,6 @@ "items": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "bounds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "typeName": { - "type": "string" - } - } - } - }, "genericDeclaration": { "type": "object", "properties": { @@ -694,20 +680,6 @@ "items": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "bounds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "typeName": { - "type": "string" - } - } - } - }, "genericDeclaration": { "type": "object" }, @@ -739,6 +711,20 @@ } } }, + "name": { + "type": "string" + }, + "bounds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "typeName": { + "type": "string" + } + } + } + }, "typeName": { "type": "string" }, @@ -992,6 +978,20 @@ } } }, + "name": { + "type": "string" + }, + "bounds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "typeName": { + "type": "string" + } + } + } + }, "typeName": { "type": "string" }, @@ -1220,20 +1220,6 @@ "items": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "bounds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "typeName": { - "type": "string" - } - } - } - }, "genericDeclaration": { "type": "object" }, @@ -1265,6 +1251,20 @@ } } }, + "name": { + "type": "string" + }, + "bounds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "typeName": { + "type": "string" + } + } + } + }, "typeName": { "type": "string" }, @@ -1614,20 +1614,6 @@ "items": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "bounds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "typeName": { - "type": "string" - } - } - } - }, "annotatedBounds": { "type": "array", "items": { @@ -1656,6 +1642,20 @@ } } }, + "name": { + "type": "string" + }, + "bounds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "typeName": { + "type": "string" + } + } + } + }, "typeName": { "type": "string" }, @@ -1876,20 +1876,6 @@ "items": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "bounds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "typeName": { - "type": "string" - } - } - } - }, "genericDeclaration": { "type": "object" }, @@ -1921,6 +1907,20 @@ } } }, + "name": { + "type": "string" + }, + "bounds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "typeName": { + "type": "string" + } + } + } + }, "typeName": { "type": "string" }, @@ -3114,21 +3114,34 @@ "text": { "type": "string" }, - "outerClass": { - "$ref": "#/components/schemas/ClassNode" + "allDeclaredMethods": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MethodNode" + } }, - "genericsPlaceHolder": { - "type": "boolean" + "allInterfaces": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/ClassNode" + } }, - "unresolvedSuperClass": { - "$ref": "#/components/schemas/ClassNode" + "abstractMethods": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MethodNode" + } }, - "plainNodeReference": { + "outerClass": { "$ref": "#/components/schemas/ClassNode" }, "redirectNode": { "type": "boolean" }, + "genericsPlaceHolder": { + "type": "boolean" + }, "primaryClassNode": { "type": "boolean" }, @@ -3150,6 +3163,9 @@ "derivedFromGroovyObject": { "type": "boolean" }, + "unresolvedSuperClass": { + "$ref": "#/components/schemas/ClassNode" + }, "unresolvedInterfaces": { "type": "array", "items": { @@ -3169,24 +3185,8 @@ "annotationDefinition": { "type": "boolean" }, - "abstractMethods": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MethodNode" - } - }, - "allInterfaces": { - "uniqueItems": true, - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassNode" - } - }, - "allDeclaredMethods": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MethodNode" - } + "plainNodeReference": { + "$ref": "#/components/schemas/ClassNode" }, "objectInitializerStatements": { "type": "array", @@ -3197,13 +3197,13 @@ "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "sourcePosition": { "$ref": "#/components/schemas/ASTNode" }, @@ -3256,21 +3256,15 @@ "type": "string" }, "encoded": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } + "type": "string", + "format": "byte" }, "publicKey": { "type": "object", "properties": { "encoded": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } + "type": "string", + "format": "byte" }, "format": { "type": "string" @@ -3291,6 +3285,12 @@ "signerCertPath": { "type": "object", "properties": { + "type": { + "type": "string" + }, + "encodings": { + "type": "object" + }, "certificates": { "type": "array", "items": { @@ -3300,21 +3300,15 @@ "type": "string" }, "encoded": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } + "type": "string", + "format": "byte" }, "publicKey": { "type": "object", "properties": { "encoded": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } + "type": "string", + "format": "byte" }, "format": { "type": "string" @@ -3327,18 +3321,9 @@ } } }, - "type": { - "type": "string" - }, "encoded": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } - }, - "encodings": { - "type": "object" + "type": "string", + "format": "byte" } } }, @@ -3352,6 +3337,12 @@ "signerCertPath": { "type": "object", "properties": { + "type": { + "type": "string" + }, + "encodings": { + "type": "object" + }, "certificates": { "type": "array", "items": { @@ -3361,21 +3352,15 @@ "type": "string" }, "encoded": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } + "type": "string", + "format": "byte" }, "publicKey": { "type": "object", "properties": { "encoded": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } + "type": "string", + "format": "byte" }, "format": { "type": "string" @@ -3388,18 +3373,9 @@ } } }, - "type": { - "type": "string" - }, "encoded": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } - }, - "encodings": { - "type": "object" + "type": "string", + "format": "byte" } } } @@ -3689,10 +3665,6 @@ "text": { "type": "string" }, - "annotationDefault": { - "type": "boolean", - "writeOnly": true - }, "voidMethod": { "type": "boolean" }, @@ -3708,16 +3680,20 @@ "staticConstructor": { "type": "boolean" }, + "annotationDefault": { + "type": "boolean", + "writeOnly": true + }, "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "sourcePosition": { "$ref": "#/components/schemas/ASTNode" }, @@ -3747,16 +3723,16 @@ "configuration": { "$ref": "#/components/schemas/CompilerConfiguration" }, + "errorCount": { + "type": "integer", + "format": "int32" + }, "warningCount": { "type": "integer", "format": "int32" }, "lastError": { "$ref": "#/components/schemas/Message" - }, - "errorCount": { - "type": "integer", - "format": "int32" } } }, @@ -3816,6 +3792,9 @@ "type": "integer", "format": "int32" }, + "classInfo": { + "$ref": "#/components/schemas/ClassInfo" + }, "groovyObject": { "type": "boolean" }, @@ -3864,20 +3843,6 @@ "items": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "bounds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "typeName": { - "type": "string" - } - } - } - }, "annotatedBounds": { "type": "array", "items": { @@ -3906,6 +3871,20 @@ } } }, + "name": { + "type": "string" + }, + "bounds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "typeName": { + "type": "string" + } + } + } + }, "typeName": { "type": "string" }, @@ -4126,20 +4105,6 @@ "items": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "bounds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "typeName": { - "type": "string" - } - } - } - }, "genericDeclaration": { "type": "object" }, @@ -4171,6 +4136,20 @@ } } }, + "name": { + "type": "string" + }, + "bounds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "typeName": { + "type": "string" + } + } + } + }, "typeName": { "type": "string" }, @@ -4436,20 +4415,6 @@ "items": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "bounds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "typeName": { - "type": "string" - } - } - } - }, "annotatedBounds": { "type": "array", "items": { @@ -4478,6 +4443,20 @@ } } }, + "name": { + "type": "string" + }, + "bounds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "typeName": { + "type": "string" + } + } + } + }, "typeName": { "type": "string" }, @@ -4698,20 +4677,6 @@ "items": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "bounds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "typeName": { - "type": "string" - } - } - } - }, "genericDeclaration": { "type": "object" }, @@ -4743,6 +4708,20 @@ } } }, + "name": { + "type": "string" + }, + "bounds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "typeName": { + "type": "string" + } + } + } + }, "typeName": { "type": "string" }, @@ -4995,9 +4974,6 @@ } } } - }, - "classInfo": { - "$ref": "#/components/schemas/ClassInfo" } } }, @@ -5038,13 +5014,13 @@ "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "text": { "type": "string" }, @@ -5155,13 +5131,13 @@ "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "text": { "type": "string" }, @@ -5688,13 +5664,13 @@ "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "sourcePosition": { "$ref": "#/components/schemas/ASTNode" }, @@ -5891,18 +5867,31 @@ "text": { "type": "string" }, - "genericsPlaceHolder": { - "type": "boolean" + "allDeclaredMethods": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MethodNode" + } }, - "unresolvedSuperClass": { - "$ref": "#/components/schemas/ClassNode" + "allInterfaces": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/ClassNode" + } }, - "plainNodeReference": { - "$ref": "#/components/schemas/ClassNode" + "abstractMethods": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MethodNode" + } }, "redirectNode": { "type": "boolean" }, + "genericsPlaceHolder": { + "type": "boolean" + }, "primaryClassNode": { "type": "boolean" }, @@ -5924,6 +5913,9 @@ "derivedFromGroovyObject": { "type": "boolean" }, + "unresolvedSuperClass": { + "$ref": "#/components/schemas/ClassNode" + }, "unresolvedInterfaces": { "type": "array", "items": { @@ -5943,24 +5935,8 @@ "annotationDefinition": { "type": "boolean" }, - "abstractMethods": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MethodNode" - } - }, - "allInterfaces": { - "uniqueItems": true, - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassNode" - } - }, - "allDeclaredMethods": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MethodNode" - } + "plainNodeReference": { + "$ref": "#/components/schemas/ClassNode" }, "objectInitializerStatements": { "type": "array", @@ -5971,13 +5947,13 @@ "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "sourcePosition": { "$ref": "#/components/schemas/ASTNode" }, @@ -6226,10 +6202,6 @@ "text": { "type": "string" }, - "annotationDefault": { - "type": "boolean", - "writeOnly": true - }, "voidMethod": { "type": "boolean" }, @@ -6245,16 +6217,20 @@ "staticConstructor": { "type": "boolean" }, + "annotationDefault": { + "type": "boolean", + "writeOnly": true + }, "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "sourcePosition": { "$ref": "#/components/schemas/ASTNode" }, @@ -6439,21 +6415,34 @@ "text": { "type": "string" }, - "outerClass": { - "$ref": "#/components/schemas/ClassNode" + "allDeclaredMethods": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MethodNode" + } }, - "genericsPlaceHolder": { - "type": "boolean" + "allInterfaces": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/ClassNode" + } }, - "unresolvedSuperClass": { - "$ref": "#/components/schemas/ClassNode" + "abstractMethods": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MethodNode" + } }, - "plainNodeReference": { + "outerClass": { "$ref": "#/components/schemas/ClassNode" }, "redirectNode": { "type": "boolean" }, + "genericsPlaceHolder": { + "type": "boolean" + }, "primaryClassNode": { "type": "boolean" }, @@ -6475,6 +6464,9 @@ "derivedFromGroovyObject": { "type": "boolean" }, + "unresolvedSuperClass": { + "$ref": "#/components/schemas/ClassNode" + }, "unresolvedInterfaces": { "type": "array", "items": { @@ -6494,24 +6486,8 @@ "annotationDefinition": { "type": "boolean" }, - "abstractMethods": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MethodNode" - } - }, - "allInterfaces": { - "uniqueItems": true, - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassNode" - } - }, - "allDeclaredMethods": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MethodNode" - } + "plainNodeReference": { + "$ref": "#/components/schemas/ClassNode" }, "objectInitializerStatements": { "type": "array", @@ -6522,13 +6498,13 @@ "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "sourcePosition": { "$ref": "#/components/schemas/ASTNode" }, @@ -6617,12 +6593,12 @@ "statementBlock": { "$ref": "#/components/schemas/BlockStatement" }, - "empty": { - "type": "boolean" - }, "packageName": { "type": "string" }, + "empty": { + "type": "boolean" + }, "package": { "$ref": "#/components/schemas/PackageNode" }, @@ -6695,13 +6671,13 @@ "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "sourcePosition": { "$ref": "#/components/schemas/ASTNode" }, @@ -6781,13 +6757,13 @@ "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "text": { "type": "string" }, @@ -6869,6 +6845,9 @@ "type": "integer", "format": "int32" }, + "type": { + "$ref": "#/components/schemas/ClassNode" + }, "name": { "type": "string" }, @@ -6878,15 +6857,9 @@ "public": { "type": "boolean" }, - "type": { - "$ref": "#/components/schemas/ClassNode" - }, "private": { "type": "boolean" }, - "dynamicTyped": { - "type": "boolean" - }, "initialExpression": { "$ref": "#/components/schemas/Expression" }, @@ -6900,6 +6873,9 @@ "originType": { "$ref": "#/components/schemas/ClassNode" }, + "dynamicTyped": { + "type": "boolean" + }, "getterNameOrDefault": { "type": "string" }, @@ -6909,13 +6885,13 @@ "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "text": { "type": "string" }, @@ -6933,12 +6909,12 @@ "ReaderSource": { "type": "object", "properties": { - "reader": { - "type": "object" - }, "uri": { "type": "string", "format": "uri" + }, + "reader": { + "type": "object" } } }, @@ -6988,13 +6964,13 @@ "instance": { "$ref": "#/components/schemas/AnnotatedNode" }, + "groovydoc": { + "$ref": "#/components/schemas/Groovydoc" + }, "hasNoRealSourcePosition": { "type": "boolean", "writeOnly": true }, - "groovydoc": { - "$ref": "#/components/schemas/Groovydoc" - }, "text": { "type": "string" }, @@ -7185,9 +7161,6 @@ "type": { "$ref": "#/components/schemas/ClassNode" }, - "dynamicTyped": { - "type": "boolean" - }, "initialExpression": { "$ref": "#/components/schemas/Expression" }, @@ -7199,6 +7172,9 @@ }, "originType": { "$ref": "#/components/schemas/ClassNode" + }, + "dynamicTyped": { + "type": "boolean" } } }, diff --git a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app38.json b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app38.json index b6127e78c..d1e0f9d27 100644 --- a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app38.json +++ b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app38.json @@ -31,11 +31,8 @@ "content": { "*/*": { "schema": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } + "type": "string", + "format": "byte" } } } @@ -45,4 +42,4 @@ } }, "components": {} -} \ No newline at end of file +} diff --git a/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml index 2b8da2454..2779092bd 100644 --- a/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml @@ -31,16 +31,6 @@ ${project.version} test - - javax.xml - jaxb-impl - test - - - javax.jws - javax.jws-api - test - io.jsonwebtoken jjwt From 479fbb716c7c9b843099eab41255cd3d764f51e7 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sat, 15 Jun 2024 18:37:17 +0200 Subject: [PATCH 14/33] "application/json; charset=UTF-8" Skipped in Generated OpenAPI JSON, Fixes #2596 --- .../test/resources/results/3.0.1/app219.json | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app219.json diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app219.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app219.json new file mode 100644 index 000000000..70b2fb8d5 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app219.json @@ -0,0 +1,76 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/api/testpost": { + "post": { + "tags": [ + "hello-controller" + ], + "operationId": "testpost", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestObject" + } + }, + "application/json;charset=UTF-8": { + "schema": { + "$ref": "#/components/schemas/TestObject" + } + }, + "application/json; charset=UTF-8": { + "schema": { + "$ref": "#/components/schemas/TestObject" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/TestObject" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestObject" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "TestObject": { + "type": "object", + "properties": { + "stringValue": { + "type": "string" + }, + "localDateTime": { + "type": "string", + "format": "date-time" + } + } + } + } + } +} From cedee7bd99bec5aa7734dc359471aeb917fb6861 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sat, 15 Jun 2024 19:00:17 +0200 Subject: [PATCH 15/33] Code review. Fixes #2625 --- .../SpringDocPageConfiguration.java | 96 ------------------- .../SpringDocPageableConfiguration.java | 19 ++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 - 3 files changed, 19 insertions(+), 97 deletions(-) delete mode 100644 springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageConfiguration.java diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageConfiguration.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageConfiguration.java deleted file mode 100644 index 6df0b467a..000000000 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageConfiguration.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * - * * - * * * - * * * * Copyright 2019-2024 the original author or authors. - * * * * - * * * * Licensed under the Apache License, Version 2.0 (the "License"); - * * * * you may not use this file except in compliance with the License. - * * * * You may obtain a copy of the License at - * * * * - * * * * https://www.apache.org/licenses/LICENSE-2.0 - * * * * - * * * * Unless required by applicable law or agreed to in writing, software - * * * * distributed under the License is distributed on an "AS IS" BASIS, - * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * * * See the License for the specific language governing permissions and - * * * * limitations under the License. - * * * - * * - * - */ - -package org.springdoc.core.configuration; - -import org.springdoc.core.converters.PageOpenAPIConverter; -import org.springdoc.core.converters.SortOpenAPIConverter; -import org.springdoc.core.converters.models.SortObject; -import org.springdoc.core.customizers.DataRestDelegatingMethodParameterCustomizer; -import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer; -import org.springdoc.core.providers.ObjectMapperProvider; -import org.springdoc.core.providers.RepositoryRestConfigurationProvider; -import org.springdoc.core.providers.SpringDataWebPropertiesProvider; -import org.springframework.boot.autoconfigure.condition.*; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Lazy; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Sort; -import org.springframework.data.web.PagedModel; -import org.springframework.data.web.config.EnableSpringDataWebSupport; -import org.springframework.data.web.config.SpringDataWebSettings; - -import java.util.Optional; - -import static org.springdoc.core.utils.Constants.SPRINGDOC_ENABLED; -import static org.springdoc.core.utils.Constants.SPRINGDOC_SORT_CONVERTER_ENABLED; -import static org.springdoc.core.utils.SpringDocUtils.getConfig; - -/** - * The type Spring doc page configuration. - * - * @author Claudio Nave - */ -@Lazy(false) -@Configuration(proxyBeanMethods = false) -@ConditionalOnProperty(name = SPRINGDOC_ENABLED, matchIfMissing = true) -@ConditionalOnClass({ Page.class, PagedModel.class }) -@ConditionalOnWebApplication -@ConditionalOnBean(SpringDocConfiguration.class) -public class SpringDocPageConfiguration { - - /** - * Page open api converter. - * @param objectMapperProvider the object mapper provider - * @return the page open api converter - */ - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean(SpringDataWebSettings.class) - @Lazy(false) - PageOpenAPIConverter pageOpenAPIConverter(SpringDataWebSettings settings, - ObjectMapperProvider objectMapperProvider) { - return new PageOpenAPIConverter( - settings.pageSerializationMode() == EnableSpringDataWebSupport.PageSerializationMode.VIA_DTO, - objectMapperProvider); - } - - /** - * Delegating method parameter customizer delegating method parameter customizer. - * @param optionalSpringDataWebPropertiesProvider the optional spring data web - * properties - * @param optionalRepositoryRestConfiguration the optional repository rest - * configuration - * @return the delegating method parameter customizer - */ - @Bean - @ConditionalOnMissingBean - @Lazy(false) - DelegatingMethodParameterCustomizer delegatingMethodParameterCustomizer( - Optional optionalSpringDataWebPropertiesProvider, - Optional optionalRepositoryRestConfiguration) { - return new DataRestDelegatingMethodParameterCustomizer(optionalSpringDataWebPropertiesProvider, - optionalRepositoryRestConfiguration); - } - -} \ No newline at end of file diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageableConfiguration.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageableConfiguration.java index 0dd0a9e50..d301d7d53 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageableConfiguration.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageableConfiguration.java @@ -26,6 +26,7 @@ import java.util.Optional; +import org.springdoc.core.converters.PageOpenAPIConverter; import org.springdoc.core.converters.PageableOpenAPIConverter; import org.springdoc.core.customizers.DataRestDelegatingMethodParameterCustomizer; import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer; @@ -42,6 +43,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.data.domain.Pageable; +import org.springframework.data.web.config.EnableSpringDataWebSupport; +import org.springframework.data.web.config.SpringDataWebSettings; import static org.springdoc.core.utils.Constants.SPRINGDOC_ENABLED; import static org.springdoc.core.utils.Constants.SPRINGDOC_PAGEABLE_CONVERTER_ENABLED; @@ -75,6 +78,22 @@ PageableOpenAPIConverter pageableOpenAPIConverter(ObjectMapperProvider objectMap return new PageableOpenAPIConverter(objectMapperProvider); } + /** + * Page open api converter. + * @param objectMapperProvider the object mapper provider + * @return the page open api converter + */ + @Bean + @ConditionalOnMissingBean + @ConditionalOnBean(SpringDataWebSettings.class) + @Lazy(false) + PageOpenAPIConverter pageOpenAPIConverter(SpringDataWebSettings settings, + ObjectMapperProvider objectMapperProvider) { + return new PageOpenAPIConverter( + settings.pageSerializationMode() == EnableSpringDataWebSupport.PageSerializationMode.VIA_DTO, + objectMapperProvider); + } + /** * Delegating method parameter customizer delegating method parameter customizer. * diff --git a/springdoc-openapi-starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/springdoc-openapi-starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index ad61f1fa5..12694c003 100644 --- a/springdoc-openapi-starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/springdoc-openapi-starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -7,7 +7,6 @@ org.springdoc.core.configuration.SpringDocFunctionCatalogConfiguration org.springdoc.core.configuration.SpringDocHateoasConfiguration org.springdoc.core.configuration.SpringDocPageableConfiguration org.springdoc.core.configuration.SpringDocSortConfiguration -org.springdoc.core.configuration.SpringDocPageConfiguration org.springdoc.core.configuration.SpringDocSpecPropertiesConfiguration org.springdoc.core.configuration.SpringDocDataRestConfiguration org.springdoc.core.configuration.SpringDocKotlinConfiguration From 3b577e499410e0b56853acfe275ad6ee43184cfb Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sat, 15 Jun 2024 20:10:57 +0200 Subject: [PATCH 16/33] Code review. Fixes #2625 --- .../app10/SpringDocApp10NotSpecifiedTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java index c6f6856dd..14b6a0452 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java @@ -22,8 +22,23 @@ package test.org.springdoc.api.app10; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.SimpleMixInResolver; +import com.fasterxml.jackson.databind.type.ClassKey; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springdoc.core.providers.ObjectMapperProvider; import org.springdoc.core.utils.Constants; + +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.web.config.EnableSpringDataWebSupport; @@ -35,6 +50,11 @@ public class SpringDocApp10NotSpecifiedTest extends AbstractSpringDocTest { + private final Map> springMixins = new HashMap<>(); + + @Autowired + ObjectMapperProvider objectMapperProvider; + @Override @Test public void testApp() throws Exception { @@ -49,4 +69,29 @@ public static class SpringDocTestApp { } + @BeforeEach + void init() throws IllegalAccessException { + Field convertersField2 = FieldUtils.getDeclaredField(ObjectMapper.class, "_mixIns", true); + SimpleMixInResolver _mixIns = (SimpleMixInResolver) convertersField2.get(objectMapperProvider.jsonMapper()); + Field convertersField3 = FieldUtils.getDeclaredField(SimpleMixInResolver.class, "_localMixIns", true); + Map> _localMixIns = (Map>) convertersField3.get(_mixIns); + Iterator>> it = _localMixIns.entrySet().iterator(); + while (it.hasNext()) { + Entry> entry = it.next(); + if (entry.getKey().toString().startsWith("org.springframework")) { + springMixins.put(entry.getKey(), entry.getValue()); + it.remove(); + } + } + + } + + @AfterEach + void clean() throws IllegalAccessException { + Field convertersField2 = FieldUtils.getDeclaredField(ObjectMapper.class, "_mixIns", true); + SimpleMixInResolver _mixIns = (SimpleMixInResolver) convertersField2.get(objectMapperProvider.jsonMapper()); + Field convertersField3 = FieldUtils.getDeclaredField(SimpleMixInResolver.class, "_localMixIns", true); + Map> _localMixIns = (Map>) convertersField3.get(_mixIns); + _localMixIns.putAll(springMixins); + } } From ea45be8a63c6952cf1843a44db9873d45eb3f01b Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sat, 15 Jun 2024 20:21:23 +0200 Subject: [PATCH 17/33] Code review. Fixes #2625 --- .../app10/SpringDocApp10NotSpecifiedTest.java | 62 +++++-------------- 1 file changed, 17 insertions(+), 45 deletions(-) diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java index 14b6a0452..933795d85 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java @@ -22,38 +22,35 @@ package test.org.springdoc.api.app10; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; +import java.util.Optional; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.introspect.SimpleMixInResolver; -import com.fasterxml.jackson.databind.type.ClassKey; -import org.apache.commons.lang3.reflect.FieldUtils; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; +import io.swagger.v3.core.converter.ModelConverter; +import io.swagger.v3.core.converter.ModelConverters; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.springdoc.core.providers.ObjectMapperProvider; +import org.springdoc.core.converters.PageOpenAPIConverter; +import org.springdoc.core.converters.SchemaPropertyDeprecatingConverter; import org.springdoc.core.utils.Constants; +import test.org.springdoc.api.AbstractSpringDocTest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.data.web.config.EnableSpringDataWebSupport; -import test.org.springdoc.api.AbstractSpringDocTest; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; public class SpringDocApp10NotSpecifiedTest extends AbstractSpringDocTest { - private final Map> springMixins = new HashMap<>(); - @Autowired - ObjectMapperProvider objectMapperProvider; + @BeforeAll + public static void init() { + Optional pageOpenAPIConverter = + ModelConverters.getInstance().getConverters() + .stream().filter(modelConverter -> modelConverter instanceof PageOpenAPIConverter).findAny(); + pageOpenAPIConverter.ifPresent(ModelConverters.getInstance()::removeConverter); + } @Override @Test @@ -69,29 +66,4 @@ public static class SpringDocTestApp { } - @BeforeEach - void init() throws IllegalAccessException { - Field convertersField2 = FieldUtils.getDeclaredField(ObjectMapper.class, "_mixIns", true); - SimpleMixInResolver _mixIns = (SimpleMixInResolver) convertersField2.get(objectMapperProvider.jsonMapper()); - Field convertersField3 = FieldUtils.getDeclaredField(SimpleMixInResolver.class, "_localMixIns", true); - Map> _localMixIns = (Map>) convertersField3.get(_mixIns); - Iterator>> it = _localMixIns.entrySet().iterator(); - while (it.hasNext()) { - Entry> entry = it.next(); - if (entry.getKey().toString().startsWith("org.springframework")) { - springMixins.put(entry.getKey(), entry.getValue()); - it.remove(); - } - } - - } - - @AfterEach - void clean() throws IllegalAccessException { - Field convertersField2 = FieldUtils.getDeclaredField(ObjectMapper.class, "_mixIns", true); - SimpleMixInResolver _mixIns = (SimpleMixInResolver) convertersField2.get(objectMapperProvider.jsonMapper()); - Field convertersField3 = FieldUtils.getDeclaredField(SimpleMixInResolver.class, "_localMixIns", true); - Map> _localMixIns = (Map>) convertersField3.get(_mixIns); - _localMixIns.putAll(springMixins); - } } From 36e20538b3e17692f9f0a96d86277f860ce15836 Mon Sep 17 00:00:00 2001 From: Claudio Nave Date: Sat, 15 Jun 2024 20:42:51 +0200 Subject: [PATCH 18/33] Ensure compatibility with previous version of spring data --- .../SpringDocPageableConfiguration.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageableConfiguration.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageableConfiguration.java index d301d7d53..b12aeb55b 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageableConfiguration.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocPageableConfiguration.java @@ -43,6 +43,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PagedModel; import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.data.web.config.SpringDataWebSettings; @@ -85,15 +86,16 @@ PageableOpenAPIConverter pageableOpenAPIConverter(ObjectMapperProvider objectMap */ @Bean @ConditionalOnMissingBean - @ConditionalOnBean(SpringDataWebSettings.class) + @ConditionalOnClass({ PagedModel.class, SpringDataWebSettings.class }) @Lazy(false) - PageOpenAPIConverter pageOpenAPIConverter(SpringDataWebSettings settings, + PageOpenAPIConverter pageOpenAPIConverter(Optional settings, ObjectMapperProvider objectMapperProvider) { - return new PageOpenAPIConverter( - settings.pageSerializationMode() == EnableSpringDataWebSupport.PageSerializationMode.VIA_DTO, - objectMapperProvider); + boolean replacePageWithPagedModel = settings.map(SpringDataWebSettings::pageSerializationMode) + .map(EnableSpringDataWebSupport.PageSerializationMode.VIA_DTO::equals) + .orElse(false); + return new PageOpenAPIConverter(replacePageWithPagedModel, objectMapperProvider); } - + /** * Delegating method parameter customizer delegating method parameter customizer. * From ef74a02c07222a31efed3cf584b33f92a3b8f05a Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sat, 15 Jun 2024 21:51:03 +0200 Subject: [PATCH 19/33] GroupedApi orders by displayName instead of name. Fixes #2576 --- .../core/properties/SwaggerUiConfigParameters.java | 4 ++-- .../test/org/springdoc/ui/app4/SpringDocApp4Test.java | 8 ++++---- .../java/test/org/springdoc/ui/app4/SpringDocTestApp.java | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SwaggerUiConfigParameters.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SwaggerUiConfigParameters.java index 8fab65098..c4b5a881f 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SwaggerUiConfigParameters.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SwaggerUiConfigParameters.java @@ -304,9 +304,9 @@ public Map getConfigParameters() { private void put(String urls, Set swaggerUrls, Map params) { Comparator swaggerUrlComparator; if (groupsOrder.isAscending()) - swaggerUrlComparator = Comparator.comparing(SwaggerUrl::getName); + swaggerUrlComparator = Comparator.comparing(SwaggerUrl::getDisplayName); else - swaggerUrlComparator = (h1, h2) -> h2.getName().compareTo(h1.getName()); + swaggerUrlComparator = (h1, h2) -> h2.getDisplayName().compareTo(h1.getDisplayName()); swaggerUrls = swaggerUrls.stream().sorted(swaggerUrlComparator).filter(elt -> StringUtils.isNotEmpty(elt.getUrl())).collect(Collectors.toCollection(LinkedHashSet::new)); if (!CollectionUtils.isEmpty(swaggerUrls)) { diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app4/SpringDocApp4Test.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app4/SpringDocApp4Test.java index 1d809ef9f..53e2d8a1d 100644 --- a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app4/SpringDocApp4Test.java +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app4/SpringDocApp4Test.java @@ -37,10 +37,10 @@ public void swagger_config_for_multiple_groups() throws Exception { .andExpect(status().isOk()) .andExpect(jsonPath("configUrl", equalTo("/v3/api-docs/swagger-config"))) .andExpect(jsonPath("url").doesNotExist()) - .andExpect(jsonPath("urls[0].url", equalTo("/v3/api-docs/stores"))) - .andExpect(jsonPath("urls[0].name", equalTo("stores"))) - .andExpect(jsonPath("urls[1].url", equalTo("/v3/api-docs/pets"))) - .andExpect(jsonPath("urls[1].name", equalTo("The pets"))) + .andExpect(jsonPath("urls[1].url", equalTo("/v3/api-docs/stores"))) + .andExpect(jsonPath("urls[1].name", equalTo("stores"))) + .andExpect(jsonPath("urls[0].url", equalTo("/v3/api-docs/pets"))) + .andExpect(jsonPath("urls[0].name", equalTo("zpets"))) .andExpect(jsonPath("$['urls.primaryName']", equalTo("pets"))); } } \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app4/SpringDocTestApp.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app4/SpringDocTestApp.java index f8d22037f..13506213c 100644 --- a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app4/SpringDocTestApp.java +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app4/SpringDocTestApp.java @@ -47,7 +47,7 @@ public GroupedOpenApi groupOpenApi() { String[] paths = { "/pet/**" }; return GroupedOpenApi.builder() .group("pets") - .displayName("The pets") + .displayName("zpets") .pathsToMatch(paths) .build(); } From eef312d0a7e04a15d28976aac621bdd8bd6ecb48 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 16 Jun 2024 11:55:51 +0200 Subject: [PATCH 20/33] Dynamically define ApiGroups does not work. Fixes #2584 --- .../MultipleOpenApiGroupsCondition.java | 7 +++++++ .../api/v30/app177/AnnotatedController.java | 18 ++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/conditions/MultipleOpenApiGroupsCondition.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/conditions/MultipleOpenApiGroupsCondition.java index 63a1ab686..66df9e4ad 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/conditions/MultipleOpenApiGroupsCondition.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/conditions/MultipleOpenApiGroupsCondition.java @@ -24,6 +24,8 @@ package org.springdoc.core.conditions; +import java.util.Collection; + import org.springdoc.core.models.GroupedOpenApi; import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; @@ -59,4 +61,9 @@ static class OnGroupedOpenApiBean {} @ConditionalOnProperty(name = GROUP_CONFIG_FIRST_PROPERTY) static class OnGroupConfigProperty {} + /** + * The type On list grouped open api bean. + */ + @ConditionalOnBean(value = GroupedOpenApi.class, parameterizedContainer = Collection.class) + static class OnListGroupedOpenApiBean {} } \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app177/AnnotatedController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app177/AnnotatedController.java index fca639d4a..74cc1c134 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app177/AnnotatedController.java +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app177/AnnotatedController.java @@ -26,6 +26,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.List; import org.springdoc.core.filters.OpenApiMethodFilter; import org.springdoc.core.models.GroupedOpenApi; @@ -65,27 +67,23 @@ public String notAnnotatedPost() { } @Bean - public GroupedOpenApi group1OpenApi() { - return GroupedOpenApi.builder() + public List apis() { + GroupedOpenApi group1OpenApi = GroupedOpenApi.builder() .group("annotatedGroup1") .addOpenApiMethodFilter(method -> method.isAnnotationPresent(Group1.class)) .build(); - } - @Bean - public GroupedOpenApi group2OpenApi() { - return GroupedOpenApi.builder() + GroupedOpenApi group2OpenApi = GroupedOpenApi.builder() .group("annotatedGroup2") .addOpenApiMethodFilter(method -> method.isAnnotationPresent(Group2.class)) .build(); - } - @Bean - public GroupedOpenApi group3OpenApi() { - return GroupedOpenApi.builder() + GroupedOpenApi group3OpenApi = GroupedOpenApi.builder() .group("annotatedCombinedGroup") .addOpenApiMethodFilter(method -> method.isAnnotationPresent(Group1.class) || method.isAnnotationPresent(Group2.class)) .build(); + + return Arrays.asList(group1OpenApi, group2OpenApi, group3OpenApi); } @Bean From 14c59da7a63e42f3a4c72f43065855a240ab4994 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 16 Jun 2024 12:57:50 +0200 Subject: [PATCH 21/33] Removed unused imports --- .../core/converters/PageOpenAPIConverter.java | 9 +++++---- .../springdoc/core/models/MethodAttributes.java | 6 +++--- .../api/AbstractOpenApiResourceTest.java | 2 +- .../api/v30/app217/SpringDocApp217Test.java | 2 -- .../api/v30/app218/HelloController.java | 5 +++-- .../api/v30/app218/SpringDocApp218Test.java | 3 ++- .../api/v30/app219/SpringDocApp219Test.java | 3 ++- .../api/AbstractSpringDocActuatorTest.java | 2 -- .../api/app147/SpringDocApp147Test.java | 3 --- .../api/app148/SpringDocApp148Test.java | 1 - .../api/app186/SpringDocApp186Test.java | 1 - .../springdoc/api/app10/HelloController.java | 4 ++-- .../api/app10/SpringDocApp10DirectTest.java | 8 +++++--- .../app10/SpringDocApp10NotSpecifiedTest.java | 1 - .../api/app10/SpringDocApp10ViaDtoTest.java | 9 +++++---- .../springdoc/api/app9/FooConfiguration.java | 6 +++--- .../springdoc/api/app9/SpringDocApp9Test.java | 3 ++- .../api/app9/application/FooController.java | 17 +++++++++++------ .../api/app9/application/dto/FeedResponse.java | 14 +++++++++----- .../api/app9/application/dto/ResponseData.java | 6 +++--- 20 files changed, 56 insertions(+), 49 deletions(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java index 3fcada041..63aaca0a8 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java @@ -22,6 +22,10 @@ package org.springdoc.core.converters; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Iterator; + import com.fasterxml.jackson.databind.JavaType; import io.swagger.v3.core.converter.AnnotatedType; import io.swagger.v3.core.converter.ModelConverter; @@ -29,13 +33,10 @@ import io.swagger.v3.oas.models.media.Schema; import org.apache.commons.lang3.StringUtils; import org.springdoc.core.providers.ObjectMapperProvider; + import org.springframework.core.ResolvableType; import org.springframework.data.web.PagedModel; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Iterator; - /** * The Spring Data Page type model converter. * diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java index dbb545a98..433df153a 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java @@ -30,16 +30,16 @@ import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import com.fasterxml.jackson.annotation.JsonView; import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponses; -import java.util.Set; -import java.util.stream.Collectors; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; - import org.jetbrains.annotations.Nullable; + import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; diff --git a/springdoc-openapi-starter-common/src/test/java/org/springdoc/api/AbstractOpenApiResourceTest.java b/springdoc-openapi-starter-common/src/test/java/org/springdoc/api/AbstractOpenApiResourceTest.java index f670da701..10ec555b0 100644 --- a/springdoc-openapi-starter-common/src/test/java/org/springdoc/api/AbstractOpenApiResourceTest.java +++ b/springdoc-openapi-starter-common/src/test/java/org/springdoc/api/AbstractOpenApiResourceTest.java @@ -60,9 +60,9 @@ import org.springframework.beans.factory.ObjectFactory; import org.springframework.context.ApplicationContext; +import org.springframework.mock.http.client.MockClientHttpRequest; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.mock.http.client.MockClientHttpRequest; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app217/SpringDocApp217Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app217/SpringDocApp217Test.java index fd4bb77ab..820e5ce8e 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app217/SpringDocApp217Test.java +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app217/SpringDocApp217Test.java @@ -20,13 +20,11 @@ import org.junit.jupiter.api.Test; import org.springdoc.core.customizers.SpecPropertiesCustomizer; -import org.springdoc.core.models.GroupedOpenApi; import org.springdoc.core.utils.Constants; import test.org.springdoc.api.v30.AbstractSpringDocV30Test; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; import org.springframework.test.context.ActiveProfiles; import static org.hamcrest.Matchers.is; diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/HelloController.java index 6749896a4..e753b54f0 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/HelloController.java +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/HelloController.java @@ -23,17 +23,18 @@ package test.org.springdoc.api.v30.app218; +import java.net.URI; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.headers.Header; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; + import org.springframework.http.HttpHeaders; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.net.URI; - @RestController @RequestMapping("/") diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/SpringDocApp218Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/SpringDocApp218Test.java index 24b9d92b4..65013aff1 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/SpringDocApp218Test.java +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app218/SpringDocApp218Test.java @@ -19,9 +19,10 @@ package test.org.springdoc.api.v30.app218; import org.springdoc.core.customizers.SpecPropertiesCustomizer; +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -import test.org.springdoc.api.v30.AbstractSpringDocV30Test; /** *

diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/SpringDocApp219Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/SpringDocApp219Test.java index a6ec97f84..a9afcaf7b 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/SpringDocApp219Test.java +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/SpringDocApp219Test.java @@ -24,9 +24,10 @@ package test.org.springdoc.api.v30.app219; +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.test.context.ActiveProfiles; -import test.org.springdoc.api.v30.AbstractSpringDocV30Test; @ActiveProfiles("219") public class SpringDocApp219Test extends AbstractSpringDocV30Test { diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java index 029d5ff0c..fa81f9c09 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/AbstractSpringDocActuatorTest.java @@ -25,11 +25,9 @@ package test.org.springdoc.api; import jakarta.annotation.PostConstruct; -import org.springdoc.core.utils.Constants; import org.springframework.boot.test.web.server.LocalManagementPort; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.web.reactive.server.EntityExchangeResult; import org.springframework.web.reactive.function.client.WebClient; import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java index a41644858..83a884cbf 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java @@ -24,9 +24,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.web.reactive.server.EntityExchangeResult; - -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java index 851b43460..11b004e45 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java @@ -30,7 +30,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app186/SpringDocApp186Test.java b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app186/SpringDocApp186Test.java index 85e94408e..8282d1e3a 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app186/SpringDocApp186Test.java +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/java/test/org/springdoc/api/app186/SpringDocApp186Test.java @@ -27,7 +27,6 @@ import org.junit.jupiter.api.Test; import org.springdoc.core.customizers.ActuatorOpenApiCustomizer; -import org.springdoc.core.customizers.OpenApiCustomizer; import org.springdoc.core.customizers.OperationCustomizer; import org.springdoc.core.models.GroupedOpenApi; import org.springdoc.core.utils.Constants; diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/HelloController.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/HelloController.java index 0597d1fd4..00d143fbf 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/HelloController.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/HelloController.java @@ -22,14 +22,14 @@ package test.org.springdoc.api.app10; +import java.util.List; + import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.web.PagedModel; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - @SuppressWarnings("rawtypes") @RestController public class HelloController { diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10DirectTest.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10DirectTest.java index 6ced6708d..4dba111c1 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10DirectTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10DirectTest.java @@ -24,14 +24,16 @@ import org.junit.jupiter.api.Test; import org.springdoc.core.utils.Constants; -import org.springframework.boot.SpringBootConfiguration; +import test.org.springdoc.api.AbstractSpringDocTest; + import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.web.config.EnableSpringDataWebSupport; -import test.org.springdoc.api.AbstractSpringDocTest; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; public class SpringDocApp10DirectTest extends AbstractSpringDocTest { diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java index 933795d85..91985d75e 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10NotSpecifiedTest.java @@ -29,7 +29,6 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.springdoc.core.converters.PageOpenAPIConverter; -import org.springdoc.core.converters.SchemaPropertyDeprecatingConverter; import org.springdoc.core.utils.Constants; import test.org.springdoc.api.AbstractSpringDocTest; diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10ViaDtoTest.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10ViaDtoTest.java index 7d37e9f38..22e8cc2ea 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10ViaDtoTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app10/SpringDocApp10ViaDtoTest.java @@ -24,15 +24,16 @@ import org.junit.jupiter.api.Test; import org.springdoc.core.utils.Constants; -import org.springframework.boot.SpringBootConfiguration; +import test.org.springdoc.api.AbstractSpringDocTest; + import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.TestConfiguration; import org.springframework.data.web.config.EnableSpringDataWebSupport; -import test.org.springdoc.api.AbstractSpringDocTest; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; public class SpringDocApp10ViaDtoTest extends AbstractSpringDocTest { diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/FooConfiguration.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/FooConfiguration.java index 11065e4b9..c5a21f1c1 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/FooConfiguration.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/FooConfiguration.java @@ -1,5 +1,7 @@ package test.org.springdoc.api.app9; +import java.util.List; + import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; @@ -8,12 +10,10 @@ import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.security.SecurityScheme; import io.swagger.v3.oas.models.tags.Tag; -import org.springdoc.core.models.GroupedOpenApi; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; - @Configuration public class FooConfiguration { @Bean diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/SpringDocApp9Test.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/SpringDocApp9Test.java index ba02d6e00..2e4cab1b2 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/SpringDocApp9Test.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/SpringDocApp9Test.java @@ -18,9 +18,10 @@ package test.org.springdoc.api.app9; -import org.springframework.boot.autoconfigure.SpringBootApplication; import test.org.springdoc.api.AbstractSpringDocTest; +import org.springframework.boot.autoconfigure.SpringBootApplication; + public class SpringDocApp9Test extends AbstractSpringDocTest { @SpringBootApplication diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/FooController.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/FooController.java index dd5864ae1..8600ded15 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/FooController.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/FooController.java @@ -1,17 +1,22 @@ package test.org.springdoc.api.app9.application; +import java.util.List; +import java.util.UUID; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.*; -import test.org.springdoc.api.app9.application.dto.ResponseData; import test.org.springdoc.api.app9.application.dto.FeedResponse; +import test.org.springdoc.api.app9.application.dto.ResponseData; -import java.util.List; -import java.util.UUID; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; @Tag(name = "ResponseDataController") @RestController @RequestMapping(value = "/some-route", produces = MediaType.APPLICATION_JSON_VALUE) diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/dto/FeedResponse.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/dto/FeedResponse.java index 9fc1e3e66..a9819e55d 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/dto/FeedResponse.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/dto/FeedResponse.java @@ -1,15 +1,19 @@ package test.org.springdoc.api.app9.application.dto; +import java.util.List; +import java.util.UUID; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; -import lombok.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; import lombok.experimental.Accessors; -import org.springframework.hateoas.IanaLinkRelations; -import org.springframework.hateoas.RepresentationModel; import test.org.springdoc.api.app9.application.FooController; -import java.util.List; -import java.util.UUID; +import org.springframework.hateoas.IanaLinkRelations; +import org.springframework.hateoas.RepresentationModel; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/dto/ResponseData.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/dto/ResponseData.java index 7d0860484..4481194c6 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/dto/ResponseData.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/app9/application/dto/ResponseData.java @@ -1,13 +1,13 @@ package test.org.springdoc.api.app9.application.dto; +import java.time.LocalDate; +import java.util.UUID; + import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Builder; -import java.time.LocalDate; -import java.util.UUID; - @Builder public record ResponseData( @JsonProperty(value = "DATA_ID", required = true) From 4059109bd42cd1e1a8613066682219ca97868121 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 16 Jun 2024 13:10:44 +0200 Subject: [PATCH 22/33] When an entity class contains fields of Class type, an infinite loop. Fixes #2591 --- .../springdoc/core/extractor/MethodParameterPojoExtractor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/extractor/MethodParameterPojoExtractor.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/extractor/MethodParameterPojoExtractor.java index ff8e3f0c1..c040264c2 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/extractor/MethodParameterPojoExtractor.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/extractor/MethodParameterPojoExtractor.java @@ -88,6 +88,7 @@ public class MethodParameterPojoExtractor { SIMPLE_TYPES.add(Iterable.class); SIMPLE_TYPES.add(Duration.class); SIMPLE_TYPES.add(LocalTime.class); + SIMPLE_TYPES.add(Class.class); SIMPLE_TYPE_PREDICATES.add(Class::isPrimitive); SIMPLE_TYPE_PREDICATES.add(Class::isEnum); From 07e2c926d174e4093efdf91e37f44668091242bc Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 16 Jun 2024 13:34:45 +0200 Subject: [PATCH 23/33] Spring security @RegisteredOAuth2AuthorizedClient is not handled in the right way. Fixes #2595 --- springdoc-openapi-starter-common/pom.xml | 5 ++++ .../SpringDocSecurityConfiguration.java | 19 ++++++++++++ .../springdoc-openapi-security-tests/pom.xml | 5 ++++ .../springdoc/api/app1/HelloController.java | 9 ++++++ .../src/test/resources/results/app1.json | 30 +++++++++++++++++++ 5 files changed, 68 insertions(+) diff --git a/springdoc-openapi-starter-common/pom.xml b/springdoc-openapi-starter-common/pom.xml index dd6ede53a..94c8ccfce 100644 --- a/springdoc-openapi-starter-common/pom.xml +++ b/springdoc-openapi-starter-common/pom.xml @@ -51,6 +51,11 @@ spring-security-oauth2-authorization-server true + + org.springframework.security + spring-security-oauth2-client + true + com.fasterxml.jackson.module diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityConfiguration.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityConfiguration.java index 465a9bc4a..d577f12fd 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityConfiguration.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityConfiguration.java @@ -58,6 +58,7 @@ import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.SecurityFilterChain; @@ -169,6 +170,9 @@ OpenApiCustomizer springSecurityLoginEndpointCustomiser(ApplicationContext appli } } + /** + * The type Spring doc security o auth 2 configuration. + */ @Lazy(false) @Configuration(proxyBeanMethods = false) @ConditionalOnClass(OAuth2AuthorizationService.class) @@ -186,4 +190,19 @@ GlobalOpenApiCustomizer springDocSecurityOAuth2Customizer() { return new SpringDocSecurityOAuth2Customizer(); } } + + /** + * The type Spring doc security o auth 2 client configuration. + */ + @Lazy(false) + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(RegisteredOAuth2AuthorizedClient.class) + class SpringDocSecurityOAuth2ClientConfiguration { + + static { + getConfig() + .addAnnotationsToIgnore(RegisteredOAuth2AuthorizedClient.class); + } + + } } \ No newline at end of file diff --git a/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml index 2779092bd..9ef3caf3f 100644 --- a/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml @@ -20,6 +20,11 @@ spring-security-config test + + org.springframework.security + spring-security-oauth2-client + test + jakarta.servlet jakarta.servlet-api diff --git a/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/java/test/org/springdoc/api/app1/HelloController.java b/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/java/test/org/springdoc/api/app1/HelloController.java index 8dbff03ac..063133377 100644 --- a/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/java/test/org/springdoc/api/app1/HelloController.java +++ b/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/java/test/org/springdoc/api/app1/HelloController.java @@ -20,6 +20,8 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.User; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @@ -38,4 +40,11 @@ public String personsWithUser(@RequestBody() Person person, return "OK"; } + @PostMapping(value = "/persons-with-oauth2-user") + public String personsWithUser(@RequestBody() Person person, + @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient, + @AuthenticationPrincipal User user) { + return "OK"; + } + } \ No newline at end of file diff --git a/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app1.json b/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app1.json index 0b91f6ec3..0260adb6d 100644 --- a/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app1.json +++ b/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app1.json @@ -74,6 +74,36 @@ } } } + }, + "/persons-with-oauth2-user": { + "post": { + "tags": [ + "hello-controller" + ], + "operationId": "personsWithUser_1", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Person" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } } }, "components": { From 497bfae781a2e637037892d333f625595675531c Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 16 Jun 2024 21:38:56 +0200 Subject: [PATCH 24/33] PolymorphicModelConverter only handles direct subtypes and misses indirect. Fixes #2603 --- .../converters/PolymorphicModelConverter.java | 42 ++++-- .../api/v30/app220/HelloController.java | 63 +++++++++ .../api/v30/app220/SpringDocApp220Test.java | 35 +++++ .../test/resources/results/3.0.1/app220.json | 132 ++++++++++++++++++ 4 files changed, 263 insertions(+), 9 deletions(-) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app220/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app220/SpringDocApp220Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app220.json diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java index 2f04a52c8..95a93340d 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java @@ -25,9 +25,11 @@ package org.springdoc.core.converters; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JavaType; import io.swagger.v3.core.converter.AnnotatedType; @@ -61,10 +63,12 @@ public PolymorphicModelConverter(ObjectMapperProvider springDocObjectMapper) { private static Schema getResolvedSchema(JavaType javaType, Schema resolvedSchema) { if (resolvedSchema instanceof ObjectSchema && resolvedSchema.getProperties() != null) { - if (resolvedSchema.getProperties().containsKey(javaType.getRawClass().getName())) + if (resolvedSchema.getProperties().containsKey(javaType.getRawClass().getName())){ resolvedSchema = resolvedSchema.getProperties().get(javaType.getRawClass().getName()); - else if (resolvedSchema.getProperties().containsKey(javaType.getRawClass().getSimpleName())) + } + else if (resolvedSchema.getProperties().containsKey(javaType.getRawClass().getSimpleName())){ resolvedSchema = resolvedSchema.getProperties().get(javaType.getRawClass().getSimpleName()); + } } return resolvedSchema; } @@ -94,13 +98,8 @@ public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterato */ private Schema composePolymorphicSchema(AnnotatedType type, Schema schema, Collection schemas) { String ref = schema.get$ref(); - List composedSchemas = schemas.stream() - .filter(ComposedSchema.class::isInstance) - .map(ComposedSchema.class::cast) - .filter(s -> s.getAllOf() != null) - .filter(s -> s.getAllOf().stream().anyMatch(s2 -> ref.equals(s2.get$ref()))) - .map(s -> new Schema().$ref(AnnotationsUtils.COMPONENTS_REF + s.getName())) - .toList(); + List composedSchemas = findComposedSchemas(ref, schemas); + if (composedSchemas.isEmpty()) return schema; ComposedSchema result = new ComposedSchema(); @@ -109,6 +108,31 @@ private Schema composePolymorphicSchema(AnnotatedType type, Schema schema, Colle return result; } + /** + * Find composed schemas recursively. + * + * @param ref the reference of the schema + * @param schemas the collection of schemas to search in + * @return the list of composed schemas + */ + private List findComposedSchemas(String ref, Collection schemas) { + List composedSchemas = schemas.stream() + .filter(ComposedSchema.class::isInstance) + .map(ComposedSchema.class::cast) + .filter(s -> s.getAllOf() != null) + .filter(s -> s.getAllOf().stream().anyMatch(s2 -> ref.equals(s2.get$ref()))) + .map(s -> new Schema().$ref(AnnotationsUtils.COMPONENTS_REF + s.getName())) + .collect(Collectors.toList()); + + List resultSchemas = new ArrayList<>(composedSchemas); + + for (Schema childSchema : composedSchemas) { + String childSchemaRef = childSchema.get$ref(); + resultSchemas.addAll(findComposedSchemas(childSchemaRef, schemas)); + } + + return resultSchemas; + } /** * Is concrete class boolean. * diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app220/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app220/HelloController.java new file mode 100644 index 000000000..f5b17bc2b --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app220/HelloController.java @@ -0,0 +1,63 @@ +package test.org.springdoc.api.v30.app220; + + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.v3.oas.annotations.media.Schema; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HelloController { + + @PostMapping("/parent") + public void parentEndpoint(@RequestBody Superclass parent) { + + } + +} + +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "@type") +@JsonSubTypes({ + @Type(value = IntermediateClass.class, name = IntermediateClass.SCHEMA_NAME), +}) +sealed class Superclass permits IntermediateClass { + + public Superclass() {} +} + +@Schema(name = IntermediateClass.SCHEMA_NAME) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "@type") +@JsonSubTypes({ + @Type(value = FirstChildClass.class, name = FirstChildClass.SCHEMA_NAME), + @Type(value = SecondChildClass.class, name = SecondChildClass.SCHEMA_NAME) +}) +sealed class IntermediateClass extends Superclass permits FirstChildClass, SecondChildClass { + + public static final String SCHEMA_NAME = "IntermediateClass"; +} + +@Schema(name = FirstChildClass.SCHEMA_NAME) +final class FirstChildClass extends IntermediateClass { + + public static final String SCHEMA_NAME = "Image"; +} + +@Schema(name = SecondChildClass.SCHEMA_NAME) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "@type") +@JsonSubTypes({ + @Type(value = ThirdChildClass.class, name = ThirdChildClass.SCHEMA_NAME) +}) +sealed class SecondChildClass extends IntermediateClass { + + public static final String SCHEMA_NAME = "Mail"; +} + +@Schema(name = ThirdChildClass.SCHEMA_NAME) +final class ThirdChildClass extends SecondChildClass { + + public static final String SCHEMA_NAME = "Home"; +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app220/SpringDocApp220Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app220/SpringDocApp220Test.java new file mode 100644 index 000000000..0e5f57595 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app220/SpringDocApp220Test.java @@ -0,0 +1,35 @@ +/* + * + * * + * * * + * * * * + * * * * * Copyright 2019-2022 the original author or authors. + * * * * * + * * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * * you may not use this file except in compliance with the License. + * * * * * You may obtain a copy of the License at + * * * * * + * * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * * + * * * * * Unless required by applicable law or agreed to in writing, software + * * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * * See the License for the specific language governing permissions and + * * * * * limitations under the License. + * * * * + * * * + * * + * + */ + +package test.org.springdoc.api.v30.app220; + +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +public class SpringDocApp220Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app220.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app220.json new file mode 100644 index 000000000..de2244501 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app220.json @@ -0,0 +1,132 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/parent": { + "post": { + "tags": [ + "hello-controller" + ], + "operationId": "parentEndpoint", + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Superclass" + }, + { + "$ref": "#/components/schemas/IntermediateClass" + }, + { + "$ref": "#/components/schemas/Image" + }, + { + "$ref": "#/components/schemas/Mail" + }, + { + "$ref": "#/components/schemas/Home" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "Home": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Mail" + } + ] + }, + "Image": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/IntermediateClass" + } + ] + }, + "IntermediateClass": { + "required": [ + "@type" + ], + "type": "object", + "discriminator": { + "propertyName": "@type" + }, + "allOf": [ + { + "$ref": "#/components/schemas/Superclass" + }, + { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + } + } + ] + }, + "Mail": { + "required": [ + "@type" + ], + "type": "object", + "discriminator": { + "propertyName": "@type" + }, + "allOf": [ + { + "$ref": "#/components/schemas/IntermediateClass" + }, + { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + } + } + ] + }, + "Superclass": { + "required": [ + "@type" + ], + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "discriminator": { + "propertyName": "@type" + } + } + } + } +} From 6c24eb632f31b36e04a37de8f99e5885df29efba Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 16 Jun 2024 22:33:14 +0200 Subject: [PATCH 25/33] Spring Authorization Server Metadata Endpoint not compatible. fixes #2606 --- .../SpringDocSecurityOAuth2Customizer.java | 19 +- .../src/test/resources/results/app10.json | 134 +++++---- .../src/test/resources/results/app11.json | 189 +++++++++---- .../src/test/resources/results/app12.json | 266 +++++++++++------- 4 files changed, 400 insertions(+), 208 deletions(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityOAuth2Customizer.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityOAuth2Customizer.java index b8cfd52f0..d155b9459 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityOAuth2Customizer.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSecurityOAuth2Customizer.java @@ -4,6 +4,8 @@ import io.swagger.v3.core.util.AnnotationsUtils; import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; @@ -18,9 +20,14 @@ import io.swagger.v3.oas.models.media.StringSchema; import io.swagger.v3.oas.models.parameters.HeaderParameter; import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.PathParameter; import io.swagger.v3.oas.models.parameters.RequestBody; import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponses; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.security.SecurityScheme.In; +import io.swagger.v3.oas.models.security.SecurityScheme.Type; import org.apache.commons.lang3.reflect.FieldUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -182,6 +189,10 @@ private void getOAuth2AuthorizationServerMetadataEndpoint(OpenAPI openAPI, Secur ReflectionUtils.makeAccessible(field); String defaultOauth2MetadataUri = (String) ReflectionUtils.getField(field, null); openAPI.getPaths().addPathItem(defaultOauth2MetadataUri , new PathItem().get(operation)); + operation = buildOperation(apiResponses); + operation.addParametersItem(new PathParameter().name("subpath").schema(new StringSchema())); + operation.summary("Valid when multiple issuers are allowed"); + openAPI.getPaths().addPathItem(defaultOauth2MetadataUri+"/{subpath}" , new PathItem().get(operation)); } } } @@ -252,7 +263,7 @@ private void getOAuth2TokenEndpoint(OpenAPI openAPI, SecurityFilterChain securit String mediaType = org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; RequestBody requestBody = new RequestBody().content(new Content().addMediaType(mediaType, new MediaType().schema(requestSchema))); operation.setRequestBody(requestBody); - operation.addParametersItem(new HeaderParameter().name("Authorization")); + operation.addParametersItem(new HeaderParameter().name("Authorization").schema(new StringSchema())); buildPath(oAuth2EndpointFilter, "tokenEndpointMatcher", openAPI, operation, HttpMethod.POST); } @@ -310,6 +321,10 @@ private void getOidcProviderConfigurationEndpoint(OpenAPI openAPI, SecurityFilte ReflectionUtils.makeAccessible(field); String defaultOidcConfigUri = (String) ReflectionUtils.getField(field, null); openAPI.getPaths().addPathItem(defaultOidcConfigUri , new PathItem().get(operation)); + operation = buildOperation(apiResponses); + operation.addParametersItem(new PathParameter().name("subpath").schema(new StringSchema())); + operation.summary("Valid when multiple issuers are allowed"); + openAPI.getPaths().addPathItem("/{subpath}"+defaultOidcConfigUri , new PathItem().get(operation)); } } } @@ -360,7 +375,7 @@ private void getOidcClientRegistrationEndpoint(OpenAPI openAPI, SecurityFilterCh String mediaType = APPLICATION_JSON_VALUE; RequestBody requestBody = new RequestBody().content(new Content().addMediaType(mediaType, new MediaType().schema(schema))); operation.setRequestBody(requestBody); - operation.addParametersItem(new HeaderParameter().name("Authorization")); + operation.addParametersItem(new HeaderParameter().name("Authorization").schema(new StringSchema())); buildPath(oAuth2EndpointFilter, "clientRegistrationEndpointMatcher", openAPI, operation, HttpMethod.POST); } diff --git a/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app10.json b/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app10.json index c53212833..9ca244228 100644 --- a/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app10.json +++ b/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app10.json @@ -56,6 +56,9 @@ } } }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -65,6 +68,25 @@ } } } + } + } + } + }, + "/.well-known/oauth-authorization-server": { + "get": { + "tags": [ + "authorization-server-endpoints" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OAuth2AuthorizationServerMetadata" + } + } + } }, "500": { "description": "Internal Server Error" @@ -72,11 +94,22 @@ } } }, - "/.well-known/oauth-authorization-server": { + "/.well-known/oauth-authorization-server/{subpath}": { "get": { "tags": [ "authorization-server-endpoints" ], + "summary": "Valid when multiple issuers are allowed", + "parameters": [ + { + "name": "subpath", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], "responses": { "200": { "description": "OK", @@ -101,8 +134,11 @@ ], "parameters": [ { + "name": "Authorization", "in": "header", - "name": "Authorization" + "schema": { + "type": "string" + } } ], "requestBody": { @@ -165,6 +201,9 @@ } } }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -184,9 +223,6 @@ } } } - }, - "500": { - "description": "Internal Server Error" } } } @@ -215,15 +251,8 @@ "text/html": {} } }, - "302": { - "description": "Moved Temporarily", - "headers": { - "Location": { - "schema": { - "type": "string" - } - } - } + "500": { + "description": "Internal Server Error" }, "400": { "description": "Bad Request", @@ -235,8 +264,15 @@ } } }, - "500": { - "description": "Internal Server Error" + "302": { + "description": "Moved Temporarily", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } } } } @@ -280,6 +316,9 @@ } } }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -289,9 +328,6 @@ } } } - }, - "500": { - "description": "Internal Server Error" } } } @@ -322,6 +358,9 @@ "200": { "description": "OK" }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -331,9 +370,6 @@ } } } - }, - "500": { - "description": "Internal Server Error" } } } @@ -358,9 +394,6 @@ "OAuth2AuthorizationServerMetadata": { "type": "object", "properties": { - "issuer": { - "type": "string" - }, "token_endpoint_auth_methods_supported": { "type": "array", "items": { @@ -397,16 +430,19 @@ "type": "string" } }, + "introspection_endpoint": { + "type": "string" + }, + "revocation_endpoint": { + "type": "string" + }, "grant_types_supported": { "type": "array", "items": { "type": "string" } }, - "revocation_endpoint": { - "type": "string" - }, - "introspection_endpoint": { + "issuer": { "type": "string" }, "jwks_uri": { @@ -424,13 +460,13 @@ "type": "integer", "format": "int64" }, - "access_token": { + "token_type": { "type": "string" }, - "refresh_token": { + "access_token": { "type": "string" }, - "token_type": { + "refresh_token": { "type": "string" } } @@ -438,26 +474,21 @@ "OAuth2TokenIntrospection": { "type": "object", "properties": { - "nbf": { - "type": "integer", - "format": "int64" - }, "scope": { "type": "string" }, "jti": { "type": "string" }, - "client_id": { - "type": "string" - }, - "username": { - "type": "string" + "exp": { + "type": "integer", + "format": "int64" }, - "active": { - "type": "boolean" + "nbf": { + "type": "integer", + "format": "int64" }, - "iss": { + "token_type": { "type": "string" }, "aud": { @@ -466,19 +497,24 @@ "type": "string" } }, - "token_type": { + "client_id": { "type": "string" }, - "exp": { - "type": "integer", - "format": "int64" + "username": { + "type": "string" }, - "sub": { + "iss": { "type": "string" }, + "active": { + "type": "boolean" + }, "iat": { "type": "integer", "format": "int64" + }, + "sub": { + "type": "string" } } } diff --git a/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app11.json b/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app11.json index 1f8119986..8d7a90106 100644 --- a/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app11.json +++ b/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app11.json @@ -56,6 +56,9 @@ } } }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -65,6 +68,25 @@ } } } + } + } + } + }, + "/.well-known/oauth-authorization-server": { + "get": { + "tags": [ + "authorization-server-endpoints" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OAuth2AuthorizationServerMetadata" + } + } + } }, "500": { "description": "Internal Server Error" @@ -72,11 +94,22 @@ } } }, - "/.well-known/oauth-authorization-server": { + "/.well-known/oauth-authorization-server/{subpath}": { "get": { "tags": [ "authorization-server-endpoints" ], + "summary": "Valid when multiple issuers are allowed", + "parameters": [ + { + "name": "subpath", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], "responses": { "200": { "description": "OK", @@ -101,8 +134,11 @@ ], "parameters": [ { + "name": "Authorization", "in": "header", - "name": "Authorization" + "schema": { + "type": "string" + } } ], "requestBody": { @@ -165,6 +201,9 @@ } } }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -184,9 +223,6 @@ } } } - }, - "500": { - "description": "Internal Server Error" } } } @@ -215,15 +251,8 @@ "text/html": {} } }, - "302": { - "description": "Moved Temporarily", - "headers": { - "Location": { - "schema": { - "type": "string" - } - } - } + "500": { + "description": "Internal Server Error" }, "400": { "description": "Bad Request", @@ -235,8 +264,15 @@ } } }, - "500": { - "description": "Internal Server Error" + "302": { + "description": "Moved Temporarily", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } } } } @@ -280,6 +316,9 @@ } } }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -289,9 +328,6 @@ } } } - }, - "500": { - "description": "Internal Server Error" } } } @@ -322,6 +358,9 @@ "200": { "description": "OK" }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -331,6 +370,25 @@ } } } + } + } + } + }, + "/.well-known/openid-configuration": { + "get": { + "tags": [ + "authorization-server-endpoints" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcProviderConfiguration" + } + } + } }, "500": { "description": "Internal Server Error" @@ -338,11 +396,22 @@ } } }, - "/.well-known/openid-configuration": { + "/{subpath}/.well-known/openid-configuration": { "get": { "tags": [ "authorization-server-endpoints" ], + "summary": "Valid when multiple issuers are allowed", + "parameters": [ + { + "name": "subpath", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], "responses": { "200": { "description": "OK", @@ -405,9 +474,6 @@ "OAuth2AuthorizationServerMetadata": { "type": "object", "properties": { - "issuer": { - "type": "string" - }, "token_endpoint_auth_methods_supported": { "type": "array", "items": { @@ -444,16 +510,19 @@ "type": "string" } }, + "introspection_endpoint": { + "type": "string" + }, + "revocation_endpoint": { + "type": "string" + }, "grant_types_supported": { "type": "array", "items": { "type": "string" } }, - "revocation_endpoint": { - "type": "string" - }, - "introspection_endpoint": { + "issuer": { "type": "string" }, "jwks_uri": { @@ -471,13 +540,13 @@ "type": "integer", "format": "int64" }, - "access_token": { + "token_type": { "type": "string" }, - "refresh_token": { + "access_token": { "type": "string" }, - "token_type": { + "refresh_token": { "type": "string" } } @@ -485,26 +554,21 @@ "OAuth2TokenIntrospection": { "type": "object", "properties": { - "nbf": { - "type": "integer", - "format": "int64" - }, "scope": { "type": "string" }, "jti": { "type": "string" }, - "client_id": { - "type": "string" - }, - "username": { - "type": "string" + "exp": { + "type": "integer", + "format": "int64" }, - "active": { - "type": "boolean" + "nbf": { + "type": "integer", + "format": "int64" }, - "iss": { + "token_type": { "type": "string" }, "aud": { @@ -513,25 +577,33 @@ "type": "string" } }, - "token_type": { + "client_id": { "type": "string" }, - "exp": { - "type": "integer", - "format": "int64" + "username": { + "type": "string" }, - "sub": { + "iss": { "type": "string" }, + "active": { + "type": "boolean" + }, "iat": { "type": "integer", "format": "int64" + }, + "sub": { + "type": "string" } } }, "OidcProviderConfiguration": { "type": "object", "properties": { + "id_token_signing_alg_values_supported": { + "type": "string" + }, "token_endpoint_auth_methods_supported": { "type": "array", "items": { @@ -556,22 +628,19 @@ "type": "string" } }, - "id_token_signing_alg_values_supported": { - "type": "string" - }, - "authorization_endpoint": { + "subject_types_supported": { "type": "string" }, - "token_endpoint": { + "scopes_supported": { "type": "string" }, "userinfo_endpoint": { "type": "string" }, - "subject_types_supported": { + "authorization_endpoint": { "type": "string" }, - "scopes_supported": { + "token_endpoint": { "type": "string" }, "response_types_supported": { @@ -580,18 +649,18 @@ "type": "string" } }, + "introspection_endpoint": { + "type": "string" + }, + "revocation_endpoint": { + "type": "string" + }, "grant_types_supported": { "type": "array", "items": { "type": "string" } }, - "revocation_endpoint": { - "type": "string" - }, - "introspection_endpoint": { - "type": "string" - }, "issuer": { "type": "string" }, diff --git a/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app12.json b/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app12.json index 8925e7038..a45d84f60 100644 --- a/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app12.json +++ b/springdoc-openapi-tests/springdoc-openapi-security-tests/src/test/resources/results/app12.json @@ -56,6 +56,9 @@ } } }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -65,6 +68,25 @@ } } } + } + } + } + }, + "/.well-known/oauth-authorization-server": { + "get": { + "tags": [ + "authorization-server-endpoints" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OAuth2AuthorizationServerMetadata" + } + } + } }, "500": { "description": "Internal Server Error" @@ -72,11 +94,22 @@ } } }, - "/.well-known/oauth-authorization-server": { + "/.well-known/oauth-authorization-server/{subpath}": { "get": { "tags": [ "authorization-server-endpoints" ], + "summary": "Valid when multiple issuers are allowed", + "parameters": [ + { + "name": "subpath", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], "responses": { "200": { "description": "OK", @@ -101,8 +134,11 @@ ], "parameters": [ { + "name": "Authorization", "in": "header", - "name": "Authorization" + "schema": { + "type": "string" + } } ], "requestBody": { @@ -165,6 +201,9 @@ } } }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -184,9 +223,6 @@ } } } - }, - "500": { - "description": "Internal Server Error" } } } @@ -215,15 +251,8 @@ "text/html": {} } }, - "302": { - "description": "Moved Temporarily", - "headers": { - "Location": { - "schema": { - "type": "string" - } - } - } + "500": { + "description": "Internal Server Error" }, "400": { "description": "Bad Request", @@ -235,8 +264,15 @@ } } }, - "500": { - "description": "Internal Server Error" + "302": { + "description": "Moved Temporarily", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } } } } @@ -280,6 +316,9 @@ } } }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -289,9 +328,6 @@ } } } - }, - "500": { - "description": "Internal Server Error" } } } @@ -322,6 +358,9 @@ "200": { "description": "OK" }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -331,6 +370,25 @@ } } } + } + } + } + }, + "/.well-known/openid-configuration": { + "get": { + "tags": [ + "authorization-server-endpoints" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcProviderConfiguration" + } + } + } }, "500": { "description": "Internal Server Error" @@ -338,11 +396,22 @@ } } }, - "/.well-known/openid-configuration": { + "/{subpath}/.well-known/openid-configuration": { "get": { "tags": [ "authorization-server-endpoints" ], + "summary": "Valid when multiple issuers are allowed", + "parameters": [ + { + "name": "subpath", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], "responses": { "200": { "description": "OK", @@ -393,7 +462,10 @@ "parameters": [ { "name": "Authorization", - "in": "header" + "in": "header", + "schema": { + "type": "string" + } } ], "requestBody": { @@ -416,6 +488,9 @@ } } }, + "500": { + "description": "Internal Server Error" + }, "400": { "description": "Bad Request", "content": { @@ -445,9 +520,6 @@ } } } - }, - "500": { - "description": "Internal Server Error" } } } @@ -472,9 +544,6 @@ "OAuth2AuthorizationServerMetadata": { "type": "object", "properties": { - "issuer": { - "type": "string" - }, "token_endpoint_auth_methods_supported": { "type": "array", "items": { @@ -511,16 +580,19 @@ "type": "string" } }, + "introspection_endpoint": { + "type": "string" + }, + "revocation_endpoint": { + "type": "string" + }, "grant_types_supported": { "type": "array", "items": { "type": "string" } }, - "revocation_endpoint": { - "type": "string" - }, - "introspection_endpoint": { + "issuer": { "type": "string" }, "jwks_uri": { @@ -538,13 +610,13 @@ "type": "integer", "format": "int64" }, - "access_token": { + "token_type": { "type": "string" }, - "refresh_token": { + "access_token": { "type": "string" }, - "token_type": { + "refresh_token": { "type": "string" } } @@ -552,26 +624,21 @@ "OAuth2TokenIntrospection": { "type": "object", "properties": { - "nbf": { - "type": "integer", - "format": "int64" - }, "scope": { "type": "string" }, "jti": { "type": "string" }, - "client_id": { - "type": "string" - }, - "username": { - "type": "string" + "exp": { + "type": "integer", + "format": "int64" }, - "active": { - "type": "boolean" + "nbf": { + "type": "integer", + "format": "int64" }, - "iss": { + "token_type": { "type": "string" }, "aud": { @@ -580,25 +647,33 @@ "type": "string" } }, - "token_type": { + "client_id": { "type": "string" }, - "exp": { - "type": "integer", - "format": "int64" + "username": { + "type": "string" }, - "sub": { + "iss": { "type": "string" }, + "active": { + "type": "boolean" + }, "iat": { "type": "integer", "format": "int64" + }, + "sub": { + "type": "string" } } }, "OidcProviderConfiguration": { "type": "object", "properties": { + "id_token_signing_alg_values_supported": { + "type": "string" + }, "token_endpoint_auth_methods_supported": { "type": "array", "items": { @@ -623,22 +698,19 @@ "type": "string" } }, - "id_token_signing_alg_values_supported": { - "type": "string" - }, - "authorization_endpoint": { + "subject_types_supported": { "type": "string" }, - "token_endpoint": { + "scopes_supported": { "type": "string" }, "userinfo_endpoint": { "type": "string" }, - "subject_types_supported": { + "authorization_endpoint": { "type": "string" }, - "scopes_supported": { + "token_endpoint": { "type": "string" }, "response_types_supported": { @@ -647,18 +719,18 @@ "type": "string" } }, + "introspection_endpoint": { + "type": "string" + }, + "revocation_endpoint": { + "type": "string" + }, "grant_types_supported": { "type": "array", "items": { "type": "string" } }, - "revocation_endpoint": { - "type": "string" - }, - "introspection_endpoint": { - "type": "string" - }, "issuer": { "type": "string" }, @@ -676,22 +748,13 @@ "id_token_signed_response_alg": { "type": "string" }, - "response_types": { - "type": "array", - "items": { - "type": "string" - } - }, - "client_secret": { + "registration_access_token": { "type": "string" }, "client_secret_expires_at": { "type": "integer", "format": "int64" }, - "registration_access_token": { - "type": "string" - }, "registration_client_uri": { "type": "string" }, @@ -705,12 +768,27 @@ "type": "string" } }, - "scope": { + "client_secret": { "type": "string" }, + "response_types": { + "type": "array", + "items": { + "type": "string" + } + }, "client_id": { "type": "string" }, + "client_name": { + "type": "string" + }, + "jwks_uri": { + "type": "string" + }, + "scope": { + "type": "string" + }, "token_endpoint_auth_signing_alg": { "type": "string" }, @@ -719,12 +797,6 @@ "items": { "type": "string" } - }, - "jwks_uri": { - "type": "string" - }, - "client_name": { - "type": "string" } } }, @@ -737,15 +809,6 @@ "id_token_signed_response_alg": { "type": "string" }, - "response_types": { - "type": "array", - "items": { - "type": "string" - } - }, - "client_secret": { - "type": "string" - }, "client_secret_expires_at": { "type": "string", "format": "date-time" @@ -760,12 +823,27 @@ "type": "string" } }, - "scope": { + "client_secret": { "type": "string" }, + "response_types": { + "type": "array", + "items": { + "type": "string" + } + }, "client_id": { "type": "string" }, + "client_name": { + "type": "string" + }, + "jwks_uri": { + "type": "string" + }, + "scope": { + "type": "string" + }, "token_endpoint_auth_signing_alg": { "type": "string" }, @@ -774,12 +852,6 @@ "items": { "type": "string" } - }, - "jwks_uri": { - "type": "string" - }, - "client_name": { - "type": "string" } } } From cf125474883829c11fd7389e86d2aed811785207 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Wed, 19 Jun 2024 03:04:11 +0200 Subject: [PATCH 26/33] Content-type for POST endpoints with multipart/form-data does not work since v2.4.0. Fixes #2621 --- .../core/data/DataRestRequestService.java | 2 +- .../core/service/AbstractRequestService.java | 41 ++++----- .../org/springdoc/api/v30/app221/HomeApi.java | 23 +++++ .../api/v30/app221/HomeController.java | 24 ++++++ .../api/v30/app221/SpringDocApp221Test.java | 35 ++++++++ .../test/resources/results/3.0.1/app221.json | 83 +++++++++++++++++++ 6 files changed, 188 insertions(+), 20 deletions(-) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/HomeApi.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/HomeController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/SpringDocApp221Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app221.json diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/data/DataRestRequestService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/data/DataRestRequestService.java index b756e7a87..fd67c75c0 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/data/DataRestRequestService.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/data/DataRestRequestService.java @@ -175,7 +175,7 @@ else if (methodParameter.getParameterAnnotation(BackendId.class) != null) { parameterInfo.setParameterModel(parameter); } if (!ArrayUtils.isEmpty(methodParameter.getParameterAnnotations())) - parameter = requestBuilder.buildParams(parameterInfo, openAPI.getComponents(), requestMethod, null, + parameter = requestBuilder.buildParams(parameterInfo, openAPI.getComponents(), requestMethod, methodAttributes, openAPI.getOpenapi()); addParameters(openAPI, requestMethod, methodAttributes, operation, methodParameter, parameterInfo, parameter); } diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java index 7fe94dad5..6a53cc4e3 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java @@ -25,6 +25,7 @@ package org.springdoc.core.service; import java.lang.annotation.Annotation; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.ArrayList; @@ -88,12 +89,14 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.method.HandlerMethod; +import org.springframework.web.multipart.MultipartFile; import org.springframework.web.util.UriComponentsBuilder; import static org.springdoc.core.converters.SchemaPropertyDeprecatingConverter.containsDeprecatedAnnotation; import static org.springdoc.core.service.GenericParameterService.isFile; import static org.springdoc.core.utils.Constants.OPENAPI_ARRAY_TYPE; import static org.springdoc.core.utils.Constants.OPENAPI_STRING_TYPE; +import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; /** * The type Abstract request builder. @@ -323,7 +326,7 @@ public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod, } if (!isParamToIgnore(methodParameter)) { - parameter = buildParams(parameterInfo, components, requestMethod, methodAttributes.getJsonViewAnnotation(), openAPI.getOpenapi()); + parameter = buildParams(parameterInfo, components, requestMethod, methodAttributes, openAPI.getOpenapi()); // Merge with the operation parameters parameter = GenericParameterService.mergeParameter(operationParameters, parameter); List parameterAnnotations = Arrays.asList(methodParameter.getParameterAnnotations()); @@ -353,7 +356,7 @@ else if (!RequestMethod.GET.equals(requestMethod) || OpenApiVersion.OPENAPI_3_1. // support form-data if (defaultSupportFormData && requestBody != null && requestBody.getContent() != null - && requestBody.getContent().containsKey(org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE)) { + && requestBody.getContent().containsKey(MULTIPART_FORM_DATA_VALUE)) { Iterator> it = map.entrySet().iterator(); while (it.hasNext()) { Entry entry = it.next(); @@ -496,28 +499,28 @@ public boolean isValidParameter(Parameter parameter) { /** * Build params parameter. * - * @param parameterInfo the parameter info - * @param components the components - * @param requestMethod the request method - * @param jsonView the json view - * @param openApiVersion the open api version + * @param parameterInfo the parameter info + * @param components the components + * @param requestMethod the request method + * @param methodAttributes the method attributes + * @param openApiVersion the open api version * @return the parameter */ public Parameter buildParams(ParameterInfo parameterInfo, Components components, - RequestMethod requestMethod, JsonView jsonView, String openApiVersion) { + RequestMethod requestMethod, MethodAttributes methodAttributes, String openApiVersion) { MethodParameter methodParameter = parameterInfo.getMethodParameter(); if (parameterInfo.getParamType() != null) { if (!ValueConstants.DEFAULT_NONE.equals(parameterInfo.getDefaultValue())) parameterInfo.setRequired(false); else parameterInfo.setDefaultValue(null); - return this.buildParam(parameterInfo, components, jsonView); + return this.buildParam(parameterInfo, components, methodAttributes.getJsonViewAnnotation()); } // By default - if (!isRequestBodyParam(requestMethod, parameterInfo, openApiVersion)) { + if (!isRequestBodyParam(requestMethod, parameterInfo, openApiVersion, methodAttributes)) { parameterInfo.setRequired(!((DelegatingMethodParameter) methodParameter).isNotRequired() && !methodParameter.isOptional()); parameterInfo.setDefaultValue(null); - return this.buildParam(parameterInfo, components, jsonView); + return this.buildParam(parameterInfo, components, methodAttributes.getJsonViewAnnotation()); } return null; } @@ -631,7 +634,7 @@ public RequestBodyService getRequestBodyBuilder() { public boolean isDefaultFlatParamObject() { return defaultFlatParamObject; } - + /** * Calculate size. * @@ -722,12 +725,13 @@ private void applyValidationsToSchema(Map annos, Schema s /** * Is RequestBody param boolean. * - * @param requestMethod the request method - * @param parameterInfo the parameter info - * @param openApiVersion the open api version + * @param requestMethod the request method + * @param parameterInfo the parameter info + * @param openApiVersion the open api version + * @param methodAttributes the method attributes * @return the boolean */ - private boolean isRequestBodyParam(RequestMethod requestMethod, ParameterInfo parameterInfo, String openApiVersion) { + private boolean isRequestBodyParam(RequestMethod requestMethod, ParameterInfo parameterInfo, String openApiVersion, MethodAttributes methodAttributes) { MethodParameter methodParameter = parameterInfo.getMethodParameter(); DelegatingMethodParameter delegatingMethodParameter = (DelegatingMethodParameter) methodParameter; boolean isBodyAllowed = !RequestMethod.GET.equals(requestMethod) || OpenApiVersion.OPENAPI_3_1.getVersion().equals(openApiVersion); @@ -739,8 +743,7 @@ private boolean isRequestBodyParam(RequestMethod requestMethod, ParameterInfo pa || AnnotatedElementUtils.findMergedAnnotation(Objects.requireNonNull(methodParameter.getMethod()), io.swagger.v3.oas.annotations.parameters.RequestBody.class) != null) || checkOperationRequestBody(methodParameter) || checkFile(methodParameter) - - ); + || Arrays.asList(methodAttributes.getMethodConsumes()).contains(MULTIPART_FORM_DATA_VALUE)); } /** @@ -767,7 +770,7 @@ else if (methodParameter.getParameterAnnotation(org.springframework.web.bind.ann private boolean checkOperationRequestBody(MethodParameter methodParameter) { if (AnnotatedElementUtils.findMergedAnnotation(Objects.requireNonNull(methodParameter.getMethod()), io.swagger.v3.oas.annotations.Operation.class) != null) { io.swagger.v3.oas.annotations.Operation operation = AnnotatedElementUtils.findMergedAnnotation(Objects.requireNonNull(methodParameter.getMethod()), io.swagger.v3.oas.annotations.Operation.class); - if(operation!=null){ + if (operation != null) { io.swagger.v3.oas.annotations.parameters.RequestBody requestBody = operation.requestBody(); if (StringUtils.isNotBlank(requestBody.description())) return true; diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/HomeApi.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/HomeApi.java new file mode 100644 index 000000000..40506c3da --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/HomeApi.java @@ -0,0 +1,23 @@ +package test.org.springdoc.api.v30.app221; + +import java.io.IOException; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import test.org.springdoc.api.v30.app221.HomeController.HelloDto; +import test.org.springdoc.api.v30.app221.HomeController.HelloUploadDto; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; + +@Tag(name = "Hello World Api", description = "This is a test api") +@RequestMapping("api/hello") +public interface HomeApi { + + @Operation(summary = "Upload new content", description = "Upload test content") + @PostMapping(produces = APPLICATION_JSON_VALUE, consumes = MULTIPART_FORM_DATA_VALUE) + HelloDto uploadContent(HelloUploadDto contentUploadDto) throws IOException; +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/HomeController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/HomeController.java new file mode 100644 index 000000000..3c4115e94 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/HomeController.java @@ -0,0 +1,24 @@ +package test.org.springdoc.api.v30.app221; + +import java.io.IOException; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +@RestController +public class HomeController implements HomeApi { + + @Override + public HelloDto uploadContent(@Valid HelloUploadDto uploadDto) + throws IOException { + var fileBytes = uploadDto.file.getBytes(); + return new HelloDto(uploadDto.title, fileBytes); + } + + public record HelloDto(String title, byte[] file) {} + + public record HelloUploadDto(@NotNull String title, MultipartFile file) {} +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/SpringDocApp221Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/SpringDocApp221Test.java new file mode 100644 index 000000000..d53ee8dbf --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app221/SpringDocApp221Test.java @@ -0,0 +1,35 @@ +/* + * + * * + * * * + * * * * + * * * * * Copyright 2019-2022 the original author or authors. + * * * * * + * * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * * you may not use this file except in compliance with the License. + * * * * * You may obtain a copy of the License at + * * * * * + * * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * * + * * * * * Unless required by applicable law or agreed to in writing, software + * * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * * See the License for the specific language governing permissions and + * * * * * limitations under the License. + * * * * + * * * + * * + * + */ + +package test.org.springdoc.api.v30.app221; + +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +public class SpringDocApp221Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app221.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app221.json new file mode 100644 index 000000000..2554fd2f9 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app221.json @@ -0,0 +1,83 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "tags": [ + { + "name": "Hello World Api", + "description": "This is a test api" + } + ], + "paths": { + "/api/hello": { + "post": { + "tags": [ + "Hello World Api" + ], + "summary": "Upload new content", + "description": "Upload test content", + "operationId": "uploadContent", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/HelloUploadDto" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HelloDto" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "HelloUploadDto": { + "required": [ + "title" + ], + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "file": { + "type": "string", + "format": "binary" + } + } + }, + "HelloDto": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "file": { + "type": "string", + "format": "byte" + } + } + } + } + } +} From 524c5fa24593150854ea7ee0fee17cef08caafe1 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 23 Jun 2024 10:11:08 +0200 Subject: [PATCH 27/33] Kotlin enums are always marked as required if used in Java controllers. Fixes #2622 --- .../SpringDocKotlinConfiguration.kt | 8 ++- .../springdoc/api/app12/EnumController.java | 18 +++++++ .../springdoc/api/app12/SpringDocApp12Test.kt | 35 +++++++++++++ .../src/test/resources/results/app12.json | 50 +++++++++++++++++++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/EnumController.java create mode 100644 springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/SpringDocApp12Test.kt create mode 100644 springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/resources/results/app12.json diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocKotlinConfiguration.kt b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocKotlinConfiguration.kt index 7c7dd6070..fc09e6465 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocKotlinConfiguration.kt +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocKotlinConfiguration.kt @@ -92,9 +92,13 @@ class SpringDocKotlinConfiguration() { // parameter is not required if a default value is provided in @RequestParam else if (requestParam != null && requestParam.defaultValue != ValueConstants.DEFAULT_NONE) parameterModel.required = false - else + else{ + val isJavaNullableAnnotationPresent = methodParameter.parameterAnnotations.any { + it.annotationClass.qualifiedName == "jakarta.annotation.Nullable" + } parameterModel.required = - kParameter.type.isMarkedNullable == false + kParameter.type.isMarkedNullable == false && !isJavaNullableAnnotationPresent + } } } return@ParameterCustomizer parameterModel diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/EnumController.java b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/EnumController.java new file mode 100644 index 000000000..7bdd2ffe2 --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/EnumController.java @@ -0,0 +1,18 @@ +package test.org.springdoc.api.app12; + +import jakarta.annotation.Nullable; +import test.org.springdoc.api.app12.SpringDocApp12Test.MyEnum; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author bnasslahsen + */ +@RestController +public class EnumController { + @GetMapping("/test-enum-2") + String testEnum2(@Nullable MyEnum e) { + return ""; + } +} \ No newline at end of file diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/SpringDocApp12Test.kt b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/SpringDocApp12Test.kt new file mode 100644 index 000000000..f522f7de3 --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/SpringDocApp12Test.kt @@ -0,0 +1,35 @@ +/* + * + * * Copyright 2019-2023 the original author or authors. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * https://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package test.org.springdoc.api.app12 + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.context.annotation.ComponentScan +import test.org.springdoc.api.AbstractKotlinSpringDocMVCTest + +class SpringDocApp12Test : AbstractKotlinSpringDocMVCTest() { + + @SpringBootApplication + @ComponentScan(basePackages = ["org.springdoc", "test.org.springdoc.api.app12"]) + class DemoApplication + + enum class MyEnum { + A, B; + } + +} diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/resources/results/app12.json b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/resources/results/app12.json new file mode 100644 index 000000000..407e5620a --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/resources/results/app12.json @@ -0,0 +1,50 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/test-enum-2": { + "get": { + "tags": [ + "enum-controller" + ], + "operationId": "testEnum2", + "parameters": [ + { + "name": "e", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "A", + "B" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} From 42de831b5adbe50fd7d4bc8c29ac43512a7d0b77 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 23 Jun 2024 10:59:47 +0200 Subject: [PATCH 28/33] Kotlin enums are always marked as required if used in Java controllers. Fixes #2622 --- .../test/org/springdoc/api/app12/EnumController.java | 0 .../test/org/springdoc/api/app12/SpringDocApp12Test.kt | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/{kotlin => java}/test/org/springdoc/api/app12/EnumController.java (100%) rename springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/{kotlin => java}/test/org/springdoc/api/app12/SpringDocApp12Test.kt (100%) diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/EnumController.java b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/java/test/org/springdoc/api/app12/EnumController.java similarity index 100% rename from springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/EnumController.java rename to springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/java/test/org/springdoc/api/app12/EnumController.java diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/SpringDocApp12Test.kt b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/java/test/org/springdoc/api/app12/SpringDocApp12Test.kt similarity index 100% rename from springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/SpringDocApp12Test.kt rename to springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/java/test/org/springdoc/api/app12/SpringDocApp12Test.kt From cd9778fae6d7ccdcaffc4f7fd26e786be7614ae0 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 23 Jun 2024 12:48:40 +0200 Subject: [PATCH 29/33] Kotlin enums are always marked as required if used in Java controllers. Fixes #2622 --- .../pom.xml | 30 +++++++++++++++++++ .../springdoc/api/app12/SpringDocApp12Test.kt | 0 2 files changed, 30 insertions(+) rename springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/{java => kotlin}/test/org/springdoc/api/app12/SpringDocApp12Test.kt (100%) diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml index 745ee023f..14818297f 100644 --- a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml @@ -78,6 +78,36 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + + default-compile + none + + + + default-testCompile + none + + + java-compile + compile + + compile + + + + java-test-compile + test-compile + + testCompile + + + + \ No newline at end of file diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/java/test/org/springdoc/api/app12/SpringDocApp12Test.kt b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/SpringDocApp12Test.kt similarity index 100% rename from springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/java/test/org/springdoc/api/app12/SpringDocApp12Test.kt rename to springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/app12/SpringDocApp12Test.kt From fa35308fa19f522e4217ae723895bc3df5e32b68 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 23 Jun 2024 18:10:32 +0200 Subject: [PATCH 30/33] @Schema and description not picked up for polymorphic attributes. Fixes #2620 --- .../src/test/java/test/org/springdoc/api/v30/app185/Pet.java | 2 ++ .../src/test/resources/results/3.0.1/app185.json | 1 + 2 files changed, 3 insertions(+) diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app185/Pet.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app185/Pet.java index f02de23cc..93dc30461 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app185/Pet.java +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app185/Pet.java @@ -26,12 +26,14 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.v3.oas.annotations.media.Schema; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(Dog.class), @JsonSubTypes.Type(Cat.class) }) +@Schema(description = "This is a Pet") public class Pet { public final String name; diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app185.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app185.json index 699f9026b..78b116b1d 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app185.json +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app185.json @@ -109,6 +109,7 @@ "type": "string" } }, + "description": "This is a Pet", "discriminator": { "propertyName": "type" } From 8a1e0ad2bc71f7c3befd368c59b0d8119bb078b9 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 30 Jun 2024 00:23:25 +0200 Subject: [PATCH 31/33] Multiple Superclasses Are Not Mapped To Multiple allOf If Used In Different Services. Fixes #2601. --- .../converters/PolymorphicModelConverter.java | 2 +- .../core/utils/SpringDocAnnotationsUtils.java | 24 +++- .../api/v30/app222/HelloController.java | 28 ++++ .../api/v30/app222/SpringDocApp222Test.java | 55 ++++++++ .../test/resources/results/3.0.1/app222.json | 122 ++++++++++++++++++ 5 files changed, 225 insertions(+), 6 deletions(-) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app222/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app222/SpringDocApp222Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app222.json diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java index 95a93340d..eb9e04adb 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java @@ -122,7 +122,7 @@ private List findComposedSchemas(String ref, Collection schemas) .filter(s -> s.getAllOf() != null) .filter(s -> s.getAllOf().stream().anyMatch(s2 -> ref.equals(s2.get$ref()))) .map(s -> new Schema().$ref(AnnotationsUtils.COMPONENTS_REF + s.getName())) - .collect(Collectors.toList()); + .toList(); List resultSchemas = new ArrayList<>(composedSchemas); diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/SpringDocAnnotationsUtils.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/SpringDocAnnotationsUtils.java index c532a679a..0c3750eea 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/SpringDocAnnotationsUtils.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/SpringDocAnnotationsUtils.java @@ -31,9 +31,11 @@ import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonView; @@ -65,6 +67,7 @@ /** * The type Spring doc annotations utils. + * * @author bnasslahsen */ @SuppressWarnings({ "rawtypes" }) @@ -142,10 +145,21 @@ public static Schema extractSchema(Components components, Type returnType, JsonV for (Map.Entry entry : schemaMap.entrySet()) { // If we've seen this schema before but find later it should be polymorphic, // replace the existing schema with this richer version. + Schema existingSchema = componentSchemas.get(entry.getKey()); if (!componentSchemas.containsKey(entry.getKey()) || - (!entry.getValue().getClass().equals(componentSchemas.get(entry.getKey()).getClass()) && entry.getValue().getAllOf() != null)) { + (!entry.getValue().getClass().equals(existingSchema.getClass()) && entry.getValue().getAllOf() != null)) { componentSchemas.put(entry.getKey(), entry.getValue()); } + else if (componentSchemas.containsKey(entry.getKey()) && schemaMap.containsKey(entry.getKey())) { + // Check to merge polymorphic types + Set existingAllOf = new LinkedHashSet<>(); + if(existingSchema.getAllOf() != null) + existingAllOf.addAll(existingSchema.getAllOf()); + if (schemaMap.get(entry.getKey()).getAllOf() != null){ + existingAllOf.addAll(schemaMap.get(entry.getKey()).getAllOf()); + existingSchema.setAllOf(new ArrayList<>(existingAllOf)); + } + } } components.setSchemas(componentSchemas); } @@ -207,8 +221,8 @@ public static Optional getContent(io.swagger.v3.oas.annotations.media.C * Merge schema. * * @param existingContent the existing content - * @param schemaN the schema n - * @param mediaTypeStr the media type str + * @param schemaN the schema n + * @param mediaTypeStr the media type str */ public static void mergeSchema(Content existingContent, Schema schemaN, String mediaTypeStr) { if (existingContent.containsKey(mediaTypeStr)) { @@ -322,7 +336,7 @@ private static void addExtension(io.swagger.v3.oas.annotations.media.Content ann * Sets examples. * * @param mediaType the media type - * @param examples the examples + * @param examples the examples */ private static void setExamples(MediaType mediaType, ExampleObject[] examples) { if (examples.length == 1 && StringUtils.isBlank(examples[0].name())) { @@ -436,7 +450,7 @@ private static boolean isArray(io.swagger.v3.oas.annotations.media.Content annot * Resolve default value object. * * @param defaultValueStr the default value str - * @param objectMapper the object mapper + * @param objectMapper the object mapper * @return the object */ public static Object resolveDefaultValue(String defaultValueStr, ObjectMapper objectMapper) { diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app222/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app222/HelloController.java new file mode 100644 index 000000000..0415f7911 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app222/HelloController.java @@ -0,0 +1,28 @@ +package test.org.springdoc.api.v30.app222; + + + +import test.org.springdoc.api.v30.app222.SpringDocApp222Test.FirstHierarchyUser; +import test.org.springdoc.api.v30.app222.SpringDocApp222Test.SecondHierarchyUser; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author bnasslahsen + */ + +@RestController +class HelloController { + + @GetMapping("/hello1") + public FirstHierarchyUser getItems1() { + return null; + } + + @GetMapping("/hello2") + public SecondHierarchyUser getItems2() { + return null; + } + +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app222/SpringDocApp222Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app222/SpringDocApp222Test.java new file mode 100644 index 000000000..d25dc5598 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app222/SpringDocApp222Test.java @@ -0,0 +1,55 @@ +/* + * + * * + * * * + * * * * + * * * * * Copyright 2019-2022 the original author or authors. + * * * * * + * * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * * you may not use this file except in compliance with the License. + * * * * * You may obtain a copy of the License at + * * * * * + * * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * * + * * * * * Unless required by applicable law or agreed to in writing, software + * * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * * See the License for the specific language governing permissions and + * * * * * limitations under the License. + * * * * + * * * + * * + * + */ + +package test.org.springdoc.api.v30.app222; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +public class SpringDocApp222Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} + + @JsonTypeInfo(use = Id.NAME, property = "@type") + @JsonSubTypes(@Type(CommonImplementor.class)) + interface FirstHierarchy {} + + @JsonTypeInfo(use = Id.NAME, property = "@type") + @JsonSubTypes(@Type(CommonImplementor.class)) + interface SecondHierarchy {} + + class CommonImplementor implements FirstHierarchy, SecondHierarchy {} + + record CommonImplementorUser(FirstHierarchy firstHierarchy, SecondHierarchy secondHierarchy) {} + + record FirstHierarchyUser(FirstHierarchy firstHierarchy) {} + + record SecondHierarchyUser(SecondHierarchy secondHierarchy) {} +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app222.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app222.json new file mode 100644 index 000000000..cd4de9975 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app222.json @@ -0,0 +1,122 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/hello2": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getItems2", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SecondHierarchyUser" + } + } + } + } + } + } + }, + "/hello1": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getItems1", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/FirstHierarchyUser" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "CommonImplementor": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/SecondHierarchy" + }, + { + "$ref": "#/components/schemas/FirstHierarchy" + } + ] + }, + "SecondHierarchy": { + "required": [ + "@type" + ], + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "discriminator": { + "propertyName": "@type" + } + }, + "SecondHierarchyUser": { + "type": "object", + "properties": { + "secondHierarchy": { + "oneOf": [ + { + "$ref": "#/components/schemas/CommonImplementor" + } + ] + } + } + }, + "FirstHierarchy": { + "required": [ + "@type" + ], + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "discriminator": { + "propertyName": "@type" + } + }, + "FirstHierarchyUser": { + "type": "object", + "properties": { + "firstHierarchy": { + "oneOf": [ + { + "$ref": "#/components/schemas/CommonImplementor" + } + ] + } + } + } + } + } +} From 935b984673cbfd7aa6633644304497760b0f4ffb Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sun, 30 Jun 2024 19:12:19 +0200 Subject: [PATCH 32/33] Polymorphic fields on polymorphic parents don't get correct oneOf docs generated. Fixes #2597 --- .../converters/PolymorphicModelConverter.java | 39 +- .../springdoc/core/utils/SpringDocUtils.java | 12 + .../api/v30/app223/ARestController.java | 23 ++ .../api/v30/app223/SpringDocApp223Test.java | 35 ++ .../v30/app223/apiobjects/AbstractChild.java | 61 +++ .../v30/app223/apiobjects/AbstractParent.java | 72 ++++ .../api/v30/app223/apiobjects/Response.java | 4 + .../test/resources/results/3.0.1/app223.json | 228 +++++++++++ .../src/test/resources/results/app105-3.json | 380 +++++++++--------- .../src/test/resources/results/app2.json | 14 +- 10 files changed, 666 insertions(+), 202 deletions(-) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/ARestController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/SpringDocApp223Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/AbstractChild.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/AbstractParent.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/Response.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app223.json diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java index eb9e04adb..e243f7e1a 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java @@ -27,9 +27,9 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JavaType; import io.swagger.v3.core.converter.AnnotatedType; @@ -43,6 +43,7 @@ /** * The type Polymorphic model converter. + * * @author bnasslahsen */ public class PolymorphicModelConverter implements ModelConverter { @@ -52,6 +53,17 @@ public class PolymorphicModelConverter implements ModelConverter { */ private final ObjectMapperProvider springDocObjectMapper; + /** + * The constant PARENT_TYPES_TO_IGNORE. + */ + private static final List PARENT_TYPES_TO_IGNORE = Collections.synchronizedList(new ArrayList<>()); + + static { + PARENT_TYPES_TO_IGNORE.add("JsonSchema"); + PARENT_TYPES_TO_IGNORE.add("Pageable"); + PARENT_TYPES_TO_IGNORE.add("EntityModel"); + } + /** * Instantiates a new Polymorphic model converter. * @@ -61,12 +73,21 @@ public PolymorphicModelConverter(ObjectMapperProvider springDocObjectMapper) { this.springDocObjectMapper = springDocObjectMapper; } - private static Schema getResolvedSchema(JavaType javaType, Schema resolvedSchema) { + /** + * Add parent type. + * + * @param parentTypes the parent types + */ + public static void addParentType(String... parentTypes) { + PARENT_TYPES_TO_IGNORE.addAll(List.of(parentTypes)); + } + + private Schema getResolvedSchema(JavaType javaType, Schema resolvedSchema) { if (resolvedSchema instanceof ObjectSchema && resolvedSchema.getProperties() != null) { - if (resolvedSchema.getProperties().containsKey(javaType.getRawClass().getName())){ + if (resolvedSchema.getProperties().containsKey(javaType.getRawClass().getName())) { resolvedSchema = resolvedSchema.getProperties().get(javaType.getRawClass().getName()); } - else if (resolvedSchema.getProperties().containsKey(javaType.getRawClass().getSimpleName())){ + else if (resolvedSchema.getProperties().containsKey(javaType.getRawClass().getSimpleName())) { resolvedSchema = resolvedSchema.getProperties().get(javaType.getRawClass().getSimpleName()); } } @@ -78,6 +99,9 @@ public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterato JavaType javaType = springDocObjectMapper.jsonMapper().constructType(type.getType()); if (javaType != null) { if (chain.hasNext()) { + if (!type.isResolveAsRef() && type.getParent() != null + && PARENT_TYPES_TO_IGNORE.stream().noneMatch(ignore -> type.getParent().getName().startsWith(ignore))) + type.resolveAsRef(true); Schema resolvedSchema = chain.next().resolve(type, context, chain); resolvedSchema = getResolvedSchema(javaType, resolvedSchema); if (resolvedSchema == null || resolvedSchema.get$ref() == null) @@ -91,8 +115,8 @@ public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterato /** * Compose polymorphic schema. * - * @param type the type - * @param schema the schema + * @param type the type + * @param schema the schema * @param schemas the schemas * @return the schema */ @@ -111,7 +135,7 @@ private Schema composePolymorphicSchema(AnnotatedType type, Schema schema, Colle /** * Find composed schemas recursively. * - * @param ref the reference of the schema + * @param ref the reference of the schema * @param schemas the collection of schemas to search in * @return the list of composed schemas */ @@ -133,6 +157,7 @@ private List findComposedSchemas(String ref, Collection schemas) return resultSchemas; } + /** * Is concrete class boolean. * diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/SpringDocUtils.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/SpringDocUtils.java index 09175e6e4..f1023e3c6 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/SpringDocUtils.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/SpringDocUtils.java @@ -32,6 +32,7 @@ import org.springdoc.api.AbstractOpenApiResource; import org.springdoc.core.converters.AdditionalModelsConverter; import org.springdoc.core.converters.ConverterUtils; +import org.springdoc.core.converters.PolymorphicModelConverter; import org.springdoc.core.converters.SchemaPropertyDeprecatingConverter; import org.springdoc.core.extractor.MethodParameterPojoExtractor; import org.springdoc.core.service.AbstractRequestService; @@ -388,5 +389,16 @@ public static boolean isValidPath(String path) { return true; return false; } + + /** + * Add parent type spring doc utils. + * + * @param parentTypes the parent types + * @return the spring doc utils + */ + public SpringDocUtils addParentType(String ...parentTypes) { + PolymorphicModelConverter.addParentType(parentTypes); + return this; + } } diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/ARestController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/ARestController.java new file mode 100644 index 000000000..8c672eb38 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/ARestController.java @@ -0,0 +1,23 @@ +package test.org.springdoc.api.v30.app223; + + +import test.org.springdoc.api.v30.app223.apiobjects.AbstractChild; +import test.org.springdoc.api.v30.app223.apiobjects.AbstractParent; +import test.org.springdoc.api.v30.app223.apiobjects.Response; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ARestController { + @PostMapping("/parent") + public Response parentEndpoint(@RequestBody AbstractParent parent) { + return null; + } + + @PostMapping("/child") + public Response childEndpoint(@RequestBody AbstractChild child) { + return null; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/SpringDocApp223Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/SpringDocApp223Test.java new file mode 100644 index 000000000..ce55a35c6 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/SpringDocApp223Test.java @@ -0,0 +1,35 @@ +/* + * + * * + * * * + * * * * + * * * * * Copyright 2019-2022 the original author or authors. + * * * * * + * * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * * you may not use this file except in compliance with the License. + * * * * * You may obtain a copy of the License at + * * * * * + * * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * * + * * * * * Unless required by applicable law or agreed to in writing, software + * * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * * See the License for the specific language governing permissions and + * * * * * limitations under the License. + * * * * + * * * + * * + * + */ + +package test.org.springdoc.api.v30.app223; + +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +public class SpringDocApp223Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/AbstractChild.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/AbstractChild.java new file mode 100644 index 000000000..de53786c3 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/AbstractChild.java @@ -0,0 +1,61 @@ +package test.org.springdoc.api.v30.app223.apiobjects; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +@JsonTypeInfo(use = Id.NAME, property = "type") +@JsonSubTypes({ + @Type(ChildType1.class), + @Type(ChildType2.class) +}) +public abstract class AbstractChild { + private int id; + + public AbstractChild(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } +} + + class ChildType1 extends AbstractChild { + private String childType1Param; + + public ChildType1(int id, String childType1Param) { + super(id); + this.childType1Param = childType1Param; + } + + public String getChildType1Param() { + return childType1Param; + } + + public void setChildType1Param(String childType1Param) { + this.childType1Param = childType1Param; + } +} + +class ChildType2 extends AbstractChild { + private String childType2Param; + + public ChildType2(int id, String childType2Param) { + super(id); + this.childType2Param = childType2Param; + } + + public String getChildType2Param() { + return childType2Param; + } + + public void setChildType2Param(String childType2Param) { + this.childType2Param = childType2Param; + } +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/AbstractParent.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/AbstractParent.java new file mode 100644 index 000000000..73795f768 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/AbstractParent.java @@ -0,0 +1,72 @@ +package test.org.springdoc.api.v30.app223.apiobjects; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + + +@JsonTypeInfo(use = Id.NAME, property = "type") +@JsonSubTypes({ + @Type(ParentType1.class), + @Type(ParentType2.class) +}) +public abstract class AbstractParent { + private int id; + + public AbstractParent(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } +} + +class ParentType1 extends AbstractParent { + private String parentType1Param; + private AbstractChild abstractChild; + + public ParentType1(int id, String parentType1Param, AbstractChild abstractChild) { + super(id); + this.parentType1Param = parentType1Param; + this.abstractChild = abstractChild; + } + + public String getParentType1Param() { + return parentType1Param; + } + + public void setParentType1Param(String parentType1Param) { + this.parentType1Param = parentType1Param; + } + + public AbstractChild getAbstractChild() { + return abstractChild; + } + + public void setAbstractChild(AbstractChild abstractChild) { + this.abstractChild = abstractChild; + } +} + +class ParentType2 extends AbstractParent { + private String parentType2Param; + + public ParentType2(int id, String parentType2Param) { + super(id); + this.parentType2Param = parentType2Param; + } + + public String getParentType2Param() { + return parentType2Param; + } + + public void setParentType2Param(String parentType2Param) { + this.parentType2Param = parentType2Param; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/Response.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/Response.java new file mode 100644 index 000000000..71dfdf576 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app223/apiobjects/Response.java @@ -0,0 +1,4 @@ +package test.org.springdoc.api.v30.app223.apiobjects; + +public record Response(AbstractParent abstractParent, AbstractChild abstractChild) { +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app223.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app223.json new file mode 100644 index 000000000..31ab9d5f6 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app223.json @@ -0,0 +1,228 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/parent": { + "post": { + "tags": [ + "a-rest-controller" + ], + "operationId": "parentEndpoint", + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ParentType1" + }, + { + "$ref": "#/components/schemas/ParentType2" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Response" + } + } + } + } + } + } + }, + "/child": { + "post": { + "tags": [ + "a-rest-controller" + ], + "operationId": "childEndpoint", + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ChildType1" + }, + { + "$ref": "#/components/schemas/ChildType2" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Response" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "AbstractChild": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "string" + } + }, + "discriminator": { + "propertyName": "type" + } + }, + "AbstractParent": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "string" + } + }, + "discriminator": { + "propertyName": "type" + } + }, + "ChildType1": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/AbstractChild" + }, + { + "type": "object", + "properties": { + "childType1Param": { + "type": "string" + } + } + } + ] + }, + "ChildType2": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/AbstractChild" + }, + { + "type": "object", + "properties": { + "childType2Param": { + "type": "string" + } + } + } + ] + }, + "ParentType1": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/AbstractParent" + }, + { + "type": "object", + "properties": { + "parentType1Param": { + "type": "string" + }, + "abstractChild": { + "oneOf": [ + { + "$ref": "#/components/schemas/ChildType1" + }, + { + "$ref": "#/components/schemas/ChildType2" + } + ] + } + } + } + ] + }, + "ParentType2": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/AbstractParent" + }, + { + "type": "object", + "properties": { + "parentType2Param": { + "type": "string" + } + } + } + ] + }, + "Response": { + "type": "object", + "properties": { + "abstractParent": { + "oneOf": [ + { + "$ref": "#/components/schemas/ParentType1" + }, + { + "$ref": "#/components/schemas/ParentType2" + } + ] + }, + "abstractChild": { + "oneOf": [ + { + "$ref": "#/components/schemas/ChildType1" + }, + { + "$ref": "#/components/schemas/ChildType2" + } + ] + } + } + } + } + } +} diff --git a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app105-3.json b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app105-3.json index bccc4af1b..ff9c8392e 100644 --- a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app105-3.json +++ b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app105-3.json @@ -34,12 +34,12 @@ "requestBody": { "description": "Pet object that needs to be added to the store", "content": { - "application/json": { + "application/xml": { "schema": { "$ref": "#/components/schemas/Pet" } }, - "application/xml": { + "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } @@ -87,12 +87,12 @@ "requestBody": { "description": "Pet object that needs to be added to the store", "content": { - "application/json": { + "application/xml": { "schema": { "$ref": "#/components/schemas/Pet" } }, - "application/xml": { + "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } @@ -128,142 +128,6 @@ ] } }, - "/pet/findByStatus": { - "get": { - "tags": [ - "pet" - ], - "summary": "Finds Pets by status", - "description": "Multiple status values can be provided with comma separated strings", - "operationId": "findPetsByStatus", - "parameters": [ - { - "name": "status", - "in": "query", - "description": "Status values that need to be considered for filter", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - ], - "responses": { - "200": { - "description": "successful operation", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Pet" - } - } - }, - "application/xml": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Pet" - } - } - } - } - }, - "400": { - "description": "Invalid status value", - "content": { - "*/*": { - "schema": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - }, - "security": [ - { - "petstore_auth": [ - "write:pets", - "read:pets" - ] - } - ] - } - }, - "/pet/findByTags": { - "get": { - "tags": [ - "pet" - ], - "summary": "Finds Pets by tags", - "description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", - "operationId": "findPetsByTags", - "parameters": [ - { - "name": "tags", - "in": "query", - "description": "Tags to filter by", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - ], - "responses": { - "200": { - "description": "successful operation", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Pet" - } - } - }, - "application/xml": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Pet" - } - } - } - } - }, - "400": { - "description": "Invalid tag value", - "content": { - "*/*": { - "schema": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - }, - "security": [ - { - "petstore_auth": [ - "write:pets", - "read:pets" - ] - } - ] - } - }, "/pet/{petId}": { "get": { "tags": [ @@ -285,21 +149,6 @@ } ], "responses": { - "200": { - "description": "successful operation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Pet" - } - }, - "application/xml": { - "schema": { - "$ref": "#/components/schemas/Pet" - } - } - } - }, "400": { "description": "Invalid ID supplied", "content": { @@ -316,15 +165,30 @@ "404": { "description": "Pet not found", "content": { - "application/json": { + "application/xml": { "schema": { "$ref": "#/components/schemas/Pet" } }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "200": { + "description": "successful operation", + "content": { "application/xml": { "schema": { "$ref": "#/components/schemas/Pet" } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } } } } @@ -504,6 +368,19 @@ } }, "responses": { + "400": { + "description": "the map", + "content": { + "*/*": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + }, "200": { "description": "successful operation", "content": { @@ -513,9 +390,111 @@ } } } + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + }, + "/pet/findByTags": { + "get": { + "tags": [ + "pet" + ], + "summary": "Finds Pets by tags", + "description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + "operationId": "findPetsByTags", + "parameters": [ + { + "name": "tags", + "in": "query", + "description": "Tags to filter by", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "400": { + "description": "Invalid tag value", + "content": { + "*/*": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } }, + "200": { + "description": "successful operation", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + }, + "/pet/findByStatus": { + "get": { + "tags": [ + "pet" + ], + "summary": "Finds Pets by status", + "description": "Multiple status values can be provided with comma separated strings", + "operationId": "findPetsByStatus", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "Status values that need to be considered for filter", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { "400": { - "description": "the map", + "description": "Invalid status value", "content": { "*/*": { "schema": { @@ -526,6 +505,27 @@ } } } + }, + "200": { + "description": "successful operation", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } } }, "security": [ @@ -553,26 +553,8 @@ "type": "string", "description": "The Name." } - } - }, - "ModelApiResponse": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "description": "The Code.", - "format": "int32" - }, - "message": { - "type": "string", - "description": "The Message." - }, - "type": { - "type": "string", - "description": "The Type." - } }, - "description": "The type Model api response." + "description": "The type Category." }, "Pet": { "required": [ @@ -581,14 +563,14 @@ ], "type": "object", "properties": { - "category": { - "$ref": "#/components/schemas/Category" - }, "id": { "type": "integer", "description": "The Id.", "format": "int64" }, + "category": { + "$ref": "#/components/schemas/Category" + }, "name": { "type": "string", "description": "The Name.", @@ -601,6 +583,13 @@ "type": "string" } }, + "tags": { + "type": "array", + "description": "The Tags.", + "items": { + "$ref": "#/components/schemas/Tag" + } + }, "status": { "type": "string", "description": "pet status in the store", @@ -609,13 +598,6 @@ "pending", "sold" ] - }, - "tags": { - "type": "array", - "description": "The Tags.", - "items": { - "$ref": "#/components/schemas/Tag" - } } }, "description": "The type Pet." @@ -632,7 +614,27 @@ "type": "string", "description": "The Name." } - } + }, + "description": "The type Tag." + }, + "ModelApiResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "The Code.", + "format": "int32" + }, + "type": { + "type": "string", + "description": "The Type." + }, + "message": { + "type": "string", + "description": "The Message." + } + }, + "description": "The type Model api response." } }, "securitySchemes": { @@ -646,8 +648,8 @@ "implicit": { "authorizationUrl": "http://petstore.swagger.io/oauth/dialog", "scopes": { - "read:pets": "read your pets", - "write:pets": "modify pets in your account" + "write:pets": "modify pets in your account", + "read:pets": "read your pets" } } } diff --git a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app2.json b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app2.json index a0c5620f9..3a0de8a56 100644 --- a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app2.json +++ b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/app2.json @@ -193,12 +193,12 @@ "requestBody": { "description": "Pet object that needs to be added to the store", "content": { - "application/json": { + "application/xml": { "schema": { "$ref": "#/components/schemas/Pet" } }, - "application/xml": { + "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } @@ -246,12 +246,12 @@ "requestBody": { "description": "Pet object that needs to be added to the store", "content": { - "application/json": { + "application/xml": { "schema": { "$ref": "#/components/schemas/Pet" } }, - "application/xml": { + "application/json": { "schema": { "$ref": "#/components/schemas/Pet" } @@ -1163,7 +1163,8 @@ "type": "string", "description": "The Name." } - } + }, + "description": "The type Category." }, "Pet": { "required": [ @@ -1223,7 +1224,8 @@ "type": "string", "description": "The Name." } - } + }, + "description": "The type Tag." }, "Order": { "type": "object", From c1523b5265acc40cfd6af8f9493bd5eb28268d5a Mon Sep 17 00:00:00 2001 From: jenkins Date: Sun, 30 Jun 2024 18:08:46 +0000 Subject: [PATCH 33/33] [maven-release-plugin] prepare release v2.6.0 --- pom.xml | 4 ++-- springdoc-openapi-starter-common/pom.xml | 2 +- springdoc-openapi-starter-webflux-api/pom.xml | 2 +- springdoc-openapi-starter-webflux-ui/pom.xml | 2 +- springdoc-openapi-starter-webmvc-api/pom.xml | 2 +- springdoc-openapi-starter-webmvc-ui/pom.xml | 2 +- springdoc-openapi-tests/pom.xml | 2 +- .../springdoc-openapi-actuator-webflux-tests/pom.xml | 2 +- .../springdoc-openapi-actuator-webmvc-tests/pom.xml | 2 +- .../springdoc-openapi-data-rest-tests/pom.xml | 2 +- .../springdoc-openapi-function-webflux-tests/pom.xml | 2 +- .../springdoc-openapi-function-webmvc-tests/pom.xml | 2 +- .../springdoc-openapi-groovy-tests/pom.xml | 2 +- .../springdoc-openapi-hateoas-tests/pom.xml | 2 +- .../springdoc-openapi-javadoc-tests/pom.xml | 2 +- .../springdoc-openapi-kotlin-webflux-tests/pom.xml | 2 +- .../springdoc-openapi-kotlin-webmvc-tests/pom.xml | 2 +- .../springdoc-openapi-security-tests/pom.xml | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/pom.xml b/pom.xml index 05ca7eee9..0f2d9d8ba 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.springdoc springdoc-openapi - 2.5.1-SNAPSHOT + 2.6.0 pom Spring openapi documentation Spring openapi documentation @@ -35,7 +35,7 @@ scm:git:git@github.com:springdoc/springdoc-openapi.git scm:git:git@github.com:springdoc/springdoc-openapi.git - HEAD + v2.6.0 diff --git a/springdoc-openapi-starter-common/pom.xml b/springdoc-openapi-starter-common/pom.xml index 94c8ccfce..bdd9a305d 100644 --- a/springdoc-openapi-starter-common/pom.xml +++ b/springdoc-openapi-starter-common/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi - 2.5.1-SNAPSHOT + 2.6.0 springdoc-openapi-starter-common diff --git a/springdoc-openapi-starter-webflux-api/pom.xml b/springdoc-openapi-starter-webflux-api/pom.xml index d83221c8c..550254788 100644 --- a/springdoc-openapi-starter-webflux-api/pom.xml +++ b/springdoc-openapi-starter-webflux-api/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi - 2.5.1-SNAPSHOT + 2.6.0 springdoc-openapi-starter-webflux-api diff --git a/springdoc-openapi-starter-webflux-ui/pom.xml b/springdoc-openapi-starter-webflux-ui/pom.xml index 26ddadf7a..0f5a75883 100644 --- a/springdoc-openapi-starter-webflux-ui/pom.xml +++ b/springdoc-openapi-starter-webflux-ui/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi - 2.5.1-SNAPSHOT + 2.6.0 springdoc-openapi-starter-webflux-ui diff --git a/springdoc-openapi-starter-webmvc-api/pom.xml b/springdoc-openapi-starter-webmvc-api/pom.xml index 8ffe7c7db..0fafe6f0b 100644 --- a/springdoc-openapi-starter-webmvc-api/pom.xml +++ b/springdoc-openapi-starter-webmvc-api/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi - 2.5.1-SNAPSHOT + 2.6.0 springdoc-openapi-starter-webmvc-api diff --git a/springdoc-openapi-starter-webmvc-ui/pom.xml b/springdoc-openapi-starter-webmvc-ui/pom.xml index 1f1c56b89..3d5f5fd3d 100644 --- a/springdoc-openapi-starter-webmvc-ui/pom.xml +++ b/springdoc-openapi-starter-webmvc-ui/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi - 2.5.1-SNAPSHOT + 2.6.0 springdoc-openapi-starter-webmvc-ui diff --git a/springdoc-openapi-tests/pom.xml b/springdoc-openapi-tests/pom.xml index f62280958..7db59be14 100644 --- a/springdoc-openapi-tests/pom.xml +++ b/springdoc-openapi-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi org.springdoc - 2.5.1-SNAPSHOT + 2.6.0 pom 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml index 933aadce0..e4773b39b 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.1-SNAPSHOT + 2.6.0 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml index e719c73cf..62fe7665c 100644 --- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.1-SNAPSHOT + 2.6.0 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml index c937bd6fe..6d65af1dc 100644 --- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.1-SNAPSHOT + 2.6.0 4.0.0 springdoc-openapi-data-rest-tests diff --git a/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml index 24f81f82c..059a207db 100644 --- a/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.1-SNAPSHOT + 2.6.0 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml index 34d734fdb..e3b01e3ba 100644 --- a/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.1-SNAPSHOT + 2.6.0 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml index 4435adfad..f37fe303c 100644 --- a/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi-tests - 2.5.1-SNAPSHOT + 2.6.0 springdoc-openapi-groovy-tests diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml index ca833c0ec..75a2200e1 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.1-SNAPSHOT + 2.6.0 4.0.0 springdoc-openapi-hateoas-tests diff --git a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml index a657bd3df..5499ce7d1 100644 --- a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml @@ -2,7 +2,7 @@ org.springdoc springdoc-openapi-tests - 2.5.1-SNAPSHOT + 2.6.0 4.0.0 diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml index 214de16ee..c16a98152 100644 --- a/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.1-SNAPSHOT + 2.6.0 4.0.0 springdoc-openapi-kotlin-webflux-tests diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml index 14818297f..d1fc090ec 100644 --- a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml @@ -2,7 +2,7 @@ springdoc-openapi-tests org.springdoc - 2.5.1-SNAPSHOT + 2.6.0 4.0.0 springdoc-openapi-kotlin-webmvc-tests diff --git a/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml index 9ef3caf3f..ee932d0be 100644 --- a/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml +++ b/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml @@ -3,7 +3,7 @@ org.springdoc springdoc-openapi-tests - 2.5.1-SNAPSHOT + 2.6.0 springdoc-openapi-security-tests