From 61f020281fb3d3a79eb81629f1e77b282e65f769 Mon Sep 17 00:00:00 2001 From: Badr NASS LAHSEN Date: Sun, 6 Sep 2026 04:34:17 +0200 Subject: [PATCH] fix: ignore an injected HttpHeaders parameter HttpHeaders used to be covered by the Map entry of the ignore list, but it no longer implements MultiValueMap in Spring Framework 7, so a controller asking for every request header at once got the whole class described as a schema. Fixes #3317 Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 1 + .../core/service/AbstractRequestService.java | 2 + .../api/v30/app272/HelloController.java | 37 +++++++++++++++++ .../api/v30/app272/SpringDocApp272Test.java | 33 +++++++++++++++ .../api/v31/app272/HelloController.java | 37 +++++++++++++++++ .../api/v31/app272/SpringDocApp272Test.java | 33 +++++++++++++++ .../test/resources/results/3.0.1/app272.json | 40 +++++++++++++++++++ .../test/resources/results/3.1.0/app272.json | 40 +++++++++++++++++++ 8 files changed, 223 insertions(+) create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app272/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app272/SpringDocApp272Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app272/HelloController.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app272/SpringDocApp272Test.java create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app272.json create mode 100644 springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app272.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 247823694..41363de23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - #3328, #3337 – `/v3/api-docs` fails with a `NullPointerException` when spring-hateoas is on the classpath without `HateoasProperties` - #3314 – `Json Processing Exception occurred` is logged for every constrained parameter whose schema is not a `JsonSchema` +- #3317 – An injected `HttpHeaders` parameter is described as a schema - #3320 – `@Order` and `Ordered` ignored when applying customizers - #3319 – A `Page` nested in another schema is not replaced by `PagedModel` - #3313 – Springdoc auto-configurations rely on unspecified auto-configuration ordering 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 a8d9ac278..3afa3f6c2 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 @@ -88,6 +88,7 @@ import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; @@ -143,6 +144,7 @@ public abstract class AbstractRequestService { PARAM_TYPES_TO_IGNORE.add(NativeWebRequest.class); PARAM_TYPES_TO_IGNORE.add(Principal.class); PARAM_TYPES_TO_IGNORE.add(HttpMethod.class); + PARAM_TYPES_TO_IGNORE.add(HttpHeaders.class); PARAM_TYPES_TO_IGNORE.add(Locale.class); PARAM_TYPES_TO_IGNORE.add(TimeZone.class); PARAM_TYPES_TO_IGNORE.add(InputStream.class); diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app272/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app272/HelloController.java new file mode 100644 index 000000000..f3078ec80 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app272/HelloController.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2026 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.app272; + +import org.springframework.http.HttpHeaders; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * A controller that asks for every request header at once. + * + * @author bnasslahsen + */ +@RestController +public class HelloController { + + @GetMapping("/hello") + public String hello(@RequestHeader HttpHeaders headers, @RequestParam String name) { + return name; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app272/SpringDocApp272Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app272/SpringDocApp272Test.java new file mode 100644 index 000000000..41d9a4a75 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app272/SpringDocApp272Test.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2026 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.app272; + +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * An injected HttpHeaders is a request wrapper, not a schema. + * + * @author bnasslahsen + */ +public class SpringDocApp272Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp { + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app272/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app272/HelloController.java new file mode 100644 index 000000000..a21130630 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app272/HelloController.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2026 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.app272; + +import org.springframework.http.HttpHeaders; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * A controller that asks for every request header at once. + * + * @author bnasslahsen + */ +@RestController +public class HelloController { + + @GetMapping("/hello") + public String hello(@RequestHeader HttpHeaders headers, @RequestParam String name) { + return name; + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app272/SpringDocApp272Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app272/SpringDocApp272Test.java new file mode 100644 index 000000000..25cd078ce --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app272/SpringDocApp272Test.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2026 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.app272; + +import test.org.springdoc.api.v31.AbstractSpringDocV31Test; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * An injected HttpHeaders is a request wrapper, not a schema. + * + * @author bnasslahsen + */ +public class SpringDocApp272Test extends AbstractSpringDocV31Test { + + @SpringBootApplication + static class SpringDocTestApp { + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app272.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app272.json new file mode 100644 index 000000000..93d97a19d --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app272.json @@ -0,0 +1,40 @@ +{ + "openapi" : "3.0.1", + "info" : { + "title" : "OpenAPI definition", + "version" : "v0" + }, + "servers" : [ { + "url" : "http://localhost", + "description" : "Generated server url" + } ], + "paths" : { + "/hello" : { + "get" : { + "tags" : [ "hello-controller" ], + "operationId" : "hello", + "parameters" : [ { + "name" : "name", + "in" : "query", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + } + } + } + } + }, + "components" : { } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app272.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app272.json new file mode 100644 index 000000000..748af1ade --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app272.json @@ -0,0 +1,40 @@ +{ + "openapi" : "3.1.0", + "info" : { + "title" : "OpenAPI definition", + "version" : "v0" + }, + "servers" : [ { + "url" : "http://localhost", + "description" : "Generated server url" + } ], + "paths" : { + "/hello" : { + "get" : { + "tags" : [ "hello-controller" ], + "operationId" : "hello", + "parameters" : [ { + "name" : "name", + "in" : "query", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "string" + } + } + } + } + } + } + } + }, + "components" : { } +}