Skip to content

Commit 65f5b3f

Browse files
committed
Merge branch 'kamilkrzywanski-issue2733'
2 parents d502af2 + f8dfee8 commit 65f5b3f

File tree

7 files changed

+184
-4
lines changed

7 files changed

+184
-4
lines changed

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/ConverterUtils.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ public static boolean isResponseTypeWrapper(Class<?> rawClass) {
102102
return RESULT_WRAPPERS_TO_IGNORE.stream().anyMatch(clazz -> clazz.isAssignableFrom(rawClass));
103103
}
104104

105+
/**
106+
* Is exact class
107+
* @param rawClass the raw class
108+
* true if the class is in the list of classes to ignore
109+
*/
110+
public static boolean isExactClass(Class<?> rawClass) {
111+
return RESULT_WRAPPERS_TO_IGNORE.stream().anyMatch(clazz -> clazz == rawClass);
112+
}
113+
105114
/**
106115
* Is response type to ignore boolean.
107116
*

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/ResponseSupportConverter.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@
3535
import io.swagger.v3.oas.models.media.StringSchema;
3636
import org.springdoc.core.providers.ObjectMapperProvider;
3737

38-
import static org.springdoc.core.converters.ConverterUtils.isFluxTypeWrapper;
39-
import static org.springdoc.core.converters.ConverterUtils.isResponseTypeToIgnore;
40-
import static org.springdoc.core.converters.ConverterUtils.isResponseTypeWrapper;
38+
import static org.springdoc.core.converters.ConverterUtils.*;
4139

4240
/**
4341
* The type Response support converter.
@@ -65,7 +63,7 @@ public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterato
6563
if (javaType != null) {
6664
Class<?> cls = javaType.getRawClass();
6765
if (isResponseTypeWrapper(cls) && !isFluxTypeWrapper(cls)) {
68-
JavaType innerType = javaType.getBindings().getBoundType(0);
66+
JavaType innerType = resolveInnerType(javaType);
6967
if (innerType == null)
7068
return new StringSchema();
7169
return context.resolve(new AnnotatedType(innerType)
@@ -79,4 +77,17 @@ else if (isResponseTypeToIgnore(cls))
7977
return (chain.hasNext()) ? chain.next().resolve(type, context, chain) : null;
8078
}
8179

80+
/**
81+
* Resolve inner type java type.
82+
*
83+
* @param javaType the java type
84+
* @return the java type
85+
*/
86+
private JavaType resolveInnerType(JavaType javaType) {
87+
if(!isExactClass(javaType.getRawClass())) {
88+
javaType = javaType.getSuperClass();
89+
}
90+
return javaType.getBindings().getBoundType(0);
91+
}
92+
8293
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
*
3+
* * Copyright 2019-2024 the original author or authors.
4+
* *
5+
* * Licensed under the Apache License, Version 2.0 (the "License");
6+
* * you may not use this file except in compliance with the License.
7+
* * You may obtain a copy of the License at
8+
* *
9+
* * https://www.apache.org/licenses/LICENSE-2.0
10+
* *
11+
* * Unless required by applicable law or agreed to in writing, software
12+
* * distributed under the License is distributed on an "AS IS" BASIS,
13+
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* * See the License for the specific language governing permissions and
15+
* * limitations under the License.
16+
*
17+
*/
18+
19+
package test.org.springdoc.api.app227;
20+
21+
import org.springframework.http.HttpStatus;
22+
import org.springframework.web.bind.annotation.GetMapping;
23+
import org.springframework.web.bind.annotation.RestController;
24+
import test.org.springdoc.api.app227.model.Item;
25+
import test.org.springdoc.api.app227.wrapper.ResponseEntityWrapper;
26+
27+
@RestController
28+
public class HelloController {
29+
30+
@GetMapping("/persons")
31+
public ResponseEntityWrapper<String> persons() {
32+
return new ResponseEntityWrapper<>(Item.fromPayload("1", "OK", "String"), HttpStatus.OK);
33+
}
34+
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
*
3+
* * Copyright 2019-2024 the original author or authors.
4+
* *
5+
* * Licensed under the Apache License, Version 2.0 (the "License");
6+
* * you may not use this file except in compliance with the License.
7+
* * You may obtain a copy of the License at
8+
* *
9+
* * https://www.apache.org/licenses/LICENSE-2.0
10+
* *
11+
* * Unless required by applicable law or agreed to in writing, software
12+
* * distributed under the License is distributed on an "AS IS" BASIS,
13+
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* * See the License for the specific language governing permissions and
15+
* * limitations under the License.
16+
*
17+
*/
18+
19+
package test.org.springdoc.api.app227;
20+
21+
import org.junit.jupiter.api.Test;
22+
import org.springdoc.core.utils.Constants;
23+
24+
import org.springframework.boot.autoconfigure.SpringBootApplication;
25+
import org.springframework.test.context.TestPropertySource;
26+
import test.org.springdoc.api.AbstractSpringDocTest;
27+
28+
import static org.hamcrest.Matchers.is;
29+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
30+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
31+
32+
@TestPropertySource(properties = {
33+
"management.endpoints.enabled-by-default=true",
34+
})
35+
public class SpringDocApp227Test extends AbstractSpringDocTest {
36+
37+
@Test
38+
public void testApp() throws Exception {
39+
mockMvc.perform(get(Constants.DEFAULT_API_DOCS_URL))
40+
.andExpect(status().isOk())
41+
.andExpect(jsonPath("$.openapi", is("3.0.1")))
42+
.andExpect(content().json(getContent("results/app227.json"), true));
43+
}
44+
45+
@SpringBootApplication
46+
static class SpringDocTestApp {}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package test.org.springdoc.api.app227.model;
2+
3+
/**
4+
* Base item
5+
*/
6+
public record Item<T>(String id, String type, T resource) {
7+
8+
/**
9+
* Create Item object
10+
*/
11+
public static <T> Item<T> fromPayload(String id, String type, T payload) {
12+
return new Item<>(id, type, payload);
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package test.org.springdoc.api.app227.wrapper;
2+
3+
import org.springframework.http.HttpStatusCode;
4+
import org.springframework.http.ResponseEntity;
5+
import test.org.springdoc.api.app227.model.Item;
6+
7+
public class ResponseEntityWrapper<T> extends ResponseEntity<Item<T>> {
8+
public ResponseEntityWrapper(Item<T> body, HttpStatusCode status) {
9+
super(body, status);
10+
}
11+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"openapi": "3.0.1",
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+
"/persons": {
15+
"get": {
16+
"tags": [
17+
"hello-controller"
18+
],
19+
"operationId": "persons",
20+
"responses": {
21+
"200": {
22+
"description": "OK",
23+
"content": {
24+
"*/*": {
25+
"schema": {
26+
"$ref": "#/components/schemas/ItemString"
27+
}
28+
}
29+
}
30+
}
31+
}
32+
}
33+
}
34+
},
35+
"components": {
36+
"schemas": {
37+
"ItemString": {
38+
"type": "object",
39+
"properties": {
40+
"id": {
41+
"type": "string"
42+
},
43+
"type": {
44+
"type": "string"
45+
},
46+
"resource": {
47+
"type": "string"
48+
}
49+
}
50+
}
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)