From d633484d24a42803582128e98e59698c7d5a746b Mon Sep 17 00:00:00 2001 From: margie1a <4987kk@naver.com> Date: Sun, 15 Feb 2026 01:27:24 +0900 Subject: [PATCH] Fix validation mapping, path schema regression, and Boot 4 NPE Fixes #3201 Fixes #3213 Fixes #3202 --- .../configuration/SpringDocConfiguration.java | 14 ++ .../SchemaPropertyValidationConverter.java | 122 ++++++++++++++++++ .../KotlinDeprecatedPropertyCustomizer.kt | 11 +- ...otlinDeprecatedPropertyCustomizerTest.java | 69 ++++++++++ .../api/v30/app245/HelloController.java | 70 ++++++++++ .../api/v30/app245/SpringDocApp245Test.java | 42 ++++++ .../api/v30/app248/HelloController.java | 50 +++++++ .../api/v30/app248/SpringDocApp248Test.java | 43 ++++++ .../api/v31/app248/HelloController.java | 50 +++++++ .../api/v31/app248/SpringDocApp248Test.java | 43 ++++++ .../test/resources/results/3.0.1/app245.json | 87 +++++++++++++ .../test/resources/results/3.0.1/app248.json | 50 +++++++ .../test/resources/results/3.1.0/app248.json | 50 +++++++ 13 files changed, 698 insertions(+), 3 deletions(-) create mode 100644 springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/SchemaPropertyValidationConverter.java create mode 100644 springdoc-openapi-starter-common/src/test/java/org/springdoc/core/customizers/KotlinDeprecatedPropertyCustomizerTest.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app245/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app245/SpringDocApp245Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app248/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app248/SpringDocApp248Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app248/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app248/SpringDocApp248Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app245.json create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app248.json create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app248.json 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 0b3154fcf..4bb7e89eb 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 @@ -58,6 +58,7 @@ import org.springdoc.core.converters.PropertyCustomizingConverter; import org.springdoc.core.converters.ResponseSupportConverter; import org.springdoc.core.converters.SchemaPropertyDeprecatingConverter; +import org.springdoc.core.converters.SchemaPropertyValidationConverter; import org.springdoc.core.converters.WebFluxSupportConverter; import org.springdoc.core.customizers.ActuatorOperationCustomizer; import org.springdoc.core.customizers.DataRestRouterOperationCustomizer; @@ -275,6 +276,19 @@ SchemaPropertyDeprecatingConverter schemaPropertyDeprecatingConverter() { return new SchemaPropertyDeprecatingConverter(); } + /** + * Schema property validation converter schema property validation converter. + * + * @param springDocConfigProperties the spring doc config properties + * @return the schema property validation converter + */ + @Bean + @ConditionalOnMissingBean + @Lazy(false) + SchemaPropertyValidationConverter schemaPropertyValidationConverter(SpringDocConfigProperties springDocConfigProperties) { + return new SchemaPropertyValidationConverter(springDocConfigProperties); + } + /** * Polymorphic model converter polymorphic model converter. * diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/SchemaPropertyValidationConverter.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/SchemaPropertyValidationConverter.java new file mode 100644 index 000000000..bfe9eac93 --- /dev/null +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/SchemaPropertyValidationConverter.java @@ -0,0 +1,122 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * 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.converters; + +import java.lang.annotation.Annotation; +import java.math.BigDecimal; +import java.util.Iterator; + +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverter; +import io.swagger.v3.core.converter.ModelConverterContext; +import io.swagger.v3.oas.models.media.Schema; +import jakarta.validation.constraints.Negative; +import jakarta.validation.constraints.NegativeOrZero; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import org.springdoc.core.properties.SpringDocConfigProperties; + +import static org.springdoc.core.properties.SpringDocConfigProperties.ApiDocs.OpenApiVersion; + +/** + * The type Schema property validation converter. + * Applies Jakarta Bean Validation annotations ({@link Positive}, {@link PositiveOrZero}, + * {@link Negative}, {@link NegativeOrZero}) to schema properties. + *

