Skip to content

Commit 95fa3bb

Browse files
committed
Regression: @Header(schema = @Schema(type = "string")) generates empty or broken schema in OpenAPI output since 2.8.0. Fixes #2972
1 parent 3d056d8 commit 95fa3bb

File tree

6 files changed

+145
-2
lines changed

6 files changed

+145
-2
lines changed

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ private Map<String, ApiResponse> computeResponseFromDoc(Components components, M
408408
apiResponse.extensions(extensions);
409409
}
410410
}
411-
AnnotationsUtils.getHeaders(apiResponseAnnotations.headers(), components, methodAttributes.getJsonViewAnnotation(), openapi31)
411+
SpringDocAnnotationsUtils.getHeaders(apiResponseAnnotations.headers(), components, methodAttributes.getJsonViewAnnotation(), openapi31)
412412
.ifPresent(apiResponse::headers);
413413
apiResponsesOp.addApiResponse(httpCode, apiResponse);
414414
}

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OperationService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ private Optional<ApiResponses> getApiResponses(
337337

338338
buildResponseContent(methodAttributes, components, classProduces, methodProduces, apiResponsesOp, response, apiResponseObject);
339339

340-
AnnotationsUtils.getHeaders(response.headers(), components, null, propertyResolverUtils.isOpenapi31()).ifPresent(apiResponseObject::headers);
340+
SpringDocAnnotationsUtils.getHeaders(response.headers(), components, null, propertyResolverUtils.isOpenapi31()).ifPresent(apiResponseObject::headers);
341341
// Make schema as string if empty
342342
calculateHeader(apiResponseObject);
343343
if (isResponseObject(apiResponseObject)) {

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/SpringDocAnnotationsUtils.java

+15
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import io.swagger.v3.oas.annotations.media.SchemaProperty;
5454
import io.swagger.v3.oas.models.Components;
5555
import io.swagger.v3.oas.models.SpecVersion;
56+
import io.swagger.v3.oas.models.headers.Header;
5657
import io.swagger.v3.oas.models.media.ArraySchema;
5758
import io.swagger.v3.oas.models.media.ComposedSchema;
5859
import io.swagger.v3.oas.models.media.Content;
@@ -481,4 +482,18 @@ public static Object resolveDefaultValue(String defaultValueStr, ObjectMapper ob
481482
}
482483
return defaultValue;
483484
}
485+
486+
public static Optional<Map<String, Header>> getHeaders(io.swagger.v3.oas.annotations.headers.Header[] annotationHeaders, Components components, JsonView jsonViewAnnotation, boolean openapi31) {
487+
Optional<Map<String, Header>> headerMap = AnnotationsUtils.getHeaders(annotationHeaders, components, jsonViewAnnotation, openapi31);
488+
if(openapi31){
489+
headerMap.ifPresent(map -> {
490+
for (Entry<String, Header> entry : map.entrySet()) {
491+
Header header = entry.getValue();
492+
Schema schema = header.getSchema();
493+
handleSchemaTypes(schema);
494+
}
495+
});
496+
}
497+
return headerMap;
498+
}
484499
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
*
3+
* *
4+
* * *
5+
* * * *
6+
* * * * *
7+
* * * * * * Copyright 2019-2025 the original author or authors.
8+
* * * * * *
9+
* * * * * * Licensed under the Apache License, Version 2.0 (the "License");
10+
* * * * * * you may not use this file except in compliance with the License.
11+
* * * * * * You may obtain a copy of the License at
12+
* * * * * *
13+
* * * * * * https://www.apache.org/licenses/LICENSE-2.0
14+
* * * * * *
15+
* * * * * * Unless required by applicable law or agreed to in writing, software
16+
* * * * * * distributed under the License is distributed on an "AS IS" BASIS,
17+
* * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* * * * * * See the License for the specific language governing permissions and
19+
* * * * * * limitations under the License.
20+
* * * * *
21+
* * * *
22+
* * *
23+
* *
24+
*
25+
*/
26+
27+
package test.org.springdoc.api.v31.app244;
28+
29+
import io.swagger.v3.oas.annotations.headers.Header;
30+
import io.swagger.v3.oas.annotations.media.Schema;
31+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
32+
33+
import org.springframework.web.bind.annotation.PostMapping;
34+
import org.springframework.web.bind.annotation.RequestMapping;
35+
import org.springframework.web.bind.annotation.RestController;
36+
37+
@RestController
38+
@RequestMapping("/test")
39+
public class HelloController {
40+
41+
@PostMapping
42+
@ApiResponse(
43+
responseCode = "201",
44+
description = "Created",
45+
headers = {
46+
@Header(name = "Location", required = true, schema = @Schema(type = "string"))
47+
}
48+
)
49+
public void uploadMultipartWithBody(){
50+
}
51+
52+
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
*
3+
* *
4+
* * *
5+
* * * *
6+
* * * * *
7+
* * * * * * Copyright 2019-2025 the original author or authors.
8+
* * * * * *
9+
* * * * * * Licensed under the Apache License, Version 2.0 (the "License");
10+
* * * * * * you may not use this file except in compliance with the License.
11+
* * * * * * You may obtain a copy of the License at
12+
* * * * * *
13+
* * * * * * https://www.apache.org/licenses/LICENSE-2.0
14+
* * * * * *
15+
* * * * * * Unless required by applicable law or agreed to in writing, software
16+
* * * * * * distributed under the License is distributed on an "AS IS" BASIS,
17+
* * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* * * * * * See the License for the specific language governing permissions and
19+
* * * * * * limitations under the License.
20+
* * * * *
21+
* * * *
22+
* * *
23+
* *
24+
*
25+
*/
26+
27+
package test.org.springdoc.api.v31.app244;
28+
29+
import test.org.springdoc.api.v31.AbstractSpringDocTest;
30+
31+
import org.springframework.boot.autoconfigure.SpringBootApplication;
32+
33+
public class SpringDocApp244Test extends AbstractSpringDocTest {
34+
35+
@SpringBootApplication
36+
static class SpringDocTestApp {}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"openapi": "3.1.0",
3+
"info": {
4+
"title": "OpenAPI definition",
5+
"version": "v0"
6+
},
7+
"servers": [
8+
{
9+
"url": "http://localhost",
10+
"description": "Generated server url"
11+
}
12+
],
13+
"paths": {
14+
"/test": {
15+
"post": {
16+
"tags": [
17+
"hello-controller"
18+
],
19+
"operationId": "uploadMultipartWithBody",
20+
"responses": {
21+
"201": {
22+
"description": "Created",
23+
"headers": {
24+
"Location": {
25+
"required": true,
26+
"style": "simple",
27+
"schema": {
28+
"type": "string"
29+
}
30+
}
31+
}
32+
}
33+
}
34+
}
35+
}
36+
},
37+
"components": {}
38+
}

0 commit comments

Comments
 (0)