From 5300c497d2b30c23160af31da12932ad5096ae57 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 15 Jul 2023 16:24:00 +0900 Subject: [PATCH] feat: Added function to preload by specifying locale --- .../api/AbstractOpenApiResource.java | 13 +- .../properties/SpringDocConfigProperties.java | 24 ++- .../api/v30/app209/HelloController.java | 70 ++++++ .../api/v30/app209/SpringDocApp209Test.java | 114 ++++++++++ .../test/resources/results/3.0.1/app209.json | 203 ++++++++++++++++++ 5 files changed, 418 insertions(+), 6 deletions(-) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app209/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app209/SpringDocApp209Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app209.json diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java index a553dccb1..fb58b1409 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java @@ -3,7 +3,7 @@ * * * * * * * * * - * * * * * Copyright 2019-2022 the original author or authors. + * * * * * 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. @@ -226,8 +226,15 @@ protected AbstractOpenApiResource(String groupName, ObjectFactory this.getOpenApi(Locale.forLanguageTag(locale))); + } + } + } } /** diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SpringDocConfigProperties.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SpringDocConfigProperties.java index 41abcdecd..5c01b4eff 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SpringDocConfigProperties.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SpringDocConfigProperties.java @@ -3,7 +3,7 @@ * * * * * * * * * - * * * * * Copyright 2019-2022 the original author or authors. + * * * * * 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. @@ -167,6 +167,11 @@ public class SpringDocConfigProperties { */ private boolean preLoadingEnabled; + /** + * locale list to pre-loading + */ + private List preLoadingLocales; + /** * If set to true, exposes the swagger-ui on the actuator management port. */ @@ -949,14 +954,27 @@ public boolean isPreLoadingEnabled() { } /** - * Sets pre loading enabled. + * locale list to pre-loading. + * + * @return the Locales + */ + public List getPreLoadingLocales() { + return preLoadingLocales; + } + + /** + * Sets locale list to pre-loading. * - * @param preLoadingEnabled the pre loading enabled + * @param preLoadingEnabled the Locales */ public void setPreLoadingEnabled(boolean preLoadingEnabled) { this.preLoadingEnabled = preLoadingEnabled; } + public void setPreLoadingLocales(List preLoadingLocales) { + this.preLoadingLocales = preLoadingLocales; + } + /** * The type Model converters. * diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app209/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app209/HelloController.java new file mode 100644 index 000000000..79a6c6121 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app209/HelloController.java @@ -0,0 +1,70 @@ +/* + * + * * + * * * + * * * * + * * * * * 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.v30.app209; + +import io.swagger.v3.oas.annotations.Parameter; +import jakarta.validation.constraints.NegativeOrZero; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.PositiveOrZero; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HelloController { + + @GetMapping(value = "/persons") + public String persons(@NotBlank String name) { + return "OK"; + } + + @GetMapping(value = "/persons2") + public String persons2(@NotBlank @Parameter(description = "persons name") String name) { + return "OK"; + } + + @GetMapping(value = "/persons3") + public String persons3(@NotBlank @Parameter(description = "persons name") @RequestParam String name) { + return "OK"; + } + + @GetMapping(value = "/persons4") + public String persons4(@PositiveOrZero int age) { + return "OK"; + } + + @GetMapping(value = "/persons5") + public String persons5(@NegativeOrZero int age) { + return "OK"; + } + + @GetMapping(value = "/persons6") + public String persons6(@NotEmpty @Parameter(description = "persons name") String name) { + return "OK"; + } + +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app209/SpringDocApp209Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app209/SpringDocApp209Test.java new file mode 100644 index 000000000..dc74d703f --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app209/SpringDocApp209Test.java @@ -0,0 +1,114 @@ +/* + * + * * + * * * + * * * * + * * * * * 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.v30.app209; + +import java.util.List; +import java.util.Locale; +import java.util.Optional; + +import io.swagger.v3.oas.models.OpenAPI; +import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import org.springdoc.core.customizers.OpenApiBuilderCustomizer; +import org.springdoc.core.customizers.ServerBaseUrlCustomizer; +import org.springdoc.core.properties.SpringDocConfigProperties; +import org.springdoc.core.providers.JavadocProvider; +import org.springdoc.core.service.OpenAPIService; +import org.springdoc.core.service.SecurityService; +import org.springdoc.core.utils.Constants; +import org.springdoc.core.utils.PropertyResolverUtils; +import test.org.springdoc.api.AbstractCommonTest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpHeaders; +import org.springframework.test.web.servlet.MvcResult; + +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(properties = { + "springdoc.pre-loading-enabled=true", + "springdoc.pre-loading-locales=ja" +}) +public class SpringDocApp209Test extends AbstractCommonTest { + public static String className; + + static { + System.setProperty("user.country", "JP"); + System.setProperty("user.language", "ja"); + } + + @Autowired + private OpenAPIServiceMock openAPIService; + + @SpringBootApplication + static class SpringDocTestApp { + @Bean("openAPIService") + public OpenAPIServiceMock openAPIService(Optional openAPI, SecurityService securityParser, SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, Optional> openApiBuilderCustomizers, Optional> serverBaseUrlCustomizers, Optional javadocProvider) { + return new OpenAPIServiceMock(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); + } + } + + public static class OpenAPIServiceMock extends OpenAPIService { + private int numberOfTimesCalculatePathWasCalled; + + public OpenAPIServiceMock(Optional openAPI, SecurityService securityParser, SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, Optional> openApiBuilderCustomizers, Optional> serverBaseUrlCustomizers, Optional javadocProvider) { + super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); + } + + @Override + public void setCachedOpenAPI(OpenAPI cachedOpenAPI, Locale locale) { + numberOfTimesCalculatePathWasCalled++; + super.setCachedOpenAPI(cachedOpenAPI, locale); + } + + public int getNumberOfTimesCalculatePathWasCalled() { + return numberOfTimesCalculatePathWasCalled; + } + } + + @Test + public void shouldOnlyByCalledOnce() throws Exception { + assertEquals(1, openAPIService.getNumberOfTimesCalculatePathWasCalled()); + + className = getClass().getSimpleName(); + String testNumber = className.replaceAll("[^0-9]", ""); + MvcResult mockMvcResult = mockMvc + .perform(get(Constants.DEFAULT_API_DOCS_URL).header(HttpHeaders.ACCEPT_LANGUAGE, "ja")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.openapi", is("3.0.1"))).andReturn(); + String result = mockMvcResult.getResponse().getContentAsString(); + String expected = getContent("results/3.0.1/app" + testNumber + ".json"); + JSONAssert.assertEquals(expected, result, true); + + assertEquals(1, openAPIService.getNumberOfTimesCalculatePathWasCalled()); + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app209.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app209.json new file mode 100644 index 000000000..52c543602 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app209.json @@ -0,0 +1,203 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/persons3": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "persons3", + "parameters": [ + { + "name": "name", + "in": "query", + "description": "persons name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/persons5": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "persons5", + "parameters": [ + { + "name": "age", + "in": "query", + "required": true, + "schema": { + "maximum": 0, + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/persons4": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "persons4", + "parameters": [ + { + "name": "age", + "in": "query", + "required": true, + "schema": { + "minimum": 0, + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/persons2": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "persons2", + "parameters": [ + { + "name": "name", + "in": "query", + "description": "persons name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/persons6": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "persons6", + "parameters": [ + { + "name": "name", + "in": "query", + "description": "persons name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/persons": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "persons", + "parameters": [ + { + "name": "name", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +}