|
18 | 18 |
|
19 | 19 | import com.fasterxml.jackson.databind.JavaType; |
20 | 20 | import com.fasterxml.jackson.databind.type.TypeFactory; |
| 21 | +import com.google.common.collect.Collections2; |
21 | 22 | import io.swagger.annotations.Api; |
22 | 23 | import io.swagger.annotations.ApiImplicitParam; |
23 | 24 | import io.swagger.annotations.ApiImplicitParams; |
24 | 25 | import io.swagger.annotations.ApiOperation; |
| 26 | +import io.swagger.annotations.ApiParam; |
25 | 27 | import io.swagger.annotations.ApiResponse; |
26 | 28 | import io.swagger.annotations.ApiResponses; |
27 | 29 | import io.swagger.annotations.Authorization; |
|
68 | 70 | import javax.ws.rs.HttpMethod; |
69 | 71 | import javax.ws.rs.Produces; |
70 | 72 | import java.lang.annotation.Annotation; |
| 73 | +import java.lang.reflect.Constructor; |
| 74 | +import java.lang.reflect.Field; |
71 | 75 | import java.lang.reflect.Method; |
72 | 76 | import java.lang.reflect.ParameterizedType; |
73 | 77 | import java.lang.reflect.Type; |
74 | 78 | import java.util.ArrayList; |
75 | 79 | import java.util.Arrays; |
| 80 | +import java.util.Collection; |
76 | 81 | import java.util.Collections; |
77 | 82 | import java.util.EnumSet; |
78 | 83 | import java.util.HashMap; |
|
83 | 88 | import java.util.Map; |
84 | 89 | import java.util.Set; |
85 | 90 |
|
| 91 | +import javax.ws.rs.Consumes; |
| 92 | +import javax.ws.rs.HeaderParam; |
| 93 | +import javax.ws.rs.HttpMethod; |
| 94 | +import javax.ws.rs.PathParam; |
| 95 | +import javax.ws.rs.Produces; |
| 96 | +import javax.ws.rs.QueryParam; |
| 97 | + |
| 98 | +import org.apache.commons.lang3.StringUtils; |
| 99 | +import org.slf4j.Logger; |
| 100 | +import org.slf4j.LoggerFactory; |
| 101 | + |
86 | 102 | public class Reader { |
87 | 103 | private static final Logger LOGGER = LoggerFactory.getLogger(Reader.class); |
88 | 104 | private static final String SUCCESSFUL_OPERATION = "successful operation"; |
89 | 105 | private static final String PATH_DELIMITER = "/"; |
90 | 106 |
|
| 107 | + private static final Set<Class<? extends Annotation>> FIELD_ANNOTATIONS; |
91 | 108 | private final ReaderConfig config; |
92 | 109 | private Swagger swagger; |
93 | 110 |
|
| 111 | + static { |
| 112 | + final Set<Class<? extends Annotation>> fieldAnnotations = new HashSet<Class<? extends Annotation>>(); |
| 113 | + fieldAnnotations.add(PathParam.class); |
| 114 | + fieldAnnotations.add(QueryParam.class); |
| 115 | + fieldAnnotations.add(HeaderParam.class); |
| 116 | + fieldAnnotations.add(ApiParam.class); |
| 117 | + fieldAnnotations.add(ApiImplicitParam.class); |
| 118 | + FIELD_ANNOTATIONS = Collections.unmodifiableSet(fieldAnnotations); |
| 119 | + } |
| 120 | + |
94 | 121 | public Reader(Swagger swagger) { |
95 | 122 | this(swagger, null); |
96 | 123 | } |
@@ -270,8 +297,8 @@ protected Swagger read(Class<?> cls, String parentPath, String parentMethod, boo |
270 | 297 | final ApiOperation apiOperation = getAnnotation(method, ApiOperation.class); |
271 | 298 | String httpMethod = extractOperationMethod(apiOperation, method, SwaggerExtensions.chain()); |
272 | 299 |
|
273 | | - Operation operation = parseMethod(method); |
274 | | - if(operation == null) |
| 300 | + Operation operation = parseMethod(method, collectGlobalParameters(cls)); |
| 301 | + if(operation == null) |
275 | 302 | continue; |
276 | 303 | if(parentParameters != null) { |
277 | 304 | for(Parameter param : parentParameters) { |
@@ -668,6 +695,10 @@ public Map<String, Property> parseResponseHeaders(ResponseHeader[] headers) { |
668 | 695 | } |
669 | 696 |
|
670 | 697 | public Operation parseMethod(Method method) { |
| 698 | + return parseMethod(method, Collections.<Parameter> emptyList()); |
| 699 | + } |
| 700 | + |
| 701 | + private Operation parseMethod(Method method, List<Parameter> globalParameters) { |
671 | 702 | Operation operation = new Operation(); |
672 | 703 |
|
673 | 704 | ApiOperation apiOperation = getAnnotation(method, ApiOperation.class); |
@@ -851,6 +882,10 @@ else if(responseType != null && !isVoid(responseType)) { |
851 | 882 | hidden = apiOperation.hidden(); |
852 | 883 |
|
853 | 884 | // process parameters |
| 885 | + for (Parameter globalParameter : globalParameters) { |
| 886 | + operation.parameter(globalParameter); |
| 887 | + } |
| 888 | + |
854 | 889 | Type[] genericParameterTypes = method.getGenericParameterTypes(); |
855 | 890 | Annotation[][] paramAnnotations = method.getParameterAnnotations(); |
856 | 891 | for(int i = 0; i < genericParameterTypes.length; i++) { |
@@ -1005,6 +1040,31 @@ private static boolean isResourceClass(Class<?> cls) { |
1005 | 1040 | return cls.getAnnotation(Api.class) != null; |
1006 | 1041 | } |
1007 | 1042 |
|
| 1043 | + private List<Parameter> collectGlobalParameters(Class<?> cls) { |
| 1044 | + final List<Parameter> globalParameters = new ArrayList<Parameter>(); |
| 1045 | + |
| 1046 | + // look for constructor-level annotated properties |
| 1047 | + final Constructor<?> constructor = ReflectionUtils.findConstructor(cls); |
| 1048 | + if (constructor != null) { |
| 1049 | + final Type[] genericParameterTypes = constructor.getGenericParameterTypes(); |
| 1050 | + final Annotation[][] annotations = constructor.getParameterAnnotations(); |
| 1051 | + for (int i = 0; i < genericParameterTypes.length; i++) { |
| 1052 | + globalParameters.addAll(getParameters(genericParameterTypes[i], Arrays.asList(annotations[i]))); |
| 1053 | + } |
| 1054 | + } |
| 1055 | + |
| 1056 | + // look for field-level annotated properties |
| 1057 | + for (Field field : cls.getDeclaredFields()) { |
| 1058 | + final List<Annotation> annotations = Arrays.asList(field.getAnnotations()); |
| 1059 | + final Collection<Class<? extends Annotation>> types = Collections2.transform(annotations, ReflectionUtils.createAnnotationTypeGetter()); |
| 1060 | + if (!Collections.disjoint(types, FIELD_ANNOTATIONS)) { |
| 1061 | + globalParameters.addAll(getParameters(field.getGenericType(), annotations)); |
| 1062 | + } |
| 1063 | + } |
| 1064 | + |
| 1065 | + return globalParameters; |
| 1066 | + } |
| 1067 | + |
1008 | 1068 | enum ContainerWrapper { |
1009 | 1069 | LIST("list") { |
1010 | 1070 | @Override |
|
0 commit comments