Skip to content

Commit a63426e

Browse files
committed
Incorrect RequestBody type on schema/ui if class implements Map. Fixes #1428.
1 parent 3de0309 commit a63426e

File tree

7 files changed

+276
-14
lines changed

7 files changed

+276
-14
lines changed

springdoc-openapi-common/src/main/java/org/springdoc/core/AbstractRequestService.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,6 @@ else if (!RequestMethod.GET.equals(requestMethod)) {
292292
}
293293
applyBeanValidatorAnnotations(requestBodyInfo.getRequestBody(), parameterAnnotations, methodParameter.isOptional());
294294
}
295-
296295
customiseParameter(parameter, parameterInfo, operationParameters);
297296
}
298297
}

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

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -120,21 +120,26 @@ public static Schema extractSchema(Components components, Type returnType, JsonV
120120
LOGGER.warn(Constants.GRACEFUL_EXCEPTION_OCCURRED, e);
121121
return null;
122122
}
123-
if (resolvedSchema.schema != null) {
124-
schemaN = resolvedSchema.schema;
123+
if (resolvedSchema != null) {
125124
Map<String, Schema> schemaMap = resolvedSchema.referencedSchemas;
126-
if (schemaMap != null) {
127-
for (Map.Entry<String, Schema> entry : schemaMap.entrySet()) {
128-
Map<String, Schema> componentSchemas = components.getSchemas();
129-
if (componentSchemas == null) {
130-
componentSchemas = new LinkedHashMap<>();
131-
componentSchemas.put(entry.getKey(), entry.getValue());
132-
}
133-
else if (!componentSchemas.containsKey(entry.getKey())) {
134-
componentSchemas.put(entry.getKey(), entry.getValue());
135-
}
136-
components.setSchemas(componentSchemas);
125+
if (!CollectionUtils.isEmpty(schemaMap) && components != null) {
126+
Map<String, Schema> componentSchemas = components.getSchemas();
127+
if (componentSchemas == null) {
128+
componentSchemas = new LinkedHashMap<>();
129+
componentSchemas.putAll(schemaMap);
137130
}
131+
else
132+
for (Map.Entry<String, Schema> entry : schemaMap.entrySet())
133+
if (!componentSchemas.containsKey(entry.getKey()))
134+
componentSchemas.put(entry.getKey(), entry.getValue());
135+
components.setSchemas(componentSchemas);
136+
}
137+
if (resolvedSchema.schema != null) {
138+
schemaN = new Schema();
139+
if (StringUtils.isNotBlank(resolvedSchema.schema.getName()))
140+
schemaN.set$ref(COMPONENTS_REF + resolvedSchema.schema.getName());
141+
else
142+
schemaN = resolvedSchema.schema;
138143
}
139144
}
140145
return schemaN;
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package test.org.springdoc.api.app180;
2+
3+
import java.util.Collection;
4+
import java.util.Map;
5+
import java.util.Set;
6+
7+
import io.swagger.v3.oas.annotations.media.Schema;
8+
9+
10+
@Schema(name = "Body", description = "Body", example = "{\"key\":\"value\"}")
11+
public class Body implements Map<String, Object>, MapExclusion {
12+
13+
@Schema(hidden = true)
14+
private Map<String, Object> data;
15+
16+
public Map<String, Object> getData() {
17+
return data;
18+
}
19+
20+
public void setData(Map<String, Object> data) {
21+
this.data = data;
22+
}
23+
24+
@Override
25+
public int size() {
26+
return 0;
27+
}
28+
29+
@Override
30+
public boolean isEmpty() {
31+
return false;
32+
}
33+
34+
@Override
35+
public boolean containsKey(Object key) {
36+
return false;
37+
}
38+
39+
@Override
40+
public boolean containsValue(Object value) {
41+
return false;
42+
}
43+
44+
@Override
45+
public Object get(Object key) {
46+
return null;
47+
}
48+
49+
@Override
50+
public Object put(String key, Object value) {
51+
return null;
52+
}
53+
54+
@Override
55+
public Object remove(Object key) {
56+
return null;
57+
}
58+
59+
@Override
60+
public void putAll(Map<? extends String, ?> m) {
61+
62+
}
63+
64+
@Override
65+
public void clear() {
66+
67+
}
68+
69+
@Override
70+
public Set<String> keySet() {
71+
return null;
72+
}
73+
74+
@Override
75+
public Collection<Object> values() {
76+
return null;
77+
}
78+
79+
@Override
80+
public Set<Entry<String, Object>> entrySet() {
81+
return null;
82+
}
83+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package test.org.springdoc.api.app180;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnore;
4+
5+
public interface MapExclusion {
6+
@JsonIgnore
7+
boolean isEmpty();
8+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package test.org.springdoc.api.app180;
2+
3+
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.media.Content;
5+
import io.swagger.v3.oas.annotations.media.Schema;
6+
import io.swagger.v3.oas.annotations.tags.Tag;
7+
8+
import org.springframework.web.bind.annotation.PostMapping;
9+
import org.springframework.web.bind.annotation.RequestBody;
10+
import org.springframework.web.bind.annotation.RequestMapping;
11+
import org.springframework.web.bind.annotation.RestController;
12+
13+
@RestController
14+
@RequestMapping("api")
15+
@Tag(name = "REST Service")
16+
public class RESTService {
17+
18+
@PostMapping("/testWithoutSchema")
19+
@Operation(summary = "Test Request Body type Schema usage [Error]")
20+
public String withoutSchema(@io.swagger.v3.oas.annotations.parameters.RequestBody(required = true)
21+
@RequestBody Body body) {
22+
return "without proper schema";
23+
}
24+
25+
@PostMapping("/testWithSchema")
26+
@Operation(summary = "Test Request Body type Schema usage [Correct]")
27+
public String withSchema(@io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = @Content(schema = @Schema(implementation = Body.class)))
28+
@RequestBody Body body) {
29+
return "with proper schema";
30+
}
31+
32+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
*
3+
* *
4+
* * *
5+
* * * * Copyright 2019-2020 the original author or authors.
6+
* * * *
7+
* * * * Licensed under the Apache License, Version 2.0 (the "License");
8+
* * * * you may not use this file except in compliance with the License.
9+
* * * * You may obtain a copy of the License at
10+
* * * *
11+
* * * * https://www.apache.org/licenses/LICENSE-2.0
12+
* * * *
13+
* * * * Unless required by applicable law or agreed to in writing, software
14+
* * * * distributed under the License is distributed on an "AS IS" BASIS,
15+
* * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* * * * See the License for the specific language governing permissions and
17+
* * * * limitations under the License.
18+
* * *
19+
* *
20+
*
21+
*
22+
*/
23+
24+
package test.org.springdoc.api.app180;
25+
26+
import test.org.springdoc.api.AbstractSpringDocTest;
27+
28+
import org.springframework.boot.autoconfigure.SpringBootApplication;
29+
30+
class SpringDocApp180Test extends AbstractSpringDocTest {
31+
32+
@SpringBootApplication
33+
static class SpringDocTestApp {}
34+
35+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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+
"tags": [
14+
{
15+
"name": "REST Service"
16+
}
17+
],
18+
"paths": {
19+
"/api/testWithoutSchema": {
20+
"post": {
21+
"tags": [
22+
"REST Service"
23+
],
24+
"summary": "Test Request Body type Schema usage [Error]",
25+
"operationId": "withoutSchema",
26+
"requestBody": {
27+
"content": {
28+
"application/json": {
29+
"schema": {
30+
"$ref": "#/components/schemas/Body"
31+
}
32+
}
33+
},
34+
"required": true
35+
},
36+
"responses": {
37+
"200": {
38+
"description": "OK",
39+
"content": {
40+
"*/*": {
41+
"schema": {
42+
"type": "string"
43+
}
44+
}
45+
}
46+
}
47+
}
48+
}
49+
},
50+
"/api/testWithSchema": {
51+
"post": {
52+
"tags": [
53+
"REST Service"
54+
],
55+
"summary": "Test Request Body type Schema usage [Correct]",
56+
"operationId": "withSchema",
57+
"requestBody": {
58+
"content": {
59+
"application/json": {
60+
"schema": {
61+
"$ref": "#/components/schemas/Body"
62+
}
63+
}
64+
},
65+
"required": true
66+
},
67+
"responses": {
68+
"200": {
69+
"description": "OK",
70+
"content": {
71+
"*/*": {
72+
"schema": {
73+
"type": "string"
74+
}
75+
}
76+
}
77+
}
78+
}
79+
}
80+
}
81+
},
82+
"components": {
83+
"schemas": {
84+
"Body": {
85+
"type": "object",
86+
"additionalProperties": {
87+
"type": "object",
88+
"description": "Body",
89+
"example": {
90+
"key": "value"
91+
}
92+
},
93+
"description": "Body",
94+
"example": {
95+
"key": "value"
96+
}
97+
}
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)