@@ -20,6 +20,8 @@ import java.lang.reflect.Method
20
20
import javax .ws .rs .core .Context
21
21
import javax .ws .rs ._
22
22
23
+ import scala .collection .mutable .ListBuffer
24
+
23
25
case class RouteEntry (httpMethod : String , path : String )
24
26
25
27
object SwaggerUtils {
@@ -29,9 +31,120 @@ object SwaggerUtils {
29
31
}
30
32
31
33
class PlayApiReader (val routes : Option [Routes ]) extends JaxrsApiReader {
32
-
33
34
private var _routesCache : Map [String , RouteEntry ] = null
34
35
36
+ override
37
+ def readRecursive (
38
+ docRoot : String ,
39
+ parentPath : String , cls : Class [_],
40
+ config : SwaggerConfig ,
41
+ operations : ListBuffer [Tuple3 [String , String , ListBuffer [Operation ]]],
42
+ parentMethods : ListBuffer [Method ]): Option [ApiListing ] = {
43
+ val api = cls.getAnnotation(classOf [Api ])
44
+
45
+ // must have @Api annotation to process!
46
+ if (api != null ) {
47
+ val consumes = Option (api.consumes) match {
48
+ case Some (e) if (e != " " ) => e.split(" ," ).map(_.trim).toList
49
+ case _ => cls.getAnnotation(classOf [Consumes ]) match {
50
+ case e : Consumes => e.value.toList
51
+ case _ => List ()
52
+ }
53
+ }
54
+ val produces = Option (api.produces) match {
55
+ case Some (e) if (e != " " ) => e.split(" ," ).map(_.trim).toList
56
+ case _ => cls.getAnnotation(classOf [Produces ]) match {
57
+ case e : Produces => e.value.toList
58
+ case _ => List ()
59
+ }
60
+ }
61
+ val protocols = Option (api.protocols) match {
62
+ case Some (e) if (e != " " ) => e.split(" ," ).map(_.trim).toList
63
+ case _ => List ()
64
+ }
65
+ val description = api.description match {
66
+ case e : String if (e != " " ) => Some (e)
67
+ case _ => None
68
+ }
69
+ // look for method-level annotated properties
70
+ val parentParams : List [Parameter ] = (for (field <- getAllFields(cls))
71
+ yield {
72
+ // only process fields with @ApiParam, @QueryParam, @HeaderParam, @PathParam
73
+ if (field.getAnnotation(classOf [QueryParam ]) != null || field.getAnnotation(classOf [HeaderParam ]) != null ||
74
+ field.getAnnotation(classOf [HeaderParam ]) != null || field.getAnnotation(classOf [PathParam ]) != null ||
75
+ field.getAnnotation(classOf [ApiParam ]) != null ) {
76
+ val param = new MutableParameter
77
+ param.dataType = field.getType.getName
78
+ Option (field.getAnnotation(classOf [ApiParam ])) match {
79
+ case Some (annotation) => toAllowableValues(annotation.allowableValues)
80
+ case _ =>
81
+ }
82
+ val annotations = field.getAnnotations
83
+ processParamAnnotations(param, annotations)
84
+ }
85
+ else None
86
+ }
87
+ ).flatten.toList
88
+
89
+ for (method <- cls.getMethods) {
90
+ val returnType = findSubresourceType(method)
91
+ val path = method.getAnnotation(classOf [Path ]) match {
92
+ case e : Path => e.value()
93
+ case _ => " "
94
+ }
95
+ val endpoint = (parentPath + pathFromMethod(method)).replace(" //" , " /" )
96
+ Option (returnType.getAnnotation(classOf [Api ])) match {
97
+ case Some (e) => {
98
+ val root = docRoot + api.value + pathFromMethod(method)
99
+ parentMethods += method
100
+ readRecursive(root, endpoint, returnType, config, operations, parentMethods)
101
+ parentMethods -= method
102
+ }
103
+ case _ => {
104
+ if (method.getAnnotation(classOf [ApiOperation ]) != null ) {
105
+ readMethod(method, parentParams, parentMethods) match {
106
+ case Some (op) => appendOperation(endpoint, path, op, operations)
107
+ case None =>
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ // sort them by min position in the operations
114
+ val s = (for (op <- operations) yield {
115
+ (op, op._3.map(_.position).toList.min)
116
+ }).sortWith(_._2 < _._2).toList
117
+ val orderedOperations = new ListBuffer [Tuple3 [String , String , ListBuffer [Operation ]]]
118
+ s.foreach(op => {
119
+ val ops = op._1._3.sortWith(_.position < _.position)
120
+ orderedOperations += Tuple3 (op._1._1, op._1._2, ops)
121
+ })
122
+ val apis = (for ((endpoint, resourcePath, operationList) <- orderedOperations) yield {
123
+ val orderedOperations = new ListBuffer [Operation ]
124
+ operationList.sortWith(_.position < _.position).foreach(e => orderedOperations += e)
125
+ ApiDescription (
126
+ addLeadingSlash(endpoint),
127
+ None ,
128
+ orderedOperations.toList)
129
+ }).toList
130
+ val models = ModelUtil .modelsFromApis(apis)
131
+ Some (ApiListing (
132
+ apiVersion = config.apiVersion,
133
+ swaggerVersion = config.swaggerVersion,
134
+ basePath = config.basePath,
135
+ resourcePath = addLeadingSlash(api.value),
136
+ apis = ModelUtil .stripPackages(apis),
137
+ models = models,
138
+ description = description,
139
+ produces = produces,
140
+ consumes = consumes,
141
+ protocols = protocols,
142
+ position = api.position)
143
+ )
144
+ }
145
+ else None
146
+ }
147
+
35
148
override def read (docRoot : String , cls : Class [_], config : SwaggerConfig ): Option [ApiListing ] = {
36
149
Logger (" swagger" ).debug(" ControllerReader: read(docRoot = %s, cls = %s, config = %s)" .format(docRoot, cls.getName, config.toString))
37
150
val api = cls.getAnnotation(classOf [Api ])
@@ -353,10 +466,10 @@ class PlayApiReader(val routes: Option[Routes]) extends JaxrsApiReader {
353
466
* @deprecated - do not be tempted to use this.... this is here to cover the method in the superclass.
354
467
*/
355
468
@ Deprecated
356
- override def readMethod (method : java.lang.reflect. Method , parentParams : scala. List [com.wordnik.swagger.model. Parameter ], parentMethods : scala.collection.mutable. ListBuffer [java.lang.reflect. Method ]) : com.wordnik.swagger.model. Operation = {
469
+ override def readMethod (method : Method , parentParams : List [Parameter ], parentMethods : ListBuffer [Method ]) : Option [ Operation ] = {
357
470
// don't use this - it is specific to Jax-RS models.
358
471
throw new RuntimeException (" method not in use.." )
359
- null
472
+ None
360
473
}
361
474
362
475
def findSubresourceType (method : Method ): Class [_] = {
0 commit comments