From def90dd939081b79e2c810b9ec305d798f720f6d Mon Sep 17 00:00:00 2001 From: TAEWOOKK Date: Sat, 1 Nov 2025 21:29:57 +0900 Subject: [PATCH 01/13] feat: Add @EnumDescription annotation for automatic enum --- .../core/annotations/EnumDescription.java | 51 +++++ .../configuration/SpringDocConfiguration.java | 13 ++ .../EnumDescriptionOperationCustomizer.java | 188 ++++++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 springdoc-openapi-starter-common/src/main/java/org/springdoc/core/annotations/EnumDescription.java create mode 100644 springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/EnumDescriptionOperationCustomizer.java diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/annotations/EnumDescription.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/annotations/EnumDescription.java new file mode 100644 index 000000000..aa4fef21e --- /dev/null +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/annotations/EnumDescription.java @@ -0,0 +1,51 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Scans an Enum class from the annotated field and automatically adds its constants + * and descriptions to the OpenAPI documentation. + * + * @author TAEWOOKK + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface EnumDescription { + + /** + * The field name in the Enum class to read for description. + * If left empty (default), the library will attempt to find "description" field. + * + * @return The name of the field to read (e.g., "label", "description", "value"). + */ + String fieldName() default ""; +} diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java index 9bdbd742d..2a245ea26 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java @@ -75,6 +75,7 @@ import org.springdoc.core.customizers.RouterOperationCustomizer; import org.springdoc.core.customizers.ServerBaseUrlCustomizer; import org.springdoc.core.customizers.SpringDocCustomizers; +import org.springdoc.core.customizers.EnumDescriptionOperationCustomizer; import org.springdoc.core.discoverer.SpringDocParameterNameDiscoverer; import org.springdoc.core.extractor.MethodParameterPojoExtractor; import org.springdoc.core.filters.GlobalOpenApiMethodFilter; @@ -717,4 +718,16 @@ SchemaUtils schemaUtils(Optional springDocKotlinUtils){ MethodParameterPojoExtractor methodParameterPojoExtractor(SchemaUtils schemaUtils){ return new MethodParameterPojoExtractor(schemaUtils); } + + /** + * Enum description operation customizer. + * + * @return the enum description operation customizer + */ + @Bean + @ConditionalOnMissingBean + @Lazy(false) + GlobalOperationCustomizer enumDescriptionOperationCustomizer() { + return new EnumDescriptionOperationCustomizer(); + } } diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/EnumDescriptionOperationCustomizer.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/EnumDescriptionOperationCustomizer.java new file mode 100644 index 000000000..5f829afa4 --- /dev/null +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/EnumDescriptionOperationCustomizer.java @@ -0,0 +1,188 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.customizers; + +import io.swagger.v3.oas.models.Operation; +import org.apache.commons.lang3.StringUtils; +import org.springdoc.core.annotations.EnumDescription; +import org.springdoc.core.service.AbstractRequestService; +import org.springframework.core.MethodParameter; +import org.springframework.web.method.HandlerMethod; + +import java.lang.reflect.Field; + +/** + * The type Enum description operation customizer. + * Automatically adds enum constants and descriptions to operation. + * when fields are annotated with {@link EnumDescription}. + * + * @author TAEWOOKK + */ +public class EnumDescriptionOperationCustomizer implements GlobalOperationCustomizer{ + + /** + * The constant DEFAULT_FIELD_NAME. + */ + private static final String DEFAULT_FIELD_NAME = "description"; + + @Override + public Operation customize(Operation operation, HandlerMethod handlerMethod) { + if (operation == null || handlerMethod == null) { + return operation; + } + + for (MethodParameter methodParameter : handlerMethod.getMethodParameters()) { + Class dtoClass = methodParameter.getParameterType(); + + if (!isValidDtoClass(dtoClass)) { + continue; + } + + String enumDescriptions = extractEnumDescriptionsFromDto(dtoClass); + if (StringUtils.isNotBlank(enumDescriptions)) { + String existingDescription = operation.getDescription(); + String newDescription = StringUtils.isNotBlank(existingDescription) + ? existingDescription + "\n\n" + enumDescriptions + : enumDescriptions; + operation.setDescription(newDescription); + } + } + + return operation; + } + + /** + * Is valid dto class boolean. + * + * @param clazz the clazz + * @return the boolean + */ + private boolean isValidDtoClass(Class clazz) { + return !clazz.isPrimitive() + && !clazz.isEnum() + && !clazz.isArray() + && !clazz.isInterface() + && !clazz.getName().startsWith("java.") + && !AbstractRequestService.isRequestTypeToIgnore(clazz); + } + + /** + * Extract enum descriptions from dto string. + * + * @param dtoClass the dto class + * @return the string + */ + private String extractEnumDescriptionsFromDto(Class dtoClass) { + if (dtoClass == null) { + return null; + } + + StringBuilder result = new StringBuilder(); + Class currentClass = dtoClass; + + while (currentClass != null && !currentClass.getName().startsWith("java.")) { + for (Field field : currentClass.getDeclaredFields()) { + EnumDescription annotation = field.getAnnotation(EnumDescription.class); + + if (annotation != null && field.getType().isEnum()) { + String enumDescriptionText = extractEnumDescription( + field.getType(), + annotation.fieldName(), + field.getName() + ); + + if (StringUtils.isNotBlank(enumDescriptionText)) { + if (!result.isEmpty()) { + result.append("\n\n"); + } + result.append(enumDescriptionText); + } + } + } + currentClass = currentClass.getSuperclass(); + } + + return !result.isEmpty() ? result.toString() : null; + } + + /** + * Extract enum description string. + * + * @param enumClass the enum class + * @param fieldName the field name + * @param fieldDisplayName the field display name + * @return the string + */ + private String extractEnumDescription(Class enumClass, + String fieldName, + String fieldDisplayName) { + Object[] enumConstants = enumClass.getEnumConstants(); + if (enumConstants == null || enumConstants.length == 0) { + return null; + } + + StringBuilder sb = new StringBuilder(); + sb.append("**").append(fieldDisplayName).append("**\n"); + + for (Object enumConstant : enumConstants) { + String enumKey = ((Enum) enumConstant).name(); + String description = getEnumDescription(enumConstant, fieldName); + + sb.append("- `").append(enumKey).append("`"); + if (StringUtils.isNotBlank(description)) { + sb.append(": ").append(description); + } + sb.append("\n"); + } + + return sb.toString(); + } + + /** + * Gets enum description string. + * + * @param enumConstant the enum constant + * @param fieldName the field name + * @return the string + */ + private String getEnumDescription(Object enumConstant, String fieldName) { + if (enumConstant == null) { + return ""; + } + + String targetFieldName = StringUtils.isNotBlank(fieldName) ? fieldName : DEFAULT_FIELD_NAME; + + try { + Field field = enumConstant.getClass().getDeclaredField(targetFieldName); + field.setAccessible(true); + Object value = field.get(enumConstant); + return value != null ? value.toString() : ""; + } catch (NoSuchFieldException | IllegalAccessException e) { + return ""; + } + } +} From 29d980b7f38128990adb829347cac5339f03289a Mon Sep 17 00:00:00 2001 From: TAEWOOKK Date: Mon, 3 Nov 2025 23:34:02 +0900 Subject: [PATCH 02/13] test: Add tests for EnumDescription feature --- .../springdoc/ui/app36/HelloController.java | 44 ++++++++++ .../test/org/springdoc/ui/app36/Priority.java | 42 ++++++++++ .../ui/app36/SpringDocApp36Test.java | 83 +++++++++++++++++++ .../test/org/springdoc/ui/app36/Status.java | 42 ++++++++++ .../org/springdoc/ui/app36/TestRequest.java | 42 ++++++++++ .../org/springdoc/ui/app36/TestRequest2.java | 42 ++++++++++ 6 files changed, 295 insertions(+) create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Priority.java create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Status.java create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest.java create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest2.java diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java new file mode 100644 index 000000000..5b37966ba --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java @@ -0,0 +1,44 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +import org.springframework.web.bind.annotation.GetMapping; +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("/test") + public void test(@RequestBody TestRequest request) { + } + + @GetMapping("/test2") + public void test2(TestRequest2 request) { + } +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Priority.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Priority.java new file mode 100644 index 000000000..20a46b930 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Priority.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +public enum Priority { + HIGH("High priority"), + LOW("Low priority"); + + private final String label; + + Priority(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } +} diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java new file mode 100644 index 000000000..74d399ab2 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java @@ -0,0 +1,83 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.test.web.servlet.MvcResult; +import test.org.springdoc.ui.AbstractSpringDocTest; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public class SpringDocApp36Test extends AbstractSpringDocTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testEnumDescription() throws Exception { + MvcResult result = mockMvc.perform(get("/v3/api-docs")) + .andExpect(status().isOk()) + .andReturn(); + + String content = result.getResponse().getContentAsString(); + JsonNode jsonNode = objectMapper.readTree(content); + + String description = jsonNode.at("/paths/~1test/post/description").asText(""); + + assertTrue(description.contains("**status**"), "Should contain status enum description"); + assertTrue(description.contains("`ACTIVE`"), "Should contain ACTIVE enum value"); + assertTrue(description.contains("`INACTIVE`"), "Should contain INACTIVE enum value"); + assertTrue(description.contains("Active status"), "Should contain ACTIVE description"); + assertTrue(description.contains("Inactive status"), "Should contain INACTIVE description"); + } + + @Test + void testEnumDescriptionWithCustomFieldName() throws Exception { + MvcResult result = mockMvc.perform(get("/v3/api-docs")) + .andExpect(status().isOk()) + .andReturn(); + + String content = result.getResponse().getContentAsString(); + JsonNode jsonNode = objectMapper.readTree(content); + + String description = jsonNode.at("/paths/~1test2/get/description").asText(""); + + assertTrue(description.contains("**priority**"), "Should contain priority enum description"); + assertTrue(description.contains("`HIGH`"), "Should contain HIGH enum value"); + assertTrue(description.contains("`LOW`"), "Should contain LOW enum value"); + assertTrue(description.contains("High priority"), "Should contain HIGH label from custom field"); + assertTrue(description.contains("Low priority"), "Should contain LOW label from custom field"); + } + + @SpringBootApplication + static class SpringDocTestApp { + } +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Status.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Status.java new file mode 100644 index 000000000..cb882ede4 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Status.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +public enum Status { + ACTIVE("Active status"), + INACTIVE("Inactive status"); + + private final String description; + + Status(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest.java new file mode 100644 index 000000000..72a52d9db --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +import org.springdoc.core.annotations.EnumDescription; + +public class TestRequest { + @EnumDescription + private Status status; + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } +} diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest2.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest2.java new file mode 100644 index 000000000..89beaf23e --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest2.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +import org.springdoc.core.annotations.EnumDescription; + +public class TestRequest2 { + @EnumDescription(fieldName = "label") + private Priority priority; + + public Priority getPriority() { + return priority; + } + + public void setPriority(Priority priority) { + this.priority = priority; + } +} From 3e41f2445598cbd755893626ec0ebada1df6724e Mon Sep 17 00:00:00 2001 From: TAEWOOKK Date: Sun, 9 Nov 2025 14:12:32 +0900 Subject: [PATCH 03/13] test: Add tests for EnumDescription on webmvc-api --- .../api/v30/app244/HelloController.java | 44 ++++++++++ .../springdoc/api/v30/app244/Priority.java | 42 ++++++++++ .../api/v30/app244/SpringDocApp36Test.java | 83 +++++++++++++++++++ .../org/springdoc/api/v30/app244/Status.java | 42 ++++++++++ .../springdoc/api/v30/app244/TestRequest.java | 42 ++++++++++ .../api/v30/app244/TestRequest2.java | 42 ++++++++++ 6 files changed, 295 insertions(+) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Priority.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Status.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest2.java diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java new file mode 100644 index 000000000..9acc1a4e6 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java @@ -0,0 +1,44 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import org.springframework.web.bind.annotation.GetMapping; +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("/test") + public void test(@RequestBody TestRequest request) { + } + + @GetMapping("/test2") + public void test2(TestRequest2 request) { + } +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Priority.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Priority.java new file mode 100644 index 000000000..e0afc0da3 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Priority.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +public enum Priority { + HIGH("High priority"), + LOW("Low priority"); + + private final String label; + + Priority(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java new file mode 100644 index 000000000..84a0eac12 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java @@ -0,0 +1,83 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.test.web.servlet.MvcResult; +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public class SpringDocApp36Test extends AbstractSpringDocV30Test { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testEnumDescription() throws Exception { + MvcResult result = mockMvc.perform(get("/v3/api-docs")) + .andExpect(status().isOk()) + .andReturn(); + + String content = result.getResponse().getContentAsString(); + JsonNode jsonNode = objectMapper.readTree(content); + + String description = jsonNode.at("/paths/~1test/post/description").asText(""); + + assertTrue(description.contains("**status**"), "Should contain status enum description"); + assertTrue(description.contains("`ACTIVE`"), "Should contain ACTIVE enum value"); + assertTrue(description.contains("`INACTIVE`"), "Should contain INACTIVE enum value"); + assertTrue(description.contains("Active status"), "Should contain ACTIVE description"); + assertTrue(description.contains("Inactive status"), "Should contain INACTIVE description"); + } + + @Test + void testEnumDescriptionWithCustomFieldName() throws Exception { + MvcResult result = mockMvc.perform(get("/v3/api-docs")) + .andExpect(status().isOk()) + .andReturn(); + + String content = result.getResponse().getContentAsString(); + JsonNode jsonNode = objectMapper.readTree(content); + + String description = jsonNode.at("/paths/~1test2/get/description").asText(""); + + assertTrue(description.contains("**priority**"), "Should contain priority enum description"); + assertTrue(description.contains("`HIGH`"), "Should contain HIGH enum value"); + assertTrue(description.contains("`LOW`"), "Should contain LOW enum value"); + assertTrue(description.contains("High priority"), "Should contain HIGH label from custom field"); + assertTrue(description.contains("Low priority"), "Should contain LOW label from custom field"); + } + + @SpringBootApplication + static class SpringDocTestApp { + } +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Status.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Status.java new file mode 100644 index 000000000..a58ba166d --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Status.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +public enum Status { + ACTIVE("Active status"), + INACTIVE("Inactive status"); + + private final String description; + + Status(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest.java new file mode 100644 index 000000000..f80746a4f --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import org.springdoc.core.annotations.EnumDescription; + +public class TestRequest { + @EnumDescription + private Status status; + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest2.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest2.java new file mode 100644 index 000000000..fd6cc28b4 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest2.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import org.springdoc.core.annotations.EnumDescription; + +public class TestRequest2 { + @EnumDescription(fieldName = "label") + private Priority priority; + + public Priority getPriority() { + return priority; + } + + public void setPriority(Priority priority) { + this.priority = priority; + } +} From bf134b4e0b8bf67bb671350fdcd0fdaef390f2f3 Mon Sep 17 00:00:00 2001 From: TAEWOOKK Date: Sun, 9 Nov 2025 16:32:59 +0900 Subject: [PATCH 04/13] test: Add tests for EnumDescription on webmvc-api --- .../api/v30/app244/SpringDocApp244Test.java | 37 ++++++++ .../api/v30/app244/SpringDocApp36Test.java | 83 ----------------- .../test/resources/results/3.0.1/app244.json | 91 +++++++++++++++++++ 3 files changed, 128 insertions(+), 83 deletions(-) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp244Test.java delete mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp244Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp244Test.java new file mode 100644 index 000000000..f3db8cfa4 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp244Test.java @@ -0,0 +1,37 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +public class SpringDocApp244Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java deleted file mode 100644 index 84a0eac12..000000000 --- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * * - * * * - * * * * - * * * * * - * * * * * * Copyright 2019-2025 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.app244; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.test.web.servlet.MvcResult; -import test.org.springdoc.api.v30.AbstractSpringDocV30Test; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -public class SpringDocApp36Test extends AbstractSpringDocV30Test { - - private final ObjectMapper objectMapper = new ObjectMapper(); - - @Test - void testEnumDescription() throws Exception { - MvcResult result = mockMvc.perform(get("/v3/api-docs")) - .andExpect(status().isOk()) - .andReturn(); - - String content = result.getResponse().getContentAsString(); - JsonNode jsonNode = objectMapper.readTree(content); - - String description = jsonNode.at("/paths/~1test/post/description").asText(""); - - assertTrue(description.contains("**status**"), "Should contain status enum description"); - assertTrue(description.contains("`ACTIVE`"), "Should contain ACTIVE enum value"); - assertTrue(description.contains("`INACTIVE`"), "Should contain INACTIVE enum value"); - assertTrue(description.contains("Active status"), "Should contain ACTIVE description"); - assertTrue(description.contains("Inactive status"), "Should contain INACTIVE description"); - } - - @Test - void testEnumDescriptionWithCustomFieldName() throws Exception { - MvcResult result = mockMvc.perform(get("/v3/api-docs")) - .andExpect(status().isOk()) - .andReturn(); - - String content = result.getResponse().getContentAsString(); - JsonNode jsonNode = objectMapper.readTree(content); - - String description = jsonNode.at("/paths/~1test2/get/description").asText(""); - - assertTrue(description.contains("**priority**"), "Should contain priority enum description"); - assertTrue(description.contains("`HIGH`"), "Should contain HIGH enum value"); - assertTrue(description.contains("`LOW`"), "Should contain LOW enum value"); - assertTrue(description.contains("High priority"), "Should contain HIGH label from custom field"); - assertTrue(description.contains("Low priority"), "Should contain LOW label from custom field"); - } - - @SpringBootApplication - static class SpringDocTestApp { - } -} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json new file mode 100644 index 000000000..3b82c44bd --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json @@ -0,0 +1,91 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/test": { + "post": { + "tags": [ + "hello-controller" + ], + "description": "**status**\n- `ACTIVE`: Active status\n- `INACTIVE`: Inactive status\n", + "operationId": "test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/test2": { + "get": { + "tags": [ + "hello-controller" + ], + "description": "**priority**\n- `HIGH`: High priority\n- `LOW`: Low priority\n", + "operationId": "test2", + "parameters": [ + { + "name": "request", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/TestRequest2" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "TestRequest": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "ACTIVE", + "INACTIVE" + ] + } + } + }, + "TestRequest2": { + "type": "object", + "properties": { + "priority": { + "type": "string", + "enum": [ + "HIGH", + "LOW" + ] + } + } + } + } + } +} From 54f720961c1aa8effb79351a3b72e6048a0d49b4 Mon Sep 17 00:00:00 2001 From: Mattias-Sehlstedt <60173714+Mattias-Sehlstedt@users.noreply.github.com> Date: Sun, 9 Nov 2025 12:19:06 +0100 Subject: [PATCH 05/13] Add test examples to highlight description concatenation and that the scanning is only done to depth 0 # Conflicts: # springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json --- .../springdoc/api/v30/app244/DeepModel.java | 12 ++ .../api/v30/app244/TestRequest3.java | 49 +++++ .../api/v30/app244/TestRequest4.java | 36 ++++ .../test/resources/results/3.0.1/app244.json | 190 ++++++++++++------ 4 files changed, 220 insertions(+), 67 deletions(-) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/DeepModel.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest3.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest4.java diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/DeepModel.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/DeepModel.java new file mode 100644 index 000000000..f09e17d2f --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/DeepModel.java @@ -0,0 +1,12 @@ +package test.org.springdoc.api.v30.app244; + +import org.springdoc.core.annotations.EnumDescription; + +public class DeepModel { + @EnumDescription + private Status status; + + public Status getStatus() { + return status; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest3.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest3.java new file mode 100644 index 000000000..94c7fb4bd --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest3.java @@ -0,0 +1,49 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import org.springdoc.core.annotations.EnumDescription; + +public class TestRequest3 { + @EnumDescription(fieldName = "label") + private Priority priority; + + @EnumDescription(fieldName = "label") + private Priority priority2; + + public Priority getPriority() { + return priority; + } + + public Priority getPriority2() { + return priority2; + } + + public void setPriority(Priority priority) { + this.priority = priority; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest4.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest4.java new file mode 100644 index 000000000..8f37a19da --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest4.java @@ -0,0 +1,36 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +public class TestRequest4 { + private DeepModel deepModel; + + public DeepModel getDeepModel() { + return deepModel; + } + +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json index 3b82c44bd..a9e1e4595 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json @@ -1,91 +1,147 @@ { - "openapi": "3.0.1", - "info": { - "title": "OpenAPI definition", - "version": "v0" + "openapi" : "3.0.1", + "info" : { + "title" : "OpenAPI definition", + "version" : "v0" }, - "servers": [ - { - "url": "http://localhost", - "description": "Generated server url" - } - ], - "paths": { - "/test": { - "post": { - "tags": [ - "hello-controller" - ], - "description": "**status**\n- `ACTIVE`: Active status\n- `INACTIVE`: Inactive status\n", - "operationId": "test", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TestRequest" + "servers" : [ { + "url" : "http://localhost", + "description" : "Generated server url" + } ], + "paths" : { + "/test" : { + "post" : { + "tags" : [ "hello-controller" ], + "description" : "Endpoint to request test resource\n\n**status**\n- `ACTIVE`: Active status\n- `INACTIVE`: Inactive status\n", + "operationId" : "test", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/TestRequest" } } }, - "required": true + "required" : true }, - "responses": { - "200": { - "description": "OK" + "responses" : { + "200" : { + "description" : "OK" } } } }, - "/test2": { - "get": { - "tags": [ - "hello-controller" - ], - "description": "**priority**\n- `HIGH`: High priority\n- `LOW`: Low priority\n", - "operationId": "test2", - "parameters": [ - { - "name": "request", - "in": "query", - "required": true, - "schema": { - "$ref": "#/components/schemas/TestRequest2" - } + "/test4" : { + "get" : { + "tags" : [ "hello-controller" ], + "description" : "Endpoint to request test4 resource", + "operationId" : "test4", + "parameters" : [ { + "name" : "request", + "in" : "query", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/TestRequest4" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + } + } + } + }, + "/test3" : { + "get" : { + "tags" : [ "hello-controller" ], + "description" : "Endpoint to request test3 resource\n\n**priority**\n- `HIGH`: High priority\n- `LOW`: Low priority\n\n\n**priority2**\n- `HIGH`: High priority\n- `LOW`: Low priority\n", + "operationId" : "test3", + "parameters" : [ { + "name" : "request", + "in" : "query", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/TestRequest3" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + } + } + } + }, + "/test2" : { + "get" : { + "tags" : [ "hello-controller" ], + "description" : "Endpoint to request test2 resource\n\n**priority**\n- `HIGH`: High priority\n- `LOW`: Low priority\n", + "operationId" : "test2", + "parameters" : [ { + "name" : "request", + "in" : "query", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/TestRequest2" } - ], - "responses": { - "200": { - "description": "OK" + } ], + "responses" : { + "200" : { + "description" : "OK" } } } } }, - "components": { - "schemas": { - "TestRequest": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "ACTIVE", - "INACTIVE" - ] + "components" : { + "schemas" : { + "TestRequest" : { + "type" : "object", + "properties" : { + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "INACTIVE" ] + } + } + }, + "DeepModel" : { + "type" : "object", + "properties" : { + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "INACTIVE" ] + } + } + }, + "TestRequest4" : { + "type" : "object", + "properties" : { + "deepModel" : { + "$ref" : "#/components/schemas/DeepModel" + } + } + }, + "TestRequest3" : { + "type" : "object", + "properties" : { + "priority" : { + "type" : "string", + "enum" : [ "HIGH", "LOW" ] + }, + "priority2" : { + "type" : "string", + "enum" : [ "HIGH", "LOW" ] } } }, - "TestRequest2": { - "type": "object", - "properties": { - "priority": { - "type": "string", - "enum": [ - "HIGH", - "LOW" - ] + "TestRequest2" : { + "type" : "object", + "properties" : { + "priority" : { + "type" : "string", + "enum" : [ "HIGH", "LOW" ] } } } } } -} +} \ No newline at end of file From 7e8289ab980106d690e37ca0ee7e6fb0bd131da4 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Fri, 31 Oct 2025 23:53:02 +0100 Subject: [PATCH 06/13] update to swagger-ui version 5.30.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c6e7bea7a..8c357dc46 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.5.0 2.2.38 - 5.30.0 + 5.30.1 1.13.1 0.9.1 0.15.0 From 299ee0e5637283835968c4999e10661b76087f3a Mon Sep 17 00:00:00 2001 From: zakaria-shahen Date: Thu, 30 Oct 2025 21:20:30 +0300 Subject: [PATCH 07/13] add logs to notify developer the SpringDocs or Scalar is enabled. see #3090 --- .../core/configuration/SpringDocConfiguration.java | 11 +++++++++++ .../webflux/scalar/ScalarConfiguration.java | 12 ++++++++++++ .../springdoc/webmvc/scalar/ScalarConfiguration.java | 12 ++++++++++++ 3 files changed, 35 insertions(+) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java index 2a245ea26..370e1c778 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java @@ -44,6 +44,8 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.Schema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springdoc.api.ErrorMessage; import org.springdoc.api.OpenApiResourceNotFoundException; import org.springdoc.core.conditions.CacheOrGroupedOpenApiCondition; @@ -102,6 +104,8 @@ import org.springdoc.core.utils.PropertyResolverUtils; import org.springdoc.core.utils.SchemaUtils; import org.springdoc.core.utils.SpringDocKotlinUtils; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; import reactor.core.publisher.Flux; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; @@ -153,6 +157,13 @@ @ConditionalOnWebApplication public class SpringDocConfiguration { + protected static final Logger LOGGER = LoggerFactory.getLogger(SpringDocConfiguration.class); + + @EventListener(ApplicationReadyEvent.class) + public void init() { + LOGGER.warn("SpringDoc /api-docs endpoint is enabled by default. To disable it in production, set the property '{}=false' in your production profile configuration.", SPRINGDOC_ENABLED); + } + /** * The constant BINDRESULT_CLASS. */ diff --git a/springdoc-openapi-starter-webflux-scalar/src/main/java/org/springdoc/webflux/scalar/ScalarConfiguration.java b/springdoc-openapi-starter-webflux-scalar/src/main/java/org/springdoc/webflux/scalar/ScalarConfiguration.java index 95b1f0264..fe0689521 100644 --- a/springdoc-openapi-starter-webflux-scalar/src/main/java/org/springdoc/webflux/scalar/ScalarConfiguration.java +++ b/springdoc-openapi-starter-webflux-scalar/src/main/java/org/springdoc/webflux/scalar/ScalarConfiguration.java @@ -27,6 +27,8 @@ package org.springdoc.webflux.scalar; import com.scalar.maven.webjar.ScalarProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springdoc.core.configuration.SpringDocConfiguration; import org.springdoc.core.properties.SpringDocConfigProperties; @@ -40,10 +42,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; +import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; +import org.springframework.context.event.EventListener; import org.springframework.web.server.adapter.ForwardedHeaderTransformer; import static org.springdoc.core.utils.Constants.SPRINGDOC_SWAGGER_UI_ENABLED; @@ -63,6 +67,14 @@ @ConditionalOnProperty(prefix = "scalar", name = "enabled", havingValue = "true", matchIfMissing = true) public class ScalarConfiguration { + protected static final Logger LOGGER = LoggerFactory.getLogger(ScalarConfiguration.class); + + @EventListener(ApplicationReadyEvent.class) + public void init() { + LOGGER.warn("SpringDoc Scalar is enabled by default. To disable it in production, set the property 'scalar.enabled=false' in your production profile configuration."); + } + + /** * Scalar web mvc controller scalar web mvc controller. * diff --git a/springdoc-openapi-starter-webmvc-scalar/src/main/java/org/springdoc/webmvc/scalar/ScalarConfiguration.java b/springdoc-openapi-starter-webmvc-scalar/src/main/java/org/springdoc/webmvc/scalar/ScalarConfiguration.java index 938a2ba58..ef6ae5608 100644 --- a/springdoc-openapi-starter-webmvc-scalar/src/main/java/org/springdoc/webmvc/scalar/ScalarConfiguration.java +++ b/springdoc-openapi-starter-webmvc-scalar/src/main/java/org/springdoc/webmvc/scalar/ScalarConfiguration.java @@ -27,6 +27,8 @@ package org.springdoc.webmvc.scalar; import com.scalar.maven.webjar.ScalarProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springdoc.core.configuration.SpringDocConfiguration; import org.springdoc.core.properties.SpringDocConfigProperties; @@ -40,11 +42,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; +import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; +import org.springframework.context.event.EventListener; import org.springframework.web.filter.ForwardedHeaderFilter; import static org.springdoc.core.utils.Constants.SPRINGDOC_SWAGGER_UI_ENABLED; @@ -64,6 +68,14 @@ @ConditionalOnProperty(prefix = "scalar", name = "enabled", havingValue = "true", matchIfMissing = true) public class ScalarConfiguration { + + protected static final Logger LOGGER = LoggerFactory.getLogger(ScalarConfiguration.class); + + @EventListener(ApplicationReadyEvent.class) + public void init() { + LOGGER.warn("SpringDoc Scalar is enabled by default. To disable it in production, set the property 'scalar.enabled=false' in your production profile configuration."); + } + /** * Scalar web mvc controller scalar web mvc controller. * From 429766f55c006b34b0a4e08095552e78ce15a123 Mon Sep 17 00:00:00 2001 From: "Badr.NassLahsen" Date: Sat, 1 Nov 2025 21:42:16 +0100 Subject: [PATCH 08/13] code review --- .../configuration/SpringDocConfiguration.java | 25 ++++--- .../core/events/SpringDocAppInitializer.java | 75 +++++++++++++++++++ .../org/springdoc/core/utils/Constants.java | 5 ++ .../webflux/scalar/ScalarConfiguration.java | 53 ++++++++----- .../springdoc/webflux/ui/SwaggerConfig.java | 28 +++++++ .../webmvc/scalar/ScalarConfiguration.java | 45 +++++++---- .../springdoc/webmvc/ui/SwaggerConfig.java | 28 +++++++ 7 files changed, 214 insertions(+), 45 deletions(-) create mode 100644 springdoc-openapi-starter-common/src/main/java/org/springdoc/core/events/SpringDocAppInitializer.java diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java index 370e1c778..abeafb495 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java @@ -44,8 +44,6 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.Schema; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springdoc.api.ErrorMessage; import org.springdoc.api.OpenApiResourceNotFoundException; import org.springdoc.core.conditions.CacheOrGroupedOpenApiCondition; @@ -79,6 +77,7 @@ import org.springdoc.core.customizers.SpringDocCustomizers; import org.springdoc.core.customizers.EnumDescriptionOperationCustomizer; import org.springdoc.core.discoverer.SpringDocParameterNameDiscoverer; +import org.springdoc.core.events.SpringDocAppInitializer; import org.springdoc.core.extractor.MethodParameterPojoExtractor; import org.springdoc.core.filters.GlobalOpenApiMethodFilter; import org.springdoc.core.filters.OpenApiMethodFilter; @@ -104,8 +103,6 @@ import org.springdoc.core.utils.PropertyResolverUtils; import org.springdoc.core.utils.SchemaUtils; import org.springdoc.core.utils.SpringDocKotlinUtils; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.event.EventListener; import reactor.core.publisher.Flux; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; @@ -157,13 +154,6 @@ @ConditionalOnWebApplication public class SpringDocConfiguration { - protected static final Logger LOGGER = LoggerFactory.getLogger(SpringDocConfiguration.class); - - @EventListener(ApplicationReadyEvent.class) - public void init() { - LOGGER.warn("SpringDoc /api-docs endpoint is enabled by default. To disable it in production, set the property '{}=false' in your production profile configuration.", SPRINGDOC_ENABLED); - } - /** * The constant BINDRESULT_CLASS. */ @@ -741,4 +731,17 @@ MethodParameterPojoExtractor methodParameterPojoExtractor(SchemaUtils schemaUtil GlobalOperationCustomizer enumDescriptionOperationCustomizer() { return new EnumDescriptionOperationCustomizer(); } + + /** + * Spring doc app initializer spring doc app initializer. + * + * @param springDocConfigProperties the spring doc config properties + * @return the spring doc app initializer + */ + @Bean + @ConditionalOnMissingBean(name = "springDocAppInitializer") + @Lazy(false) + SpringDocAppInitializer springDocAppInitializer(SpringDocConfigProperties springDocConfigProperties){ + return new SpringDocAppInitializer(springDocConfigProperties.getApiDocs().getPath(), SPRINGDOC_ENABLED); + } } diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/events/SpringDocAppInitializer.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/events/SpringDocAppInitializer.java new file mode 100644 index 000000000..f1a02b05b --- /dev/null +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/events/SpringDocAppInitializer.java @@ -0,0 +1,75 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.events; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; + +/** + * The type Spring doc app initializer. + * + * @author bnasslahsen + */ +public class SpringDocAppInitializer { + + /** + * The Endpoint. + */ + private final String endpoint; + + /** + * The Property. + */ + private final String property; + + /** + * The constant LOGGER. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(SpringDocAppInitializer.class); + + /** + * Instantiates a new Spring doc app initializer. + * + * @param endpoint the endpoint + * @param property the property + */ + public SpringDocAppInitializer(String endpoint, String property) { + this.endpoint = endpoint; + this.property = property; + } + + /** + * Init. + */ + @EventListener(ApplicationReadyEvent.class) + public void init() { + LOGGER.warn("SpringDoc {} endpoint is enabled by default. To disable it in production, set the property '{}=false'", endpoint, property); + } +} diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java index 3e0b065ae..4f4d637d9 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java @@ -439,6 +439,11 @@ public final class Constants { */ public static final String SPRINGDOC_EXPLICIT_OBJECT_SCHEMA = "springdoc.explicit-object-schema"; + /** + * The constant SCALAR_ENABLED. + */ + public static final String SCALAR_ENABLED= "scalar.enabled"; + /** * Instantiates a new Constants. */ diff --git a/springdoc-openapi-starter-webflux-scalar/src/main/java/org/springdoc/webflux/scalar/ScalarConfiguration.java b/springdoc-openapi-starter-webflux-scalar/src/main/java/org/springdoc/webflux/scalar/ScalarConfiguration.java index fe0689521..70c62002d 100644 --- a/springdoc-openapi-starter-webflux-scalar/src/main/java/org/springdoc/webflux/scalar/ScalarConfiguration.java +++ b/springdoc-openapi-starter-webflux-scalar/src/main/java/org/springdoc/webflux/scalar/ScalarConfiguration.java @@ -21,15 +21,14 @@ * * * * * * * * * - * + * */ package org.springdoc.webflux.scalar; import com.scalar.maven.webjar.ScalarProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springdoc.core.configuration.SpringDocConfiguration; +import org.springdoc.core.events.SpringDocAppInitializer; import org.springdoc.core.properties.SpringDocConfigProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; @@ -42,16 +41,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; -import org.springframework.context.event.EventListener; import org.springframework.web.server.adapter.ForwardedHeaderTransformer; -import static org.springdoc.core.utils.Constants.SPRINGDOC_SWAGGER_UI_ENABLED; +import static org.springdoc.core.utils.Constants.SCALAR_ENABLED; import static org.springdoc.core.utils.Constants.SPRINGDOC_USE_MANAGEMENT_PORT; +import static org.springdoc.scalar.ScalarConstants.DEFAULT_SCALAR_ACTUATOR_PATH; /** * The type Scalar configuration. @@ -60,21 +58,12 @@ */ @Lazy(false) @Configuration(proxyBeanMethods = false) -@ConditionalOnProperty(name = SPRINGDOC_SWAGGER_UI_ENABLED, matchIfMissing = true) +@ConditionalOnProperty(name = SCALAR_ENABLED, matchIfMissing = true) @ConditionalOnWebApplication(type = Type.REACTIVE) @ConditionalOnBean(SpringDocConfiguration.class) @EnableConfigurationProperties(ScalarProperties.class) -@ConditionalOnProperty(prefix = "scalar", name = "enabled", havingValue = "true", matchIfMissing = true) public class ScalarConfiguration { - protected static final Logger LOGGER = LoggerFactory.getLogger(ScalarConfiguration.class); - - @EventListener(ApplicationReadyEvent.class) - public void init() { - LOGGER.warn("SpringDoc Scalar is enabled by default. To disable it in production, set the property 'scalar.enabled=false' in your production profile configuration."); - } - - /** * Scalar web mvc controller scalar web mvc controller. * @@ -87,7 +76,7 @@ public void init() { @ConditionalOnMissingBean @Lazy(false) ScalarWebFluxController scalarWebMvcController(ScalarProperties scalarProperties, SpringDocConfigProperties springDocConfigProperties) { - return new ScalarWebFluxController(scalarProperties,springDocConfigProperties); + return new ScalarWebFluxController(scalarProperties, springDocConfigProperties); } /** @@ -102,6 +91,20 @@ ForwardedHeaderTransformer forwardedHeaderTransformer() { return new ForwardedHeaderTransformer(); } + /** + * Spring doc app initializer spring doc app initializer. + * + * @param scalarProperties the spring doc config properties + * @return the spring doc app initializer + */ + @Bean + @ConditionalOnMissingBean(name = "springDocScalarInitializer") + @ConditionalOnProperty(name = SPRINGDOC_USE_MANAGEMENT_PORT, havingValue = "false", matchIfMissing = true) + @Lazy(false) + SpringDocAppInitializer springDocScalarInitializer(ScalarProperties scalarProperties) { + return new SpringDocAppInitializer(scalarProperties.getPath(), SCALAR_ENABLED); + } + /** * The type Swagger actuator welcome configuration. */ @@ -120,8 +123,20 @@ static class SwaggerActuatorWelcomeConfiguration { @Bean @ConditionalOnMissingBean @Lazy(false) - ScalarActuatorController scalarActuatorController(ScalarProperties properties, WebEndpointProperties webEndpointProperties) { - return new ScalarActuatorController(properties,webEndpointProperties); + ScalarActuatorController scalarActuatorController(ScalarProperties properties, WebEndpointProperties webEndpointProperties) { + return new ScalarActuatorController(properties, webEndpointProperties); + } + + /** + * Spring doc scalar initializer spring doc app initializer. + * + * @return the spring doc app initializer + */ + @Bean + @ConditionalOnMissingBean(name = "springDocScalarInitializer") + @Lazy(false) + SpringDocAppInitializer springDocScalarInitializer() { + return new SpringDocAppInitializer(DEFAULT_SCALAR_ACTUATOR_PATH, SCALAR_ENABLED); } } diff --git a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfig.java b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfig.java index 9a1618b3d..64d02123f 100644 --- a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfig.java +++ b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfig.java @@ -29,6 +29,7 @@ import java.util.Optional; import org.springdoc.core.configuration.SpringDocConfiguration; +import org.springdoc.core.events.SpringDocAppInitializer; import org.springdoc.core.properties.SpringDocConfigProperties; import org.springdoc.core.properties.SwaggerUiConfigProperties; import org.springdoc.core.properties.SwaggerUiOAuthProperties; @@ -53,6 +54,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.web.reactive.config.WebFluxConfigurer; +import static org.springdoc.core.utils.Constants.DEFAULT_SWAGGER_UI_ACTUATOR_PATH; import static org.springdoc.core.utils.Constants.SPRINGDOC_SWAGGER_UI_ENABLED; import static org.springdoc.core.utils.Constants.SPRINGDOC_USE_MANAGEMENT_PORT; import static org.springdoc.core.utils.Constants.SPRINGDOC_USE_ROOT_PATH; @@ -182,6 +184,20 @@ SwaggerResourceResolver swaggerResourceResolver(SwaggerUiConfigProperties swagge return new SwaggerResourceResolver(swaggerUiConfigProperties); } + /** + * Spring doc swagger initializer spring doc swagger initializer. + * + * @param swaggerUiConfigProperties the swagger ui config properties + * @return the spring doc swagger initializer + */ + @Bean + @ConditionalOnMissingBean(name = "springDocSwaggerInitializer") + @ConditionalOnProperty(name = SPRINGDOC_USE_MANAGEMENT_PORT, havingValue = "false", matchIfMissing = true) + @Lazy(false) + SpringDocAppInitializer springDocSwaggerInitializer(SwaggerUiConfigProperties swaggerUiConfigProperties) { + return new SpringDocAppInitializer(swaggerUiConfigProperties.getPath(), SPRINGDOC_SWAGGER_UI_ENABLED); + } + /** * The type Swagger actuator welcome configuration. * @@ -207,5 +223,17 @@ SwaggerWelcomeActuator swaggerActuatorWelcome(SwaggerUiConfigProperties swaggerU WebEndpointProperties webEndpointProperties) { return new SwaggerWelcomeActuator(swaggerUiConfig, springDocConfigProperties, webEndpointProperties); } + + /** + * Spring doc swagger initializer spring doc app initializer. + * + * @return the spring doc app initializer + */ + @Bean + @ConditionalOnMissingBean(name = "springDocSwaggerInitializer") + @Lazy(false) + SpringDocAppInitializer springDocSwaggerInitializer() { + return new SpringDocAppInitializer(DEFAULT_SWAGGER_UI_ACTUATOR_PATH, SPRINGDOC_SWAGGER_UI_ENABLED); + } } } diff --git a/springdoc-openapi-starter-webmvc-scalar/src/main/java/org/springdoc/webmvc/scalar/ScalarConfiguration.java b/springdoc-openapi-starter-webmvc-scalar/src/main/java/org/springdoc/webmvc/scalar/ScalarConfiguration.java index ef6ae5608..ccbf3ebe0 100644 --- a/springdoc-openapi-starter-webmvc-scalar/src/main/java/org/springdoc/webmvc/scalar/ScalarConfiguration.java +++ b/springdoc-openapi-starter-webmvc-scalar/src/main/java/org/springdoc/webmvc/scalar/ScalarConfiguration.java @@ -27,9 +27,8 @@ package org.springdoc.webmvc.scalar; import com.scalar.maven.webjar.ScalarProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springdoc.core.configuration.SpringDocConfiguration; +import org.springdoc.core.events.SpringDocAppInitializer; import org.springdoc.core.properties.SpringDocConfigProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; @@ -42,17 +41,16 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; -import org.springframework.context.event.EventListener; import org.springframework.web.filter.ForwardedHeaderFilter; -import static org.springdoc.core.utils.Constants.SPRINGDOC_SWAGGER_UI_ENABLED; +import static org.springdoc.core.utils.Constants.SCALAR_ENABLED; import static org.springdoc.core.utils.Constants.SPRINGDOC_USE_MANAGEMENT_PORT; +import static org.springdoc.scalar.ScalarConstants.DEFAULT_SCALAR_ACTUATOR_PATH; /** * The type Scalar configuration. @@ -61,21 +59,12 @@ */ @Lazy(false) @Configuration(proxyBeanMethods = false) -@ConditionalOnProperty(name = SPRINGDOC_SWAGGER_UI_ENABLED, matchIfMissing = true) +@ConditionalOnProperty(name = SCALAR_ENABLED, matchIfMissing = true) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnBean(SpringDocConfiguration.class) @EnableConfigurationProperties(ScalarProperties.class) -@ConditionalOnProperty(prefix = "scalar", name = "enabled", havingValue = "true", matchIfMissing = true) public class ScalarConfiguration { - - protected static final Logger LOGGER = LoggerFactory.getLogger(ScalarConfiguration.class); - - @EventListener(ApplicationReadyEvent.class) - public void init() { - LOGGER.warn("SpringDoc Scalar is enabled by default. To disable it in production, set the property 'scalar.enabled=false' in your production profile configuration."); - } - /** * Scalar web mvc controller scalar web mvc controller. * @@ -103,6 +92,20 @@ public FilterRegistrationBean forwardedHeaderFilter() { return new FilterRegistrationBean<>(new ForwardedHeaderFilter()); } + /** + * Spring doc app initializer spring doc app initializer. + * + * @param scalarProperties the spring doc config properties + * @return the spring doc app initializer + */ + @Bean + @ConditionalOnMissingBean(name = "springDocScalarInitializer") + @ConditionalOnProperty(name = SPRINGDOC_USE_MANAGEMENT_PORT, havingValue = "false", matchIfMissing = true) + @Lazy(false) + SpringDocAppInitializer springDocScalarInitializer(ScalarProperties scalarProperties){ + return new SpringDocAppInitializer(scalarProperties.getPath(), SCALAR_ENABLED); + } + /** * The type Swagger actuator welcome configuration. */ @@ -124,6 +127,18 @@ static class SwaggerActuatorWelcomeConfiguration { ScalarActuatorController scalarActuatorController(ScalarProperties properties, WebEndpointProperties webEndpointProperties) { return new ScalarActuatorController(properties,webEndpointProperties); } + + /** + * Spring doc scalar initializer spring doc app initializer. + * + * @return the spring doc app initializer + */ + @Bean + @ConditionalOnMissingBean(name = "springDocScalarInitializer") + @Lazy(false) + SpringDocAppInitializer springDocScalarInitializer(){ + return new SpringDocAppInitializer(DEFAULT_SCALAR_ACTUATOR_PATH, SCALAR_ENABLED); + } } } diff --git a/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerConfig.java b/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerConfig.java index 4593187a0..1e97bf92d 100644 --- a/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerConfig.java +++ b/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerConfig.java @@ -29,6 +29,7 @@ import java.util.Optional; import org.springdoc.core.configuration.SpringDocConfiguration; +import org.springdoc.core.events.SpringDocAppInitializer; import org.springdoc.core.properties.SpringDocConfigProperties; import org.springdoc.core.properties.SwaggerUiConfigProperties; import org.springdoc.core.properties.SwaggerUiOAuthProperties; @@ -51,6 +52,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; +import static org.springdoc.core.utils.Constants.DEFAULT_SWAGGER_UI_ACTUATOR_PATH; import static org.springdoc.core.utils.Constants.SPRINGDOC_SWAGGER_UI_ENABLED; import static org.springdoc.core.utils.Constants.SPRINGDOC_USE_MANAGEMENT_PORT; import static org.springdoc.core.utils.Constants.SPRINGDOC_USE_ROOT_PATH; @@ -170,6 +172,20 @@ SwaggerResourceResolver swaggerResourceResolver(SwaggerUiConfigProperties swagge return new SwaggerResourceResolver(swaggerUiConfigProperties); } + /** + * Spring doc swagger initializer spring doc swagger initializer. + * + * @param swaggerUiConfigProperties the swagger ui config properties + * @return the spring doc swagger initializer + */ + @Bean + @ConditionalOnMissingBean(name = "springDocSwaggerInitializer") + @ConditionalOnProperty(name = SPRINGDOC_USE_MANAGEMENT_PORT, havingValue = "false", matchIfMissing = true) + @Lazy(false) + SpringDocAppInitializer springDocSwaggerInitializer(SwaggerUiConfigProperties swaggerUiConfigProperties) { + return new SpringDocAppInitializer(swaggerUiConfigProperties.getPath(), SPRINGDOC_SWAGGER_UI_ENABLED); + } + /** * The type Swagger actuator welcome configuration. */ @@ -192,5 +208,17 @@ static class SwaggerActuatorWelcomeConfiguration { SwaggerWelcomeActuator swaggerActuatorWelcome(SwaggerUiConfigProperties swaggerUiConfig, SpringDocConfigProperties springDocConfigProperties, WebEndpointProperties webEndpointProperties) { return new SwaggerWelcomeActuator(swaggerUiConfig, springDocConfigProperties, webEndpointProperties); } + + /** + * Spring doc swagger initializer spring doc app initializer. + * + * @return the spring doc app initializer + */ + @Bean + @ConditionalOnMissingBean(name = "springDocSwaggerInitializer") + @Lazy(false) + SpringDocAppInitializer springDocSwaggerInitializer() { + return new SpringDocAppInitializer(DEFAULT_SWAGGER_UI_ACTUATOR_PATH, SPRINGDOC_SWAGGER_UI_ENABLED); + } } } From c23ba171c0d671019f753cfd5dc31b00709574d0 Mon Sep 17 00:00:00 2001 From: TAEWOOKK Date: Mon, 3 Nov 2025 23:34:02 +0900 Subject: [PATCH 09/13] test: Add tests for EnumDescription feature --- .../springdoc/ui/app36/HelloController.java | 44 ++++++++++ .../test/org/springdoc/ui/app36/Priority.java | 42 ++++++++++ .../ui/app36/SpringDocApp36Test.java | 83 +++++++++++++++++++ .../test/org/springdoc/ui/app36/Status.java | 42 ++++++++++ .../org/springdoc/ui/app36/TestRequest.java | 42 ++++++++++ .../org/springdoc/ui/app36/TestRequest2.java | 42 ++++++++++ 6 files changed, 295 insertions(+) create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Priority.java create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Status.java create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest.java create mode 100644 springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest2.java diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java new file mode 100644 index 000000000..5b37966ba --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java @@ -0,0 +1,44 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +import org.springframework.web.bind.annotation.GetMapping; +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("/test") + public void test(@RequestBody TestRequest request) { + } + + @GetMapping("/test2") + public void test2(TestRequest2 request) { + } +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Priority.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Priority.java new file mode 100644 index 000000000..20a46b930 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Priority.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +public enum Priority { + HIGH("High priority"), + LOW("Low priority"); + + private final String label; + + Priority(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } +} diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java new file mode 100644 index 000000000..74d399ab2 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java @@ -0,0 +1,83 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.test.web.servlet.MvcResult; +import test.org.springdoc.ui.AbstractSpringDocTest; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public class SpringDocApp36Test extends AbstractSpringDocTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testEnumDescription() throws Exception { + MvcResult result = mockMvc.perform(get("/v3/api-docs")) + .andExpect(status().isOk()) + .andReturn(); + + String content = result.getResponse().getContentAsString(); + JsonNode jsonNode = objectMapper.readTree(content); + + String description = jsonNode.at("/paths/~1test/post/description").asText(""); + + assertTrue(description.contains("**status**"), "Should contain status enum description"); + assertTrue(description.contains("`ACTIVE`"), "Should contain ACTIVE enum value"); + assertTrue(description.contains("`INACTIVE`"), "Should contain INACTIVE enum value"); + assertTrue(description.contains("Active status"), "Should contain ACTIVE description"); + assertTrue(description.contains("Inactive status"), "Should contain INACTIVE description"); + } + + @Test + void testEnumDescriptionWithCustomFieldName() throws Exception { + MvcResult result = mockMvc.perform(get("/v3/api-docs")) + .andExpect(status().isOk()) + .andReturn(); + + String content = result.getResponse().getContentAsString(); + JsonNode jsonNode = objectMapper.readTree(content); + + String description = jsonNode.at("/paths/~1test2/get/description").asText(""); + + assertTrue(description.contains("**priority**"), "Should contain priority enum description"); + assertTrue(description.contains("`HIGH`"), "Should contain HIGH enum value"); + assertTrue(description.contains("`LOW`"), "Should contain LOW enum value"); + assertTrue(description.contains("High priority"), "Should contain HIGH label from custom field"); + assertTrue(description.contains("Low priority"), "Should contain LOW label from custom field"); + } + + @SpringBootApplication + static class SpringDocTestApp { + } +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Status.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Status.java new file mode 100644 index 000000000..cb882ede4 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/Status.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +public enum Status { + ACTIVE("Active status"), + INACTIVE("Inactive status"); + + private final String description; + + Status(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest.java new file mode 100644 index 000000000..72a52d9db --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +import org.springdoc.core.annotations.EnumDescription; + +public class TestRequest { + @EnumDescription + private Status status; + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } +} diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest2.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest2.java new file mode 100644 index 000000000..89beaf23e --- /dev/null +++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/TestRequest2.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.ui.app36; + +import org.springdoc.core.annotations.EnumDescription; + +public class TestRequest2 { + @EnumDescription(fieldName = "label") + private Priority priority; + + public Priority getPriority() { + return priority; + } + + public void setPriority(Priority priority) { + this.priority = priority; + } +} From c0920b6356a64a91d3e9fd895a107aaf9082aefc Mon Sep 17 00:00:00 2001 From: TAEWOOKK Date: Sun, 9 Nov 2025 14:12:32 +0900 Subject: [PATCH 10/13] test: Add tests for EnumDescription on webmvc-api --- .../api/v30/app244/HelloController.java | 44 ++++++++++ .../springdoc/api/v30/app244/Priority.java | 42 ++++++++++ .../api/v30/app244/SpringDocApp36Test.java | 83 +++++++++++++++++++ .../org/springdoc/api/v30/app244/Status.java | 42 ++++++++++ .../springdoc/api/v30/app244/TestRequest.java | 42 ++++++++++ .../api/v30/app244/TestRequest2.java | 42 ++++++++++ 6 files changed, 295 insertions(+) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Priority.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Status.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest2.java diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java new file mode 100644 index 000000000..9acc1a4e6 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java @@ -0,0 +1,44 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import org.springframework.web.bind.annotation.GetMapping; +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("/test") + public void test(@RequestBody TestRequest request) { + } + + @GetMapping("/test2") + public void test2(TestRequest2 request) { + } +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Priority.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Priority.java new file mode 100644 index 000000000..e0afc0da3 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Priority.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +public enum Priority { + HIGH("High priority"), + LOW("Low priority"); + + private final String label; + + Priority(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java new file mode 100644 index 000000000..84a0eac12 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java @@ -0,0 +1,83 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.test.web.servlet.MvcResult; +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public class SpringDocApp36Test extends AbstractSpringDocV30Test { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testEnumDescription() throws Exception { + MvcResult result = mockMvc.perform(get("/v3/api-docs")) + .andExpect(status().isOk()) + .andReturn(); + + String content = result.getResponse().getContentAsString(); + JsonNode jsonNode = objectMapper.readTree(content); + + String description = jsonNode.at("/paths/~1test/post/description").asText(""); + + assertTrue(description.contains("**status**"), "Should contain status enum description"); + assertTrue(description.contains("`ACTIVE`"), "Should contain ACTIVE enum value"); + assertTrue(description.contains("`INACTIVE`"), "Should contain INACTIVE enum value"); + assertTrue(description.contains("Active status"), "Should contain ACTIVE description"); + assertTrue(description.contains("Inactive status"), "Should contain INACTIVE description"); + } + + @Test + void testEnumDescriptionWithCustomFieldName() throws Exception { + MvcResult result = mockMvc.perform(get("/v3/api-docs")) + .andExpect(status().isOk()) + .andReturn(); + + String content = result.getResponse().getContentAsString(); + JsonNode jsonNode = objectMapper.readTree(content); + + String description = jsonNode.at("/paths/~1test2/get/description").asText(""); + + assertTrue(description.contains("**priority**"), "Should contain priority enum description"); + assertTrue(description.contains("`HIGH`"), "Should contain HIGH enum value"); + assertTrue(description.contains("`LOW`"), "Should contain LOW enum value"); + assertTrue(description.contains("High priority"), "Should contain HIGH label from custom field"); + assertTrue(description.contains("Low priority"), "Should contain LOW label from custom field"); + } + + @SpringBootApplication + static class SpringDocTestApp { + } +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Status.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Status.java new file mode 100644 index 000000000..a58ba166d --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/Status.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +public enum Status { + ACTIVE("Active status"), + INACTIVE("Inactive status"); + + private final String description; + + Status(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest.java new file mode 100644 index 000000000..f80746a4f --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import org.springdoc.core.annotations.EnumDescription; + +public class TestRequest { + @EnumDescription + private Status status; + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest2.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest2.java new file mode 100644 index 000000000..fd6cc28b4 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest2.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import org.springdoc.core.annotations.EnumDescription; + +public class TestRequest2 { + @EnumDescription(fieldName = "label") + private Priority priority; + + public Priority getPriority() { + return priority; + } + + public void setPriority(Priority priority) { + this.priority = priority; + } +} From 62dd1c783acd44df8864792a3e73af0940013024 Mon Sep 17 00:00:00 2001 From: TAEWOOKK Date: Sun, 9 Nov 2025 16:32:59 +0900 Subject: [PATCH 11/13] test: Add tests for EnumDescription on webmvc-api --- .../api/v30/app244/SpringDocApp244Test.java | 37 ++++++++ .../api/v30/app244/SpringDocApp36Test.java | 83 ----------------- .../test/resources/results/3.0.1/app244.json | 91 +++++++++++++++++++ 3 files changed, 128 insertions(+), 83 deletions(-) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp244Test.java delete mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp244Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp244Test.java new file mode 100644 index 000000000..f3db8cfa4 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp244Test.java @@ -0,0 +1,37 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +public class SpringDocApp244Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java deleted file mode 100644 index 84a0eac12..000000000 --- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/SpringDocApp36Test.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * * - * * * - * * * * - * * * * * - * * * * * * Copyright 2019-2025 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.app244; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.test.web.servlet.MvcResult; -import test.org.springdoc.api.v30.AbstractSpringDocV30Test; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -public class SpringDocApp36Test extends AbstractSpringDocV30Test { - - private final ObjectMapper objectMapper = new ObjectMapper(); - - @Test - void testEnumDescription() throws Exception { - MvcResult result = mockMvc.perform(get("/v3/api-docs")) - .andExpect(status().isOk()) - .andReturn(); - - String content = result.getResponse().getContentAsString(); - JsonNode jsonNode = objectMapper.readTree(content); - - String description = jsonNode.at("/paths/~1test/post/description").asText(""); - - assertTrue(description.contains("**status**"), "Should contain status enum description"); - assertTrue(description.contains("`ACTIVE`"), "Should contain ACTIVE enum value"); - assertTrue(description.contains("`INACTIVE`"), "Should contain INACTIVE enum value"); - assertTrue(description.contains("Active status"), "Should contain ACTIVE description"); - assertTrue(description.contains("Inactive status"), "Should contain INACTIVE description"); - } - - @Test - void testEnumDescriptionWithCustomFieldName() throws Exception { - MvcResult result = mockMvc.perform(get("/v3/api-docs")) - .andExpect(status().isOk()) - .andReturn(); - - String content = result.getResponse().getContentAsString(); - JsonNode jsonNode = objectMapper.readTree(content); - - String description = jsonNode.at("/paths/~1test2/get/description").asText(""); - - assertTrue(description.contains("**priority**"), "Should contain priority enum description"); - assertTrue(description.contains("`HIGH`"), "Should contain HIGH enum value"); - assertTrue(description.contains("`LOW`"), "Should contain LOW enum value"); - assertTrue(description.contains("High priority"), "Should contain HIGH label from custom field"); - assertTrue(description.contains("Low priority"), "Should contain LOW label from custom field"); - } - - @SpringBootApplication - static class SpringDocTestApp { - } -} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json new file mode 100644 index 000000000..3b82c44bd --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json @@ -0,0 +1,91 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/test": { + "post": { + "tags": [ + "hello-controller" + ], + "description": "**status**\n- `ACTIVE`: Active status\n- `INACTIVE`: Inactive status\n", + "operationId": "test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/test2": { + "get": { + "tags": [ + "hello-controller" + ], + "description": "**priority**\n- `HIGH`: High priority\n- `LOW`: Low priority\n", + "operationId": "test2", + "parameters": [ + { + "name": "request", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/TestRequest2" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "TestRequest": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "ACTIVE", + "INACTIVE" + ] + } + } + }, + "TestRequest2": { + "type": "object", + "properties": { + "priority": { + "type": "string", + "enum": [ + "HIGH", + "LOW" + ] + } + } + } + } + } +} From c9d51125f2d1b9015cf41c344a966656927a7bdd Mon Sep 17 00:00:00 2001 From: Mattias-Sehlstedt <60173714+Mattias-Sehlstedt@users.noreply.github.com> Date: Sun, 9 Nov 2025 12:19:06 +0100 Subject: [PATCH 12/13] Add test examples to highlight description concatenation and that the scanning is only done to depth 0 # Conflicts: # springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json --- .../springdoc/api/v30/app244/DeepModel.java | 12 ++ .../api/v30/app244/TestRequest3.java | 49 +++++ .../api/v30/app244/TestRequest4.java | 36 ++++ .../test/resources/results/3.0.1/app244.json | 190 ++++++++++++------ 4 files changed, 220 insertions(+), 67 deletions(-) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/DeepModel.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest3.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest4.java diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/DeepModel.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/DeepModel.java new file mode 100644 index 000000000..f09e17d2f --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/DeepModel.java @@ -0,0 +1,12 @@ +package test.org.springdoc.api.v30.app244; + +import org.springdoc.core.annotations.EnumDescription; + +public class DeepModel { + @EnumDescription + private Status status; + + public Status getStatus() { + return status; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest3.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest3.java new file mode 100644 index 000000000..94c7fb4bd --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest3.java @@ -0,0 +1,49 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import org.springdoc.core.annotations.EnumDescription; + +public class TestRequest3 { + @EnumDescription(fieldName = "label") + private Priority priority; + + @EnumDescription(fieldName = "label") + private Priority priority2; + + public Priority getPriority() { + return priority; + } + + public Priority getPriority2() { + return priority2; + } + + public void setPriority(Priority priority) { + this.priority = priority; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest4.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest4.java new file mode 100644 index 000000000..8f37a19da --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest4.java @@ -0,0 +1,36 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +public class TestRequest4 { + private DeepModel deepModel; + + public DeepModel getDeepModel() { + return deepModel; + } + +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json index 3b82c44bd..a9e1e4595 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json @@ -1,91 +1,147 @@ { - "openapi": "3.0.1", - "info": { - "title": "OpenAPI definition", - "version": "v0" + "openapi" : "3.0.1", + "info" : { + "title" : "OpenAPI definition", + "version" : "v0" }, - "servers": [ - { - "url": "http://localhost", - "description": "Generated server url" - } - ], - "paths": { - "/test": { - "post": { - "tags": [ - "hello-controller" - ], - "description": "**status**\n- `ACTIVE`: Active status\n- `INACTIVE`: Inactive status\n", - "operationId": "test", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TestRequest" + "servers" : [ { + "url" : "http://localhost", + "description" : "Generated server url" + } ], + "paths" : { + "/test" : { + "post" : { + "tags" : [ "hello-controller" ], + "description" : "Endpoint to request test resource\n\n**status**\n- `ACTIVE`: Active status\n- `INACTIVE`: Inactive status\n", + "operationId" : "test", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/TestRequest" } } }, - "required": true + "required" : true }, - "responses": { - "200": { - "description": "OK" + "responses" : { + "200" : { + "description" : "OK" } } } }, - "/test2": { - "get": { - "tags": [ - "hello-controller" - ], - "description": "**priority**\n- `HIGH`: High priority\n- `LOW`: Low priority\n", - "operationId": "test2", - "parameters": [ - { - "name": "request", - "in": "query", - "required": true, - "schema": { - "$ref": "#/components/schemas/TestRequest2" - } + "/test4" : { + "get" : { + "tags" : [ "hello-controller" ], + "description" : "Endpoint to request test4 resource", + "operationId" : "test4", + "parameters" : [ { + "name" : "request", + "in" : "query", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/TestRequest4" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + } + } + } + }, + "/test3" : { + "get" : { + "tags" : [ "hello-controller" ], + "description" : "Endpoint to request test3 resource\n\n**priority**\n- `HIGH`: High priority\n- `LOW`: Low priority\n\n\n**priority2**\n- `HIGH`: High priority\n- `LOW`: Low priority\n", + "operationId" : "test3", + "parameters" : [ { + "name" : "request", + "in" : "query", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/TestRequest3" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + } + } + } + }, + "/test2" : { + "get" : { + "tags" : [ "hello-controller" ], + "description" : "Endpoint to request test2 resource\n\n**priority**\n- `HIGH`: High priority\n- `LOW`: Low priority\n", + "operationId" : "test2", + "parameters" : [ { + "name" : "request", + "in" : "query", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/TestRequest2" } - ], - "responses": { - "200": { - "description": "OK" + } ], + "responses" : { + "200" : { + "description" : "OK" } } } } }, - "components": { - "schemas": { - "TestRequest": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "ACTIVE", - "INACTIVE" - ] + "components" : { + "schemas" : { + "TestRequest" : { + "type" : "object", + "properties" : { + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "INACTIVE" ] + } + } + }, + "DeepModel" : { + "type" : "object", + "properties" : { + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "INACTIVE" ] + } + } + }, + "TestRequest4" : { + "type" : "object", + "properties" : { + "deepModel" : { + "$ref" : "#/components/schemas/DeepModel" + } + } + }, + "TestRequest3" : { + "type" : "object", + "properties" : { + "priority" : { + "type" : "string", + "enum" : [ "HIGH", "LOW" ] + }, + "priority2" : { + "type" : "string", + "enum" : [ "HIGH", "LOW" ] } } }, - "TestRequest2": { - "type": "object", - "properties": { - "priority": { - "type": "string", - "enum": [ - "HIGH", - "LOW" - ] + "TestRequest2" : { + "type" : "object", + "properties" : { + "priority" : { + "type" : "string", + "enum" : [ "HIGH", "LOW" ] } } } } } -} +} \ No newline at end of file From 952d3a8814fc8bd1107c8b9eabd426993443ce08 Mon Sep 17 00:00:00 2001 From: TAEWOOKK Date: Sat, 15 Nov 2025 20:30:34 +0900 Subject: [PATCH 13/13] test: Add tests for EnumDescription on webmvc-api - Field Scanning: Recursively scans DTO classes including parent classes --- .../springdoc/api/v30/app244/BaseRequest.java | 43 ++++++++++++ .../api/v30/app244/HelloController.java | 30 +++++++-- .../api/v30/app244/TestRequest5.java | 43 ++++++++++++ .../test/resources/results/3.0.1/app244.json | 65 ++++++++++++++----- 4 files changed, 160 insertions(+), 21 deletions(-) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/BaseRequest.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest5.java diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/BaseRequest.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/BaseRequest.java new file mode 100644 index 000000000..40503bb18 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/BaseRequest.java @@ -0,0 +1,43 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import org.springdoc.core.annotations.EnumDescription; + +public class BaseRequest { + + @EnumDescription + private Status status; + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java index 9acc1a4e6..b042b9a3f 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/HelloController.java @@ -26,6 +26,7 @@ package test.org.springdoc.api.v30.app244; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -34,11 +35,28 @@ @RestController public class HelloController { - @PostMapping("/test") - public void test(@RequestBody TestRequest request) { - } + @PostMapping("/test") + @Operation(description = "Endpoint to request test resource") + public void test(@RequestBody TestRequest request) { + } - @GetMapping("/test2") - public void test2(TestRequest2 request) { - } + @GetMapping("/test2") + @Operation(description = "Endpoint to request test2 resource") // ← test2 + public void test2(TestRequest2 request) { + } + + @GetMapping("/test3") + @Operation(description = "Endpoint to request test3 resource") // ← test3 + public void test3(TestRequest3 request) { + } + + @GetMapping("/test4") + @Operation(description = "Endpoint to request test4 resource") // ← test4 + public void test4(TestRequest4 request) { + } + + @PostMapping("/test5") + @Operation(description = "Endpoint to request test5 resource") + public void test5(@RequestBody TestRequest5 request) { + } } \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest5.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest5.java new file mode 100644 index 000000000..14085d87d --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app244/TestRequest5.java @@ -0,0 +1,43 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * Copyright 2019-2025 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.app244; + +import org.springdoc.core.annotations.EnumDescription; + +public class TestRequest5 extends BaseRequest { + + @EnumDescription(fieldName = "label") + private Priority priority; + + public Priority getPriority() { + return priority; + } + + public void setPriority(Priority priority) { + this.priority = priority; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json index a9e1e4595..6407a0abe 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app244.json @@ -31,17 +31,17 @@ } } }, - "/test4" : { + "/test2" : { "get" : { "tags" : [ "hello-controller" ], - "description" : "Endpoint to request test4 resource", - "operationId" : "test4", + "description" : "Endpoint to request test2 resource\n\n**priority**\n- `HIGH`: High priority\n- `LOW`: Low priority\n", + "operationId" : "test2", "parameters" : [ { "name" : "request", "in" : "query", "required" : true, "schema" : { - "$ref" : "#/components/schemas/TestRequest4" + "$ref" : "#/components/schemas/TestRequest2" } } ], "responses" : { @@ -71,17 +71,17 @@ } } }, - "/test2" : { + "/test4" : { "get" : { "tags" : [ "hello-controller" ], - "description" : "Endpoint to request test2 resource\n\n**priority**\n- `HIGH`: High priority\n- `LOW`: Low priority\n", - "operationId" : "test2", + "description" : "Endpoint to request test4 resource", + "operationId" : "test4", "parameters" : [ { "name" : "request", "in" : "query", "required" : true, "schema" : { - "$ref" : "#/components/schemas/TestRequest2" + "$ref" : "#/components/schemas/TestRequest4" } } ], "responses" : { @@ -90,6 +90,28 @@ } } } + }, + "/test5": { + "post": { + "tags": ["hello-controller"], + "description": "Endpoint to request test5 resource\n\n**priority**\n- `HIGH`: High priority\n- `LOW`: Low priority\n\n\n**status**\n- `ACTIVE`: Active status\n- `INACTIVE`: Inactive status\n", + "operationId": "test5", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestRequest5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } } }, "components" : { @@ -112,11 +134,12 @@ } } }, - "TestRequest4" : { + "TestRequest2" : { "type" : "object", "properties" : { - "deepModel" : { - "$ref" : "#/components/schemas/DeepModel" + "priority" : { + "type" : "string", + "enum" : [ "HIGH", "LOW" ] } } }, @@ -133,12 +156,24 @@ } } }, - "TestRequest2" : { + "TestRequest4" : { "type" : "object", "properties" : { - "priority" : { - "type" : "string", - "enum" : [ "HIGH", "LOW" ] + "deepModel" : { + "$ref" : "#/components/schemas/DeepModel" + } + } + }, + "TestRequest5": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": ["ACTIVE", "INACTIVE"] + }, + "priority": { + "type": "string", + "enum": ["HIGH", "LOW"] } } }