Skip to content

Commit 8e15011

Browse files
authored
Merge branch 'master' into master-4988
2 parents 1caf4f6 + 72c43ab commit 8e15011

File tree

5 files changed

+230
-4
lines changed

5 files changed

+230
-4
lines changed

shenyu-admin/src/main/resources/sql-script/h2/schema.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,
840840
INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172895', '38', 'password', 'password', 2, 3, 7, '{"required":"1","defaultValue":""}');
841841
INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172896', '38', 'engine', 'engine', 3, 3, 8, '{"required":"0","defaultValue":"MergeTree"}');
842842
INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172897', '38', 'clusterName', 'clusterName', 3, 3, 9, '{"required":"1","defaultValue":"cluster"}');
843-
INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172777', '38', 'ttl', 'ttl', 3, 3, 10, '{\"required\":\"0\",\"defaultValue\":\"30\"}');
843+
INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1529402613204172777', '38', 'ttl', 'ttl', 3, 3, 10, '{"required":"0","defaultValue":"30"}');
844844

845845
INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1570590990341775360', '39', 'endpoint', 'casdoor endpoint', 2, 3, 0, '{"required":"1","rule":""}');
846846
INSERT IGNORE INTO plugin_handle (`id`, `plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES ('1570591047635968000', '39', 'client_id', 'client_id', 2, 3, 0, '{"required":"1","rule":""}');

shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/client/AbstractContextRefreshedEventListener.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,9 @@ private String buildDocumentJson(final List<String> tags, final String path, fin
263263
.put("tags", tags)
264264
.put("operationId", path)
265265
.put("parameters", OpenApiUtils.generateDocumentParameters(path, method))
266-
.put("responses", OpenApiUtils.generateDocumentResponse(path)).build();
266+
.put("responses", OpenApiUtils.generateDocumentResponse(path))
267+
.put("responseType", Collections.singletonList(OpenApiUtils.parseReturnType(method)))
268+
.build();
267269
return GsonUtils.getInstance().toJson(documentMap);
268270
}
269271

shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/register/registrar/AbstractApiDocRegistrar.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import java.lang.reflect.Method;
4343
import java.util.ArrayList;
4444
import java.util.Arrays;
45+
import java.util.Collections;
4546
import java.util.List;
4647
import java.util.Map;
4748

@@ -131,7 +132,9 @@ private String buildDocumentJson(final List<String> tags, final String path, fin
131132
.put("tags", tags)
132133
.put("operationId", path)
133134
.put("parameters", OpenApiUtils.generateDocumentParameters(path, method))
134-
.put("responses", OpenApiUtils.generateDocumentResponse(path)).build();
135+
.put("responses", OpenApiUtils.generateDocumentResponse(path))
136+
.put("responseType", Collections.singletonList(OpenApiUtils.parseReturnType(method)))
137+
.build();
135138
return GsonUtils.getInstance().toJson(documentMap);
136139
}
137140

shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/register/registrar/ApiDocRegistrarImpl.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ private String getDocument(final ApiBean.ApiDefinition api) {
136136
.put("tags", buildTags(api))
137137
.put("operationId", path)
138138
.put("parameters", OpenApiUtils.generateDocumentParameters(path, api.getApiMethod()))
139-
.put("responses", OpenApiUtils.generateDocumentResponse(path)).build();
139+
.put("responses", OpenApiUtils.generateDocumentResponse(path))
140+
.put("responseType", Collections.singletonList(OpenApiUtils.parseReturnType(api.getApiMethod())))
141+
.build();
140142
return GsonUtils.getInstance().toJson(documentMap);
141143
}
142144

shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/utils/OpenApiUtils.java

+219
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,25 @@
2525
import org.springframework.web.bind.annotation.RequestPart;
2626

2727
import java.lang.annotation.Annotation;
28+
import java.lang.reflect.Field;
29+
import java.lang.reflect.GenericArrayType;
2830
import java.lang.reflect.Method;
31+
import java.lang.reflect.Modifier;
32+
import java.lang.reflect.ParameterizedType;
33+
import java.lang.reflect.Type;
34+
import java.lang.reflect.TypeVariable;
35+
import java.lang.reflect.WildcardType;
36+
import java.time.LocalDate;
37+
import java.time.LocalDateTime;
38+
import java.time.LocalTime;
2939
import java.util.ArrayList;
40+
import java.util.Collection;
41+
import java.util.Collections;
42+
import java.util.Date;
43+
import java.util.HashMap;
3044
import java.util.List;
3145
import java.util.Map;
46+
import java.util.Objects;
3247

3348
/**
3449
* openApiUtils.
@@ -150,6 +165,210 @@ public static Map<String, Object> generateDocumentResponse(final String path) {
150165
.build();
151166
}
152167

168+
/**
169+
* Perhaps a better way is to generate API documentation through OpenAPI annotations.
170+
*
171+
* @param method the method
172+
* @return return type
173+
*/
174+
public static ResponseType parseReturnType(final Method method) {
175+
Type returnType = method.getGenericReturnType();
176+
return parseType("ROOT", returnType, 0, new HashMap<>(16));
177+
}
178+
179+
private static ResponseType parseType(final String name, final Type type, final int depth, final Map<TypeVariable<?>, Type> typeVariableMap) {
180+
ResponseType responseType = new ResponseType();
181+
if (StringUtils.isBlank(name)) {
182+
responseType.setName(type.getTypeName());
183+
} else {
184+
responseType.setName(name);
185+
}
186+
if (depth > 5) {
187+
responseType.setType("object");
188+
return responseType;
189+
}
190+
if (type instanceof Class) {
191+
return parseClass(responseType, (Class<?>) type, depth, typeVariableMap);
192+
} else if (type instanceof ParameterizedType) {
193+
return parseParameterizedType(responseType, (ParameterizedType) type, depth, typeVariableMap);
194+
} else if (type instanceof GenericArrayType) {
195+
return parseGenericArrayType(responseType, (GenericArrayType) type, depth, typeVariableMap);
196+
} else if (type instanceof TypeVariable) {
197+
Type actualType = typeVariableMap.get(type);
198+
if (Objects.nonNull(actualType)) {
199+
return parseType(name, actualType, depth, typeVariableMap);
200+
} else if (((TypeVariable<?>) type).getBounds().length > 0) {
201+
Type upperBound = ((TypeVariable<?>) type).getBounds()[0];
202+
return parseType(name, upperBound, depth, typeVariableMap);
203+
} else {
204+
responseType.setType("object");
205+
return responseType;
206+
}
207+
} else if (type instanceof WildcardType) {
208+
responseType.setType("object");
209+
return responseType;
210+
} else {
211+
responseType.setType("object");
212+
return responseType;
213+
}
214+
}
215+
216+
private static ResponseType parseClass(final ResponseType responseType, final Class<?> clazz, final int depth, final Map<TypeVariable<?>, Type> typeVariableMap) {
217+
if (clazz.isArray()) {
218+
responseType.setType("array");
219+
responseType.setRefs(Collections.singletonList(parseType("ITEMS", clazz.getComponentType(), depth + 1, typeVariableMap)));
220+
return responseType;
221+
} else if (clazz.isEnum()) {
222+
responseType.setType("string");
223+
return responseType;
224+
} else if (isBooleanType(clazz)) {
225+
responseType.setType("boolean");
226+
return responseType;
227+
} else if (isIntegerType(clazz)) {
228+
responseType.setType("integer");
229+
return responseType;
230+
} else if (isNumberType(clazz)) {
231+
responseType.setType("number");
232+
return responseType;
233+
} else if (isStringType(clazz)) {
234+
responseType.setType("string");
235+
return responseType;
236+
} else if (isDateType(clazz)) {
237+
responseType.setType("date");
238+
return responseType;
239+
} else {
240+
List<ResponseType> refs = new ArrayList<>();
241+
for (Field field : clazz.getDeclaredFields()) {
242+
if (Modifier.isStatic(field.getModifiers())) {
243+
continue;
244+
}
245+
refs.add(parseType(field.getName(), field.getGenericType(), depth + 1, typeVariableMap));
246+
}
247+
responseType.setType("object");
248+
responseType.setRefs(refs);
249+
return responseType;
250+
}
251+
}
252+
253+
private static ResponseType parseParameterizedType(final ResponseType responseType, final ParameterizedType type, final int depth, final Map<TypeVariable<?>, Type> typeVariableMap) {
254+
Class<?> rawType = (Class<?>) type.getRawType();
255+
Type[] actualTypeArguments = type.getActualTypeArguments();
256+
TypeVariable<?>[] typeVariables = rawType.getTypeParameters();
257+
Map<TypeVariable<?>, Type> newTypeVariableMap = new HashMap<>(typeVariableMap);
258+
for (int i = 0; i < typeVariables.length; i++) {
259+
newTypeVariableMap.put(typeVariables[i], actualTypeArguments[i]);
260+
}
261+
if (Collection.class.isAssignableFrom(rawType)) {
262+
Type actualType = actualTypeArguments[0];
263+
ResponseType elementParam = parseType("ITEMS", actualType, depth + 1, newTypeVariableMap);
264+
responseType.setRefs(Collections.singletonList(elementParam));
265+
responseType.setType("array");
266+
return responseType;
267+
} else if (Map.class.isAssignableFrom(rawType)) {
268+
Type keyType = actualTypeArguments[0];
269+
Type valueType = actualTypeArguments[1];
270+
ResponseType keyParam = parseType("key", keyType, depth + 1, newTypeVariableMap);
271+
ResponseType valueParam = parseType("value", valueType, depth + 1, newTypeVariableMap);
272+
List<ResponseType> children = new ArrayList<>();
273+
children.add(keyParam);
274+
children.add(valueParam);
275+
responseType.setRefs(children);
276+
responseType.setType("map");
277+
return responseType;
278+
} else {
279+
List<ResponseType> refs = new ArrayList<>();
280+
for (Field field : rawType.getDeclaredFields()) {
281+
if (Modifier.isStatic(field.getModifiers())) {
282+
continue;
283+
}
284+
ResponseType fieldParam = parseType(field.getName(), field.getGenericType(), depth + 1, newTypeVariableMap);
285+
refs.add(fieldParam);
286+
}
287+
responseType.setType("object");
288+
responseType.setRefs(refs);
289+
return responseType;
290+
}
291+
}
292+
293+
private static ResponseType parseGenericArrayType(final ResponseType responseType, final GenericArrayType type, final int depth, final Map<TypeVariable<?>, Type> typeVariableMap) {
294+
responseType.setRefs(Collections.singletonList(parseType("ITEMS", type.getGenericComponentType(), depth + 1, typeVariableMap)));
295+
responseType.setType("array");
296+
return responseType;
297+
}
298+
299+
private static boolean isDateType(final Class<?> clazz) {
300+
return clazz == Date.class || clazz == LocalDate.class
301+
|| clazz == LocalDateTime.class || clazz == LocalTime.class;
302+
}
303+
304+
private static boolean isStringType(final Class<?> clazz) {
305+
return CharSequence.class.isAssignableFrom(clazz) || clazz == char.class
306+
|| clazz == Character.class;
307+
}
308+
309+
private static boolean isBooleanType(final Class<?> clazz) {
310+
return clazz == boolean.class || clazz == Boolean.class;
311+
}
312+
313+
private static boolean isIntegerType(final Class<?> clazz) {
314+
return clazz == byte.class || clazz == Byte.class
315+
|| clazz == short.class || clazz == Short.class
316+
|| clazz == int.class || clazz == Integer.class
317+
|| clazz == long.class || clazz == Long.class;
318+
}
319+
320+
private static boolean isNumberType(final Class<?> clazz) {
321+
return clazz == float.class || clazz == Float.class
322+
|| clazz == double.class || clazz == Double.class;
323+
}
324+
325+
public static class ResponseType {
326+
327+
private String name;
328+
329+
private String description;
330+
331+
private String type;
332+
333+
/**
334+
* child fields.
335+
*/
336+
private List<ResponseType> refs;
337+
338+
public String getName() {
339+
return name;
340+
}
341+
342+
public void setName(final String name) {
343+
this.name = name;
344+
}
345+
346+
public String getDescription() {
347+
return description;
348+
}
349+
350+
public void setDescription(final String description) {
351+
this.description = description;
352+
}
353+
354+
public String getType() {
355+
return type;
356+
}
357+
358+
public void setType(final String type) {
359+
this.type = type;
360+
}
361+
362+
public List<ResponseType> getRefs() {
363+
return refs;
364+
}
365+
366+
public void setRefs(final List<ResponseType> refs) {
367+
this.refs = refs;
368+
}
369+
}
370+
371+
153372
public static class Parameter {
154373

155374
private String name;

0 commit comments

Comments
 (0)