+ * These annotations are not natively handled by swagger-core's ModelResolver for model + * properties, so this converter fills the gap. + * + * @author springdoc + */ +public class SchemaPropertyValidationConverter implements ModelConverter { + + /** + * The spring doc config properties. + */ + private final SpringDocConfigProperties springDocConfigProperties; + + /** + * Instantiates a new Schema property validation converter. + * + * @param springDocConfigProperties the spring doc config properties + */ + public SchemaPropertyValidationConverter(SpringDocConfigProperties springDocConfigProperties) { + this.springDocConfigProperties = springDocConfigProperties; + } + + @Override + public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator chain) { + if (chain.hasNext()) { + Schema resolvedSchema = chain.next().resolve(type, context, chain); + if (type.isSchemaProperty() && resolvedSchema != null) { + applyBeanValidationAnnotations(resolvedSchema, type.getCtxAnnotations()); + } + return resolvedSchema; + } + return null; + } + + /** + * Apply bean validation annotations to the schema. + * + * @param schema the schema + * @param annotations the annotations + */ + private void applyBeanValidationAnnotations(Schema schema, Annotation[] annotations) { + if (annotations == null) { + return; + } + String openapiVersion = springDocConfigProperties.getApiDocs().getVersion().getVersion(); + for (Annotation annotation : annotations) { + Class annotationType = annotation.annotationType(); + if (annotationType == Positive.class) { + if (OpenApiVersion.OPENAPI_3_1.getVersion().equals(openapiVersion)) { + schema.setExclusiveMinimumValue(BigDecimal.ZERO); + } + else { + schema.setMinimum(BigDecimal.ZERO); + schema.setExclusiveMinimum(true); + } + } + else if (annotationType == PositiveOrZero.class) { + schema.setMinimum(BigDecimal.ZERO); + } + else if (annotationType == NegativeOrZero.class) { + schema.setMaximum(BigDecimal.ZERO); + } + else if (annotationType == Negative.class) { + if (OpenApiVersion.OPENAPI_3_1.getVersion().equals(openapiVersion)) { + schema.setExclusiveMaximumValue(BigDecimal.ZERO); + } + else { + schema.setMaximum(BigDecimal.ZERO); + schema.setExclusiveMaximum(true); + } + } + } + } +} diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/KotlinDeprecatedPropertyCustomizer.kt b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/KotlinDeprecatedPropertyCustomizer.kt index 41b2dfc10..5155afdfe 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/KotlinDeprecatedPropertyCustomizer.kt +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/KotlinDeprecatedPropertyCustomizer.kt @@ -34,7 +34,6 @@ import io.swagger.v3.oas.models.Components import io.swagger.v3.oas.models.media.Schema import org.springdoc.core.providers.ObjectMapperProvider import kotlin.reflect.full.findAnnotation -import kotlin.reflect.full.hasAnnotation import kotlin.reflect.full.memberProperties /** @@ -52,7 +51,14 @@ class KotlinDeprecatedPropertyCustomizer( ): Schema<*>? { if (!chain.hasNext()) return null // Resolve the next model in the chain - val resolvedSchema = chain.next().resolve(type, context, chain) + val resolvedSchema = try { + chain.next().resolve(type, context, chain) + } + catch (_: NullPointerException) { + // Some swagger-core subtype resolution paths can throw NPE (e.g. Spring Boot 4 + oneOf usage). + // Keep schema generation graceful and continue without this schema. + return null + } val javaType: JavaType = objectMapperProvider.jsonMapper().constructType(type.type) @@ -65,7 +71,6 @@ class KotlinDeprecatedPropertyCustomizer( // Check each property of the class for (prop in kotlinClass.memberProperties) { val deprecatedAnnotation = prop.findAnnotation() - prop.hasAnnotation() if (deprecatedAnnotation != null) { val fieldName = prop.name if (resolvedSchema!=null && resolvedSchema.`$ref` != null) { diff --git a/springdoc-openapi-starter-common/src/test/java/org/springdoc/core/customizers/KotlinDeprecatedPropertyCustomizerTest.java b/springdoc-openapi-starter-common/src/test/java/org/springdoc/core/customizers/KotlinDeprecatedPropertyCustomizerTest.java new file mode 100644 index 000000000..079052148 --- /dev/null +++ b/springdoc-openapi-starter-common/src/test/java/org/springdoc/core/customizers/KotlinDeprecatedPropertyCustomizerTest.java @@ -0,0 +1,69 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * 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 java.util.Collections; +import java.util.Iterator; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverter; +import io.swagger.v3.core.converter.ModelConverterContext; +import io.swagger.v3.oas.models.media.Schema; +import org.junit.jupiter.api.Test; +import org.springdoc.core.providers.ObjectMapperProvider; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Tests for {@link KotlinDeprecatedPropertyCustomizer}. + * + * @author springdoc + */ +class KotlinDeprecatedPropertyCustomizerTest { + + @Test + void resolveShouldGracefullyHandleNullPointerFromNextConverter() { + ObjectMapperProvider objectMapperProvider = mock(ObjectMapperProvider.class); + when(objectMapperProvider.jsonMapper()).thenReturn(new ObjectMapper()); + + ModelConverter nextConverter = mock(ModelConverter.class); + when(nextConverter.resolve(any(), any(), any())).thenThrow(new NullPointerException("subtypeModel")); + + KotlinDeprecatedPropertyCustomizer customizer = new KotlinDeprecatedPropertyCustomizer(objectMapperProvider); + ModelConverterContext context = mock(ModelConverterContext.class); + AnnotatedType type = new AnnotatedType().type(String.class); + Iterator chain = Collections.singletonList(nextConverter).iterator(); + + Schema schema = assertDoesNotThrow(() -> customizer.resolve(type, context, chain)); + assertNull(schema); + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app245/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app245/HelloController.java new file mode 100644 index 000000000..f618adbed --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app245/HelloController.java @@ -0,0 +1,70 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * 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.app245; + +import java.math.BigDecimal; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Negative; +import jakarta.validation.constraints.NegativeOrZero; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import jakarta.validation.constraints.Size; + +import org.springframework.lang.Nullable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * Test controller for validation-to-schema mapping. + * + * @author springdoc + */ +@RestController +public class HelloController { + + public record UnloadAmountRequest( + @NotNull @Positive BigDecimal amount, + @Nullable String currency, + @Nullable String description, + @Nullable @Size(max = 40) + @Pattern(regexp = "^[a-zA-Z0-9-]+$") String transactionReference, + @PositiveOrZero BigDecimal fee, + @NegativeOrZero BigDecimal discount, + @Negative BigDecimal adjustment + ) { + } + + @PostMapping(value = "/unload") + public String unload(@Valid @RequestBody UnloadAmountRequest request) { + return "OK"; + } + +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app245/SpringDocApp245Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app245/SpringDocApp245Test.java new file mode 100644 index 000000000..915600e72 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app245/SpringDocApp245Test.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.app245; + +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * OpenAPI 3.0 test for Jakarta validation mapping. + * + * @author springdoc + */ +public class SpringDocApp245Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app248/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app248/HelloController.java new file mode 100644 index 000000000..a33a49063 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app248/HelloController.java @@ -0,0 +1,50 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * 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.app248; + +import io.swagger.v3.oas.annotations.media.Schema; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Test controller for path variable schema mapping. + * + * @author springdoc + */ +@RestController +@RequestMapping("/app248") +public class HelloController { + + @GetMapping("/{id}") + public String getById(@PathVariable @Schema(type = "integer", format = "int64", description = "Entity ID") String id) { + return id; + } +} + diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app248/SpringDocApp248Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app248/SpringDocApp248Test.java new file mode 100644 index 000000000..2a7fb4cf0 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app248/SpringDocApp248Test.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.app248; + +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * OpenAPI 3.0 test for @PathVariable + @Schema handling. + * + * @author springdoc + */ +public class SpringDocApp248Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} +} + diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app248/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app248/HelloController.java new file mode 100644 index 000000000..533fc8b96 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app248/HelloController.java @@ -0,0 +1,50 @@ +/* + * + * * + * * * + * * * * + * * * * * + * * * * * * 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.v31.app248; + +import io.swagger.v3.oas.annotations.media.Schema; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Test controller for path variable schema mapping. + * + * @author springdoc + */ +@RestController +@RequestMapping("/app248") +public class HelloController { + + @GetMapping("/{id}") + public String getById(@PathVariable @Schema(type = "integer", format = "int64", description = "Entity ID") String id) { + return id; + } +} + diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app248/SpringDocApp248Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app248/SpringDocApp248Test.java new file mode 100644 index 000000000..d4a8dba24 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app248/SpringDocApp248Test.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.v31.app248; + +import test.org.springdoc.api.v31.AbstractSpringDocTest; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * OpenAPI 3.1 test for @PathVariable + @Schema handling. + * + * @author springdoc + */ +public class SpringDocApp248Test extends AbstractSpringDocTest { + + @SpringBootApplication + static class SpringDocTestApp {} +} + diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app245.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app245.json new file mode 100644 index 000000000..6e32f322d --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app245.json @@ -0,0 +1,87 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/unload": { + "post": { + "tags": [ + "hello-controller" + ], + "operationId": "unload", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnloadAmountRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "UnloadAmountRequest": { + "required": [ + "amount" + ], + "type": "object", + "properties": { + "amount": { + "exclusiveMinimum": true, + "minimum": 0, + "type": "number" + }, + "currency": { + "type": "string" + }, + "description": { + "type": "string" + }, + "transactionReference": { + "maxLength": 40, + "minLength": 0, + "type": "string", + "pattern": "^[a-zA-Z0-9-]+$" + }, + "fee": { + "minimum": 0, + "type": "number" + }, + "discount": { + "maximum": 0, + "type": "number" + }, + "adjustment": { + "exclusiveMaximum": true, + "maximum": 0, + "type": "number" + } + } + } + } + } +} \ No newline at end of file diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app248.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app248.json new file mode 100644 index 000000000..057605de9 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app248.json @@ -0,0 +1,50 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/app248/{id}": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getById", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Entity ID", + "required": true, + "schema": { + "type": "integer", + "description": "Entity ID", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} + diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app248.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app248.json new file mode 100644 index 000000000..13df06afb --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app248.json @@ -0,0 +1,50 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/app248/{id}": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getById", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Entity ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64", + "description": "Entity ID" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} +