Skip to content

Commit 31dae33

Browse files
committed
enhacement for #1128
1 parent 3d88e14 commit 31dae33

File tree

10 files changed

+314
-4
lines changed

10 files changed

+314
-4
lines changed

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import java.beans.PropertyDescriptor;
2525
import java.lang.annotation.Annotation;
2626
import java.lang.reflect.Field;
27+
import java.lang.reflect.Type;
28+
import java.lang.reflect.TypeVariable;
2729
import java.time.Duration;
2830
import java.time.LocalTime;
2931
import java.util.ArrayList;
@@ -131,10 +133,34 @@ private static Stream<MethodParameter> extractFrom(Class<?> clazz, String fieldN
131133
private static Stream<MethodParameter> fromGetterOfField(Class<?> paramClass, Field field, String fieldNamePrefix) {
132134
if (isSimpleType(field.getType()))
133135
return fromSimpleClass(paramClass, field, fieldNamePrefix);
136+
else if (field.getGenericType() instanceof TypeVariable<?>)
137+
return extractTypeParameter(paramClass, (TypeVariable<?>) field.getGenericType(), field, fieldNamePrefix);
134138
else
135139
return extractFrom(field.getType(), fieldNamePrefix + field.getName() + ".");
136140
}
137141

142+
/**
143+
* Extract type parameter stream.
144+
*
145+
* @param owningClass the owning class
146+
* @param genericType the generic type
147+
* @param field the field
148+
* @param fieldNamePrefix the field name prefix
149+
* @return the stream
150+
*/
151+
private static Stream<MethodParameter> extractTypeParameter(
152+
Class<?> owningClass,
153+
TypeVariable<?> genericType,
154+
Field field,
155+
String fieldNamePrefix) {
156+
157+
Type resolvedType = ReturnTypeParser.resolveType(genericType, owningClass);
158+
if (resolvedType instanceof Class<?> && isSimpleType((Class<?>) resolvedType)) {
159+
return fromSimpleClass(owningClass, field, fieldNamePrefix);
160+
}
161+
return Stream.empty();
162+
}
163+
138164
/**
139165
* From simple class stream.
140166
*
@@ -262,4 +288,4 @@ private static Nullable getNullable() {
262288
return null;
263289
}
264290
}
265-
}
291+
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,10 @@ default Type getReturnType(MethodParameter methodParameter) {
191191
* @return the type
192192
*/
193193
static Type getType(MethodParameter methodParameter) {
194-
if (methodParameter.getGenericParameterType() instanceof ParameterizedType)
195-
return ReturnTypeParser.resolveType(methodParameter.getGenericParameterType(), methodParameter.getContainingClass());
194+
Type genericParameterType = methodParameter.getGenericParameterType();
195+
if (genericParameterType instanceof ParameterizedType || genericParameterType instanceof TypeVariable )
196+
return ReturnTypeParser.resolveType(genericParameterType, methodParameter.getContainingClass());
196197
return methodParameter.getParameterType();
197198
}
198199

199200
}
200-
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package test.org.springdoc.api.app155;
2+
3+
public class AbstractIntParameterObject<T extends Integer> {
4+
5+
int primitiveBaseField;
6+
7+
T genericField;
8+
9+
public int getPrimitiveBaseField() {
10+
return primitiveBaseField;
11+
}
12+
13+
public void setPrimitiveBaseField(int primitiveBaseField) {
14+
this.primitiveBaseField = primitiveBaseField;
15+
}
16+
17+
public T getGenericField() {
18+
return genericField;
19+
}
20+
21+
public void setGenericField(T genericField) {
22+
this.genericField = genericField;
23+
}
24+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package test.org.springdoc.api.app155;
2+
3+
import io.swagger.v3.oas.annotations.Parameter;
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
6+
public class AbstractParameterObject<T extends Enum<T>> {
7+
8+
int primitiveBaseField;
9+
10+
@Parameter(schema=@Schema(type = "string", allowableValues = {"ONE", "TWO"}) )
11+
T genericField;
12+
13+
public int getPrimitiveBaseField() {
14+
return primitiveBaseField;
15+
}
16+
17+
public void setPrimitiveBaseField(int primitiveBaseField) {
18+
this.primitiveBaseField = primitiveBaseField;
19+
}
20+
21+
public T getGenericField() {
22+
return genericField;
23+
}
24+
25+
public void setGenericField(T genericField) {
26+
this.genericField = genericField;
27+
}
28+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package test.org.springdoc.api.app155;
2+
3+
4+
5+
enum ConcreteEnum {
6+
ONE,
7+
TWO
8+
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package test.org.springdoc.api.app155;
2+
3+
public class ConcreteIntParameterObject extends AbstractIntParameterObject<Integer>{
4+
5+
int primitiveConcreteField;
6+
7+
public int getPrimitiveConcreteField() {
8+
return primitiveConcreteField;
9+
}
10+
11+
public void setPrimitiveConcreteField(int primitiveConcreteField) {
12+
this.primitiveConcreteField = primitiveConcreteField;
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package test.org.springdoc.api.app155;
2+
3+
public class ConcreteParameterObject extends AbstractParameterObject<ConcreteEnum> {
4+
5+
int primitiveConcreteField;
6+
7+
public int getPrimitiveConcreteField() {
8+
return primitiveConcreteField;
9+
}
10+
11+
public void setPrimitiveConcreteField(int primitiveConcreteField) {
12+
this.primitiveConcreteField = primitiveConcreteField;
13+
}
14+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
*
3+
* * Copyright 2019-2020 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.app155;
20+
21+
import org.springdoc.api.annotations.ParameterObject;
22+
23+
import org.springframework.http.HttpStatus;
24+
import org.springframework.http.ResponseEntity;
25+
import org.springframework.web.bind.annotation.GetMapping;
26+
import org.springframework.web.bind.annotation.RestController;
27+
28+
@RestController
29+
public class HelloController {
30+
31+
@GetMapping( "/test1")
32+
public ResponseEntity<String> sayHello( @ParameterObject final ConcreteParameterObject test) {
33+
System.out.println("Field B = " + test);
34+
return new ResponseEntity<String>("{\"Say\": \"Hello\"}", HttpStatus.OK);
35+
}
36+
37+
@GetMapping( "/test2")
38+
public ResponseEntity<String> sayHello( @ParameterObject final ConcreteIntParameterObject test) {
39+
System.out.println("Field B = " + test);
40+
return new ResponseEntity<String>("{\"Say\": \"Hello\"}", HttpStatus.OK);
41+
}
42+
43+
44+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
*
3+
* * Copyright 2019-2020 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.app155;
20+
21+
22+
import test.org.springdoc.api.AbstractSpringDocTest;
23+
24+
import org.springframework.boot.autoconfigure.SpringBootApplication;
25+
26+
/**
27+
* Tests Spring meta-annotations as method parameters
28+
*/
29+
public class SpringDocApp155Test extends AbstractSpringDocTest {
30+
31+
@SpringBootApplication
32+
static class SpringDocTestApp {}
33+
34+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
"/test2": {
15+
"get": {
16+
"tags": [
17+
"hello-controller"
18+
],
19+
"operationId": "sayHello",
20+
"parameters": [
21+
{
22+
"name": "primitiveConcreteField",
23+
"in": "query",
24+
"required": false,
25+
"schema": {
26+
"type": "integer",
27+
"format": "int32"
28+
}
29+
},
30+
{
31+
"name": "primitiveBaseField",
32+
"in": "query",
33+
"required": false,
34+
"schema": {
35+
"type": "integer",
36+
"format": "int32"
37+
}
38+
},
39+
{
40+
"name": "genericField",
41+
"in": "query",
42+
"required": false,
43+
"schema": {
44+
"type": "integer",
45+
"format": "int32"
46+
}
47+
}
48+
],
49+
"responses": {
50+
"200": {
51+
"description": "OK",
52+
"content": {
53+
"*/*": {
54+
"schema": {
55+
"type": "string"
56+
}
57+
}
58+
}
59+
}
60+
}
61+
}
62+
},
63+
"/test1": {
64+
"get": {
65+
"tags": [
66+
"hello-controller"
67+
],
68+
"operationId": "sayHello_1",
69+
"parameters": [
70+
{
71+
"name": "primitiveConcreteField",
72+
"in": "query",
73+
"required": false,
74+
"schema": {
75+
"type": "integer",
76+
"format": "int32"
77+
}
78+
},
79+
{
80+
"name": "primitiveBaseField",
81+
"in": "query",
82+
"required": false,
83+
"schema": {
84+
"type": "integer",
85+
"format": "int32"
86+
}
87+
},
88+
{
89+
"name": "genericField",
90+
"in": "query",
91+
"required": false,
92+
"schema": {
93+
"type": "string",
94+
"enum": [
95+
"ONE",
96+
"TWO"
97+
]
98+
}
99+
}
100+
],
101+
"responses": {
102+
"200": {
103+
"description": "OK",
104+
"content": {
105+
"*/*": {
106+
"schema": {
107+
"type": "string"
108+
}
109+
}
110+
}
111+
}
112+
}
113+
}
114+
}
115+
},
116+
"components": {}
117+
}

0 commit comments

Comments
 (0)