From 88e78ae7828f9f59485d6eee2cf35eb0b3310136 Mon Sep 17 00:00:00 2001 From: m2 Date: Wed, 28 May 2025 19:09:22 +0800 Subject: [PATCH 1/2] feat: type-use for method parameters --- .../core/service/AbstractRequestService.java | 25 +++++-- .../api/v31/app19/SpringDocApp19Test.kt | 57 +++++++++++++++ .../test/resources/results/3.1.0/app19.json | 72 +++++++++++++++++++ 3 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/v31/app19/SpringDocApp19Test.kt create mode 100644 springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/resources/results/3.1.0/app19.json diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java index df1d7a0e3..f9c9bd963 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java @@ -617,13 +617,24 @@ public void applyBeanValidatorAnnotations(final MethodParameter methodParameter, if (annotations != null) { Schema schema = parameter.getSchema(); SchemaUtils.applyValidationsToSchema(schema, annotations); - if (schema instanceof ArraySchema && isParameterObject && methodParameter instanceof DelegatingMethodParameter mp) { - Field field = mp.getField(); - if (field != null && field.getAnnotatedType() instanceof AnnotatedParameterizedType paramType) { - java.lang.reflect.AnnotatedType[] typeArgs = paramType.getAnnotatedActualTypeArguments(); - for (java.lang.reflect.AnnotatedType typeArg : typeArgs) { - List genericAnnotations = Arrays.stream(typeArg.getAnnotations()).toList(); - SchemaUtils.applyValidationsToSchema(schema.getItems(), genericAnnotations); + if (schema instanceof ArraySchema && methodParameter instanceof DelegatingMethodParameter mp) { + if (isParameterObject) { + Field field = mp.getField(); + if (field != null && field.getAnnotatedType() instanceof AnnotatedParameterizedType paramType) { + java.lang.reflect.AnnotatedType[] typeArgs = paramType.getAnnotatedActualTypeArguments(); + for (java.lang.reflect.AnnotatedType typeArg : typeArgs) { + List genericAnnotations = Arrays.stream(typeArg.getAnnotations()).toList(); + SchemaUtils.applyValidationsToSchema(schema.getItems(), genericAnnotations); + } + } + } else { + java.lang.reflect.Parameter param = mp.getParameter(); + if (param.getAnnotatedType() instanceof AnnotatedParameterizedType paramType) { + java.lang.reflect.AnnotatedType[] typeArgs = paramType.getAnnotatedActualTypeArguments(); + for (java.lang.reflect.AnnotatedType typeArg : typeArgs) { + List genericAnnotations = Arrays.stream(typeArg.getAnnotations()).toList(); + SchemaUtils.applyValidationsToSchema(schema.getItems(), genericAnnotations); + } } } } diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/v31/app19/SpringDocApp19Test.kt b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/v31/app19/SpringDocApp19Test.kt new file mode 100644 index 000000000..aa1aa2085 --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/kotlin/test/org/springdoc/api/v31/app19/SpringDocApp19Test.kt @@ -0,0 +1,57 @@ +/* + * + * * Copyright 2019-2020 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.app19 + +import io.swagger.v3.oas.annotations.Parameter +import jakarta.validation.constraints.Max +import jakarta.validation.constraints.Min +import jakarta.validation.constraints.Size +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import test.org.springdoc.api.v31.AbstractKotlinSpringDocMVCTest + + +class SpringDocApp19Test : AbstractKotlinSpringDocMVCTest() { + @SpringBootApplication + class DemoApplication +} + +@RestController +@RequestMapping +class HelloController { + + @PostMapping("euroMillions") + fun euroMillions( + @Parameter(description = "the numbers") + @RequestParam + @Size(min = 5, max = 5) + numbers: List<@Max(50) @Min(1) Int>, + + @Parameter(description = "the stars") + @RequestParam + @Size(min = 2, max = 2) + stars: List<@Max(12) @Min(1) Int> + ): ResponseEntity { + return ResponseEntity.ok("ok") + } +} \ No newline at end of file diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/resources/results/3.1.0/app19.json b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/resources/results/3.1.0/app19.json new file mode 100644 index 000000000..3b6d85058 --- /dev/null +++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/src/test/resources/results/3.1.0/app19.json @@ -0,0 +1,72 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/euroMillions": { + "post": { + "tags": [ + "hello-controller" + ], + "operationId": "euroMillions", + "parameters": [ + { + "name": "numbers", + "in": "query", + "description": "the numbers", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32", + "maximum": 50, + "minimum": 1 + }, + "maxItems": 5, + "minItems": 5 + } + }, + { + "name": "stars", + "in": "query", + "description": "the stars", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32", + "maximum": 12, + "minimum": 1 + }, + "maxItems": 2, + "minItems": 2 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} From ae0d3a92654817749a2f2efa8b46714836701cc2 Mon Sep 17 00:00:00 2001 From: m2 Date: Wed, 28 May 2025 21:27:06 +0800 Subject: [PATCH 2/2] feat: type-use for method parameters --- .../core/service/AbstractRequestService.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java index f9c9bd963..466f67c57 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java @@ -618,23 +618,21 @@ public void applyBeanValidatorAnnotations(final MethodParameter methodParameter, Schema schema = parameter.getSchema(); SchemaUtils.applyValidationsToSchema(schema, annotations); if (schema instanceof ArraySchema && methodParameter instanceof DelegatingMethodParameter mp) { + java.lang.reflect.AnnotatedType annotatedType = null; if (isParameterObject) { Field field = mp.getField(); - if (field != null && field.getAnnotatedType() instanceof AnnotatedParameterizedType paramType) { - java.lang.reflect.AnnotatedType[] typeArgs = paramType.getAnnotatedActualTypeArguments(); - for (java.lang.reflect.AnnotatedType typeArg : typeArgs) { - List genericAnnotations = Arrays.stream(typeArg.getAnnotations()).toList(); - SchemaUtils.applyValidationsToSchema(schema.getItems(), genericAnnotations); - } + if (field != null) { + annotatedType = field.getAnnotatedType(); } } else { java.lang.reflect.Parameter param = mp.getParameter(); - if (param.getAnnotatedType() instanceof AnnotatedParameterizedType paramType) { - java.lang.reflect.AnnotatedType[] typeArgs = paramType.getAnnotatedActualTypeArguments(); - for (java.lang.reflect.AnnotatedType typeArg : typeArgs) { - List genericAnnotations = Arrays.stream(typeArg.getAnnotations()).toList(); - SchemaUtils.applyValidationsToSchema(schema.getItems(), genericAnnotations); - } + annotatedType = param.getAnnotatedType(); + } + if (annotatedType instanceof AnnotatedParameterizedType paramType) { + java.lang.reflect.AnnotatedType[] typeArgs = paramType.getAnnotatedActualTypeArguments(); + for (java.lang.reflect.AnnotatedType typeArg : typeArgs) { + List genericAnnotations = Arrays.stream(typeArg.getAnnotations()).toList(); + SchemaUtils.applyValidationsToSchema(schema.getItems(), genericAnnotations); } } }