Skip to content

Commit 436681a

Browse files
committed
Merge pull request #537 from junbo/develop
Add @BeanParam support for Jersey2.
2 parents 33424a2 + ee1ed29 commit 436681a

File tree

13 files changed

+137
-90
lines changed

13 files changed

+137
-90
lines changed

modules/swagger-core/src/main/scala/com/wordnik/swagger/converter/ModelConverters.scala

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ object ModelConverters {
2727
else converters += c
2828
}
2929

30+
def removeConverter(c: ModelConverter) = {
31+
converters -= c
32+
}
33+
3034
def read(cls: Class[_], t: Map[String, String] = Map.empty): Option[Model] = {
3135
val types = {
3236
if(t.isEmpty)typeMap

modules/swagger-core/src/test/scala/converter/CustomConverterTest.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ import org.scalatest.matchers.ShouldMatchers
2525
class CustomConverterTest extends FlatSpec with ShouldMatchers {
2626
it should "ignore properties with type Bar" in {
2727
// add the custom converter
28-
ModelConverters.addConverter(new CustomConverter, true)
28+
val customConverter = new CustomConverter
29+
ModelConverters.addConverter(customConverter, true)
2930

3031
// make sure the field bar: converter.Bar is not present
3132
ModelConverters.read(classOf[Foo]) match {
3233
case Some(model) => model.properties.get("bar") should be (None)
3334
case _ => fail("didn't read anything")
3435
}
36+
ModelConverters.removeConverter(customConverter)
3537
}
3638
}
3739

modules/swagger-core/src/test/scala/converter/JaveDateTimeOverride.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ import scala.reflect.BeanProperty
1717

1818
@RunWith(classOf[JUnitRunner])
1919
class JaveDateTimeOverride extends FlatSpec with ShouldMatchers {
20-
ModelConverters.addConverter(new JavaDateTimeConverter, true)
20+
val javaDateTimeConverter = new JavaDateTimeConverter
21+
ModelConverters.addConverter(javaDateTimeConverter, true)
2122
val models = ModelConverters.readAll(classOf[ModelWithDate])
2223
JsonSerializer.asJson(models) should be ("""[{"id":"ModelWithDate","properties":{"dateValue":{"type":"integer","format":"int64"}}}]""")
24+
// cleanup to avoid impacting other test cases with Date model members
25+
ModelConverters.removeConverter(javaDateTimeConverter)
2326
}
2427

2528
class JavaDateTimeConverter extends SwaggerSchemaConverter {

modules/swagger-core/src/test/scala/converter/SnakeCaseConverterTest.scala

+5-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import javax.xml.bind.annotation._
2424
class SnakeCaseConverterTest extends FlatSpec with ShouldMatchers {
2525
it should "ignore properties with type Bar" in {
2626
// add the custom converter
27-
ModelConverters.addConverter(new SnakeCaseConverter, true)
27+
val snakeCaseConverter = new SnakeCaseConverter
28+
ModelConverters.addConverter(snakeCaseConverter, true)
2829

2930
// make sure the field bar: converter.Bar is not present
3031
ModelConverters.read(classOf[SnakeCaseModel]) match {
@@ -34,6 +35,9 @@ class SnakeCaseConverterTest extends FlatSpec with ShouldMatchers {
3435
}
3536
case _ => fail("didn't read anything")
3637
}
38+
39+
// cleanup to avoid impacting other test cases with Date model members
40+
ModelConverters.removeConverter(snakeCaseConverter)
3741
}
3842
}
3943

modules/swagger-jaxrs/src/main/scala/com/wordnik/swagger/jaxrs/JaxrsApiReader.scala

+21-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ trait JaxrsApiReader extends ClassReader with ClassReaderUtils {
2424
val GenericTypeMapper = "([a-zA-Z\\.]*)<([a-zA-Z0-9\\.\\,\\s]*)>".r
2525

2626
// decorates a Parameter based on annotations, returns None if param should be ignored
27-
def processParamAnnotations(mutable: MutableParameter, paramAnnotations: Array[Annotation]): Option[Parameter]
27+
def processParamAnnotations(mutable: MutableParameter, paramAnnotations: Array[Annotation]): List[Parameter]
2828

2929
// Finds the type of the subresource this method produces, in case it's a subresource locator
3030
// In case it's not a subresource locator the entity type is returned
@@ -167,7 +167,7 @@ trait JaxrsApiReader extends ClassReader with ClassReaderUtils {
167167
param.name = TYPE_BODY
168168
param.paramType = TYPE_BODY
169169

170-
Some(param.asParameter)
170+
List(param.asParameter)
171171
}
172172
}).flatten.toList
173173

@@ -264,6 +264,25 @@ trait JaxrsApiReader extends ClassReader with ClassReaderUtils {
264264
}
265265
return fields;
266266
}
267+
268+
def getAllParamsFromFields(cls: Class[_]): List[Parameter] = {
269+
(for(field <- getAllFields(cls)) yield {
270+
// only process fields with @ApiParam, @QueryParam, @HeaderParam, @PathParam
271+
if(field.getAnnotation(classOf[QueryParam]) != null || field.getAnnotation(classOf[HeaderParam]) != null ||
272+
field.getAnnotation(classOf[HeaderParam]) != null || field.getAnnotation(classOf[PathParam]) != null ||
273+
field.getAnnotation(classOf[ApiParam]) != null) {
274+
val param = new MutableParameter
275+
param.dataType = processDataType(field.getType, field.getGenericType)
276+
Option (field.getAnnotation(classOf[ApiParam])) match {
277+
case Some(annotation) => toAllowableValues(annotation.allowableValues)
278+
case _ =>
279+
}
280+
val annotations = field.getAnnotations
281+
processParamAnnotations(param, annotations)
282+
}
283+
else List.empty
284+
}).flatten.toList
285+
}
267286

268287
def pathFromMethod(method: Method): String = {
269288
val path = method.getAnnotation(classOf[javax.ws.rs.Path])

modules/swagger-jaxrs/src/main/scala/com/wordnik/swagger/jaxrs/reader/BasicJaxrsReader.scala

+4-21
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,7 @@ class BasicJaxrsReader extends JaxrsApiReader {
6969
else ((List(), List(), List(), None))
7070
}
7171
// look for method-level annotated properties
72-
val parentParams: List[Parameter] = (for(field <- getAllFields(cls))
73-
yield {
74-
// only process fields with @ApiParam, @QueryParam, @HeaderParam, @PathParam
75-
if(field.getAnnotation(classOf[QueryParam]) != null || field.getAnnotation(classOf[HeaderParam]) != null ||
76-
field.getAnnotation(classOf[HeaderParam]) != null || field.getAnnotation(classOf[PathParam]) != null ||
77-
field.getAnnotation(classOf[ApiParam]) != null) {
78-
val param = new MutableParameter
79-
param.dataType = field.getType.getName
80-
Option (field.getAnnotation(classOf[ApiParam])) match {
81-
case Some(annotation) => toAllowableValues(annotation.allowableValues)
82-
case _ =>
83-
}
84-
val annotations = field.getAnnotations
85-
processParamAnnotations(param, annotations)
86-
}
87-
else None
88-
}
89-
).flatten.toList
72+
val parentParams: List[Parameter] = getAllParamsFromFields(cls)
9073

9174
for(method <- cls.getMethods) {
9275
val returnType = findSubresourceType(method)
@@ -146,7 +129,7 @@ class BasicJaxrsReader extends JaxrsApiReader {
146129
}
147130

148131
// decorates a Parameter based on annotations, returns None if param should be ignored
149-
def processParamAnnotations(mutable: MutableParameter, paramAnnotations: Array[Annotation]): Option[Parameter] = {
132+
def processParamAnnotations(mutable: MutableParameter, paramAnnotations: Array[Annotation]): List[Parameter] = {
150133
var shouldIgnore = false
151134
for (pa <- paramAnnotations) {
152135
pa match {
@@ -188,9 +171,9 @@ class BasicJaxrsReader extends JaxrsApiReader {
188171
mutable.paramType = TYPE_BODY
189172
mutable.name = TYPE_BODY
190173
}
191-
Some(mutable.asParameter)
174+
List(mutable.asParameter)
192175
}
193-
else None
176+
else List.empty
194177
}
195178

196179
def findSubresourceType(method: Method): Class[_] = {

modules/swagger-jaxrs/src/main/scala/com/wordnik/swagger/jaxrs/reader/DefaultJaxrsReader.scala

+4-21
Original file line numberDiff line numberDiff line change
@@ -49,24 +49,7 @@ class DefaultJaxrsApiReader extends JaxrsApiReader {
4949
case _ => None
5050
}
5151
// look for method-level annotated properties
52-
val parentParams: List[Parameter] = (for(field <- getAllFields(cls))
53-
yield {
54-
// only process fields with @ApiParam, @QueryParam, @HeaderParam, @PathParam
55-
if(field.getAnnotation(classOf[QueryParam]) != null || field.getAnnotation(classOf[HeaderParam]) != null ||
56-
field.getAnnotation(classOf[HeaderParam]) != null || field.getAnnotation(classOf[PathParam]) != null ||
57-
field.getAnnotation(classOf[ApiParam]) != null) {
58-
val param = new MutableParameter
59-
param.dataType = field.getType.getName
60-
Option (field.getAnnotation(classOf[ApiParam])) match {
61-
case Some(annotation) => toAllowableValues(annotation.allowableValues)
62-
case _ =>
63-
}
64-
val annotations = field.getAnnotations
65-
processParamAnnotations(param, annotations)
66-
}
67-
else None
68-
}
69-
).flatten.toList
52+
val parentParams: List[Parameter] = getAllParamsFromFields(cls)
7053

7154
for(method <- cls.getMethods) {
7255
val returnType = findSubresourceType(method)
@@ -128,7 +111,7 @@ class DefaultJaxrsApiReader extends JaxrsApiReader {
128111
}
129112

130113
// decorates a Parameter based on annotations, returns None if param should be ignored
131-
def processParamAnnotations(mutable: MutableParameter, paramAnnotations: Array[Annotation]): Option[Parameter] = {
114+
def processParamAnnotations(mutable: MutableParameter, paramAnnotations: Array[Annotation]): List[Parameter] = {
132115
var shouldIgnore = false
133116
for (pa <- paramAnnotations) {
134117
pa match {
@@ -170,9 +153,9 @@ class DefaultJaxrsApiReader extends JaxrsApiReader {
170153
mutable.paramType = TYPE_BODY
171154
mutable.name = TYPE_BODY
172155
}
173-
Some(mutable.asParameter)
156+
List(mutable.asParameter)
174157
}
175-
else None
158+
else List.empty
176159
}
177160

178161
def findSubresourceType(method: Method): Class[_] = {

modules/swagger-jaxrs/src/test/scala/PathParamTargetTest.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class JavaPathParamTargetTest extends FlatSpec with ShouldMatchers {
8989

9090
// verify the 2nd api
9191
val detailsOps = apis.filter(_.path == "/javaPathParamTest/{id}/details").head.operations
92-
val detailOp = detailsOps.head
92+
val detailOp = detailsOps.filter(_.method == "POST").head
9393

9494
detailOp.parameters.size should be (3)
9595

modules/swagger-jersey-jaxrs/src/main/scala/com/wordnik/swagger/jersey/JerseyApiReader.scala

+4-21
Original file line numberDiff line numberDiff line change
@@ -75,24 +75,7 @@ class JerseyApiReader extends JaxrsApiReader {
7575
case _ => None
7676
}
7777
// look for method-level annotated properties
78-
val parentParams: List[Parameter] = (for(field <- getAllFields(cls))
79-
yield {
80-
// only process fields with @ApiParam, @QueryParam, @HeaderParam, @PathParam
81-
if(field.getAnnotation(classOf[QueryParam]) != null || field.getAnnotation(classOf[HeaderParam]) != null ||
82-
field.getAnnotation(classOf[HeaderParam]) != null || field.getAnnotation(classOf[PathParam]) != null ||
83-
field.getAnnotation(classOf[ApiParam]) != null) {
84-
val param = new MutableParameter
85-
param.dataType = field.getType.getName
86-
Option (field.getAnnotation(classOf[ApiParam])) match {
87-
case Some(annotation) => toAllowableValues(annotation.allowableValues)
88-
case _ =>
89-
}
90-
val annotations = field.getAnnotations
91-
processParamAnnotations(param, annotations)
92-
}
93-
else None
94-
}
95-
).flatten.toList
78+
val parentParams: List[Parameter] = getAllParamsFromFields(cls)
9679

9780
for(method <- cls.getMethods) {
9881
val returnType = findSubresourceType(method)
@@ -153,7 +136,7 @@ class JerseyApiReader extends JaxrsApiReader {
153136
else None
154137
}
155138

156-
def processParamAnnotations(mutable: MutableParameter, paramAnnotations: Array[Annotation]): Option[Parameter] = {
139+
def processParamAnnotations(mutable: MutableParameter, paramAnnotations: Array[Annotation]): List[Parameter] = {
157140
var shouldIgnore = false
158141
for (pa <- paramAnnotations) {
159142
pa match {
@@ -211,9 +194,9 @@ class JerseyApiReader extends JaxrsApiReader {
211194
mutable.paramType = TYPE_BODY
212195
mutable.name = TYPE_BODY
213196
}
214-
Some(mutable.asParameter)
197+
List(mutable.asParameter)
215198
}
216-
else None
199+
else List()
217200
}
218201

219202
def findSubresourceType(method: Method): Class[_] = {

modules/swagger-jersey2-jaxrs/src/main/scala/com/wordnik/swagger/jersey/JerseyApiReader.scala

+8-21
Original file line numberDiff line numberDiff line change
@@ -75,24 +75,7 @@ class JerseyApiReader extends JaxrsApiReader {
7575
case _ => None
7676
}
7777
// look for method-level annotated properties
78-
val parentParams: List[Parameter] = (for(field <- getAllFields(cls))
79-
yield {
80-
// only process fields with @ApiParam, @QueryParam, @HeaderParam, @PathParam
81-
if(field.getAnnotation(classOf[QueryParam]) != null || field.getAnnotation(classOf[HeaderParam]) != null ||
82-
field.getAnnotation(classOf[HeaderParam]) != null || field.getAnnotation(classOf[PathParam]) != null ||
83-
field.getAnnotation(classOf[ApiParam]) != null) {
84-
val param = new MutableParameter
85-
param.dataType = field.getType.getName
86-
Option (field.getAnnotation(classOf[ApiParam])) match {
87-
case Some(annotation) => toAllowableValues(annotation.allowableValues)
88-
case _ =>
89-
}
90-
val annotations = field.getAnnotations
91-
processParamAnnotations(param, annotations)
92-
}
93-
else None
94-
}
95-
).flatten.toList
78+
val parentParams: List[Parameter] = getAllParamsFromFields(cls)
9679

9780
for(method <- cls.getMethods) {
9881
val returnType = findSubresourceType(method)
@@ -153,7 +136,7 @@ class JerseyApiReader extends JaxrsApiReader {
153136
else None
154137
}
155138

156-
def processParamAnnotations(mutable: MutableParameter, paramAnnotations: Array[Annotation]): Option[Parameter] = {
139+
def processParamAnnotations(mutable: MutableParameter, paramAnnotations: Array[Annotation]): List[Parameter] = {
157140
var shouldIgnore = false
158141
for (pa <- paramAnnotations) {
159142
pa match {
@@ -198,6 +181,10 @@ class JerseyApiReader extends JaxrsApiReader {
198181
}
199182
}
200183
}
184+
case e: BeanParam => {
185+
val cls = SwaggerContext.loadClass(mutable.dataType)
186+
return getAllParamsFromFields(cls)
187+
}
201188
case e: Context => shouldIgnore = true
202189
case _ =>
203190
}
@@ -207,9 +194,9 @@ class JerseyApiReader extends JaxrsApiReader {
207194
mutable.paramType = TYPE_BODY
208195
mutable.name = TYPE_BODY
209196
}
210-
Some(mutable.asParameter)
197+
List(mutable.asParameter)
211198
}
212-
else None
199+
else List.empty
213200
}
214201
def findSubresourceType(method: Method): Class[_] = {
215202
method.getGenericReturnType match {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import com.wordnik.swagger.jersey.JerseyApiReader
2+
import testresources._
3+
4+
import com.wordnik.swagger.jaxrs.reader._
5+
import com.wordnik.swagger.model._
6+
import com.wordnik.swagger.config._
7+
8+
import org.junit.runner.RunWith
9+
import org.scalatest.junit.JUnitRunner
10+
import org.scalatest.FlatSpec
11+
import org.scalatest.matchers.ShouldMatchers
12+
13+
@RunWith(classOf[JUnitRunner])
14+
class BeanParamTest extends FlatSpec with ShouldMatchers {
15+
it should "read beanparam parameters" in {
16+
val reader = new JerseyApiReader
17+
val config = new SwaggerConfig()
18+
val apiResource = reader.read("/api-docs", classOf[BeanParamResource], config).getOrElse(fail("should not be None"))
19+
20+
val apis = apiResource.apis
21+
apis.size should be (1)
22+
23+
val ops = apis.head.operations
24+
ops.size should be (1)
25+
26+
val op = ops.head
27+
op.parameters.size should be (3)
28+
29+
val param0 = op.parameters(0)
30+
param0.name should be ("ids")
31+
param0.dataType should be ("Set[string]")
32+
param0.paramType should be ("query")
33+
34+
val param1 = op.parameters(1)
35+
param1.name should be ("startDate")
36+
param1.dataType should be ("Date")
37+
param1.paramType should be ("query")
38+
39+
val param2 = op.parameters(2)
40+
param2.name should be ("name")
41+
param2.dataType should be ("string")
42+
param2.paramType should be ("query")
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package testmodels
2+
3+
import com.wordnik.swagger.annotations.ApiParam
4+
import javax.ws.rs.QueryParam
5+
import java.util.Date
6+
7+
class BeanParamModel {
8+
@ApiParam(value = "sample set param")
9+
@QueryParam("ids")
10+
var ids: Set[String] = _
11+
12+
@ApiParam(value = "sample date param")
13+
@QueryParam("startDate")
14+
var startDate: Date = _
15+
16+
@ApiParam(value = "sample string param")
17+
@QueryParam("name")
18+
var name: String = _
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package testresources
2+
3+
import javax.ws.rs._
4+
import com.wordnik.swagger.annotations._
5+
import testmodels._
6+
import javax.ws.rs.core.Response
7+
8+
@Path("/beanParam")
9+
@Api(value = "/beanParam", description = "Bean Param Resource")
10+
class BeanParamResource {
11+
@GET
12+
@ApiOperation(value = "Search Object", notes = "No details provided", position = 0)
13+
def searchObject(@BeanParam params: BeanParamModel) {
14+
Response.ok.entity("ok").build
15+
}
16+
}

0 commit comments

Comments
 (0)