Skip to content

Commit

Permalink
More updates for Java 8 compatibility; Updates for Swagger 1.3.7
Browse files Browse the repository at this point in the history
  • Loading branch information
wkennedy committed Jul 25, 2014
1 parent 59adf85 commit ead17dc
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.config.SwaggerConfig;
import com.wordnik.swagger.model.*;
import org.reflections.ReflectionUtils;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -22,8 +21,6 @@
import java.lang.reflect.Method;
import java.util.*;

import static org.reflections.ReflectionUtils.withAnnotation;

public class ApiParserImpl implements ApiParser {

private static final Logger LOGGER = LoggerFactory.getLogger(ApiParserImpl.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public static List<AnnotatedParameter> getAnnotatedParameters(Method method) {
* @return Set - all methods of this class with the specified annotation
*/
public static Set<Method> getAnnotatedMethods(Class<?> clazz, Class<? extends Annotation> annotationClass) {
Method[] methods = clazz.getMethods();
Method[] methods = clazz.getDeclaredMethods();
Set<Method> annotatedMethods = new HashSet<>(methods.length);
for (Method method : methods) {
if( method.isAnnotationPresent(annotationClass)){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.wordnik.swagger.model.Model;
import org.springframework.web.bind.annotation.ValueConstants;
import org.springframework.web.multipart.MultipartFile;
import scala.Option;
import scala.collection.immutable.HashMap;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
Expand Down Expand Up @@ -66,11 +68,11 @@ static boolean isIgnorableModel(String name) {
}

public static void addModels(final Class<?> clazz, final Map<String, Model> models) {
scala.collection.immutable.List<Model> modelOption = ModelConverters.readAll(clazz);
scala.collection.Iterator<Model> iterator = modelOption.iterator();
while (iterator.hasNext()) {
Model model = iterator.next();
if (!isIgnorableModel(model.name())) {
Option<Model> modelOption = ModelConverters.read(clazz, new HashMap<>());
Model model;
if(!modelOption.isEmpty()) {
model = modelOption.get();
if(!isIgnorableModel(model.name())) {
models.put(model.name(), model);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import java.lang.reflect.{ Method, Type, Field }
import java.lang.annotation.Annotation

import scala.collection.mutable.ListBuffer
import com.knappsack.swagger4springweb.annotation.ApiExclude

trait SpringMVCApiReader extends ClassReader with ClassReaderUtils {

Expand Down Expand Up @@ -80,16 +81,23 @@ trait SpringMVCApiReader extends ClassReader with ClassReaderUtils {
parentParams: List[Parameter],
parentMethods: ListBuffer[Method]
) = {
val api = method.getAnnotation(classOf[Api])
// val api = method.getAnnotation(classOf[Api])
val responseClass = {
val baseName = apiOperation.response.getName
val output = apiOperation.responseContainer match {
case "" => baseName
case e: String => "%s[%s]".format(e, baseName)
if(apiOperation != null){
val baseName = apiOperation.response.getName
val output = apiOperation.responseContainer match {
case "" => baseName
case e: String => "%s[%s]".format(e, baseName)
}
output
}
else {
if(!"javax.ws.rs.core.Response".equals(method.getReturnType.getCanonicalName))
method.getReturnType.getName
else
"void"
}
output
}

var paramAnnotations: Array[Array[java.lang.annotation.Annotation]] = null
var paramTypes: Array[java.lang.Class[_]] = null
var genericParamTypes: Array[java.lang.reflect.Type] = null
Expand All @@ -104,30 +112,41 @@ trait SpringMVCApiReader extends ClassReader with ClassReaderUtils {
genericParamTypes = parentMethods.map(pm => pm.getGenericParameterTypes).reduceRight(_ ++ _) ++ method.getGenericParameterTypes
}

val produces = Option(apiOperation.produces) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => method.getAnnotation(classOf[RequestMapping]).produces() match {
case e: Array[String] => e.toList
case _ => List()
}
}
val consumes = Option(apiOperation.consumes) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => method.getAnnotation(classOf[RequestMapping]).consumes() match {
case e: Array[String] => e.toList
case _ => List()
val (nickname, produces, consumes, protocols, authorizations) = {
if(apiOperation != null) {
(
(if(apiOperation.nickname != null && apiOperation.nickname != "")
apiOperation.nickname
else
method.getName
),
Option(apiOperation.produces) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => method.getAnnotation(classOf[RequestMapping]).produces() match {
case e: Array[String] => e.toList
case _ => List()
}
},
Option(apiOperation.consumes) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => method.getAnnotation(classOf[RequestMapping]).consumes() match {
case e: Array[String] => e.toList
case _ => List()
}
},
Option(apiOperation.protocols) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => List()
},
Option(apiOperation.authorizations) match {
case Some(e) => (for(a <- e) yield {
val scopes = (for(s <- a.scopes) yield com.wordnik.swagger.model.AuthorizationScope(s.scope, s.description)).toArray
new com.wordnik.swagger.model.Authorization(a.value, scopes)
}).toList
case _ => List()
})
}
}
val protocols = Option(apiOperation.protocols) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => List()
}
val authorizations:List[com.wordnik.swagger.model.Authorization] = Option(apiOperation.authorizations) match {
case Some(e) => (for(a <- e) yield {
val scopes = (for(s <- a.scopes) yield com.wordnik.swagger.model.AuthorizationScope(s.scope, s.description)).toArray
new com.wordnik.swagger.model.Authorization(a.value, scopes)
}).toList
case _ => List()
else(method.getName, List(), List(), List(), List())
}
val params = parentParams ++ (for((annotations, paramType, genericParamType) <- (paramAnnotations, paramTypes, genericParamTypes).zipped.toList) yield {
if(annotations.length > 0) {
Expand All @@ -147,38 +166,43 @@ trait SpringMVCApiReader extends ClassReader with ClassReaderUtils {
LOGGER.debug("processing " + param)
val allowableValues = toAllowableValues(param.allowableValues)
Parameter(
param.name,
Option(readString(param.value)),
Option(param.defaultValue).filter(_.trim.nonEmpty),
param.required,
param.allowMultiple,
param.dataType,
allowableValues,
param.paramType,
Option(param.access).filter(_.trim.nonEmpty))
name = param.name,
description = Option(readString(param.value)),
defaultValue = Option(param.defaultValue).filter(_.trim.nonEmpty),
required = param.required,
allowMultiple = param.allowMultiple,
dataType = param.dataType,
allowableValues = allowableValues,
paramType = param.paramType,
paramAccess = Option(param.access).filter(_.trim.nonEmpty))
}).toList
}
case _ => List()
}
}

val (summary, notes, position) = {
if(apiOperation != null) (apiOperation.value, apiOperation.notes, apiOperation.position)
else ("","",0)
}

Operation(
parseHttpMethod(method, apiOperation),
apiOperation.value,
apiOperation.notes,
responseClass,
method.getName,
apiOperation.position,
produces,
consumes,
protocols,
authorizations,
params ++ implicitParams,
apiResponses,
Option(isDeprecated))
method = parseHttpMethod(method, apiOperation),
summary = summary,
notes = notes,
responseClass = responseClass,
nickname = nickname,
position = position,
produces = produces,
consumes = consumes,
protocols = protocols,
authorizations = authorizations,
parameters = params ++ implicitParams,
responseMessages = apiResponses,
`deprecated` = Option(isDeprecated))
}

def readMethod(method: Method, parentParams: List[Parameter], parentMethods: ListBuffer[Method]) = {
def readMethod(method: Method, parentParams: List[Parameter], parentMethods: ListBuffer[Method]): Option[Operation] = {
val apiOperation = method.getAnnotation(classOf[ApiOperation])
val responseAnnotation = method.getAnnotation(classOf[ApiResponses])
val apiResponses = {
Expand All @@ -194,7 +218,12 @@ trait SpringMVCApiReader extends ClassReader with ClassReaderUtils {
}
val isDeprecated = Option(method.getAnnotation(classOf[Deprecated])).map(m => "true").getOrElse(null)

parseOperation(method, apiOperation, apiResponses, isDeprecated, parentParams, parentMethods)
val hidden =if(method.getAnnotation(classOf[ApiExclude]) != null) true
else if(apiOperation != null) apiOperation.hidden
else false

if(!hidden) Some(parseOperation(method, apiOperation, apiResponses, isDeprecated, parentParams, parentMethods))
else None
}

def appendOperation(endpoint: String, path: String, op: Operation, operations: ListBuffer[Tuple3[String, String, ListBuffer[Operation]]]) = {
Expand All @@ -204,53 +233,64 @@ trait SpringMVCApiReader extends ClassReader with ClassReaderUtils {
}
}

// def read(docRoot: String, cls: Class[_], config: SwaggerConfig): Option[ApiListing] = {
// var parentPath = ""
// if(cls.getAnnotation(classOf[RequestMapping]) != null) {
// val paths = cls.getAnnotation(classOf[RequestMapping]).value()
// if(paths.size > 0) {
// parentPath = paths(0)
// }
// }
//
// readRecursive(docRoot, parentPath.replace("//","/"), cls, config, new ListBuffer[Tuple3[String, String, ListBuffer[Operation]]], new ListBuffer[Method])
// }

def read(docRoot: String, cls: Class[_], config: SwaggerConfig): Option[ApiListing] = {
readRecursive(docRoot, "", cls, config, new ListBuffer[Tuple3[String, String, ListBuffer[Operation]]], new ListBuffer[Method])
}

var ignoredRoutes: Set[String] = Set()

def ignoreRoutes = ignoredRoutes

def readRecursive(
docRoot: String,
parentPath: String, cls: Class[_],
config: SwaggerConfig,
operations: ListBuffer[Tuple3[String, String, ListBuffer[Operation]]],
parentMethods: ListBuffer[Method]): Option[ApiListing] = {
val api = cls.getAnnotation(classOf[Api])
if(api == null || cls.getAnnotation(classOf[ApiExclude]) != null) return None

// must have @Api annotation to process!
if(api != null) {
val consumes = Option(api.consumes) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => cls.getAnnotation(classOf[RequestMapping]).consumes() match {
case e: Array[String] => e.toList
case _ => List()
}
}
val produces = Option(api.produces) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => cls.getAnnotation(classOf[RequestMapping]).produces() match {
case e: Array[String] => e.toList
case _ => List()
}
val pathAnnotation = cls.getAnnotation(classOf[RequestMapping])

val r = Option(api) match {
case Some(api) => api.value
case None => Option(pathAnnotation) match {
case Some(p) => p.value()(0)
case None => null
}
val protocols = Option(api.protocols) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => List()
}
if(r != null && !ignoreRoutes.contains(r)) {
// var resourcePath = addLeadingSlash(r)
val position = Option(api) match {
case Some(api) => api.position
case None => 0
}
val description = api.description match {
case e: String if(e != "") => Some(e)
case _ => None
val (consumes, produces, protocols, description) = {
if(api != null){
(Option(api.consumes) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => cls.getAnnotation(classOf[RequestMapping]).consumes() match {
case e: Array[String] => e.toList
case _ => List()
}
},
Option(api.produces) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => cls.getAnnotation(classOf[RequestMapping]).produces() match {
case e: Array[String] => e.toList
case _ => List()
}
},
Option(api.protocols) match {
case Some(e) if(e != "") => e.split(",").map(_.trim).toList
case _ => List()
},
api.description match {
case e: String if(e != "") => Some(e)
case _ => None
}
)}
else ((List(), List(), List(), None))
}
// look for method-level annotated properties
val parentParams: List[Parameter] = (for(field <- getAllFields(cls))
Expand All @@ -272,17 +312,16 @@ trait SpringMVCApiReader extends ClassReader with ClassReaderUtils {
}
).flatten.toList

for(method <- cls.getMethods) {
val returnType = method.getReturnType
method.getAnnotations.size
for(method <- cls.getDeclaredMethods) {
val returnType = findSubresourceType(method)
var path = ""
if(method.getAnnotation(classOf[RequestMapping]) != null) {
val paths = method.getAnnotation(classOf[RequestMapping]).value()
if(paths.size > 0) {
path = paths(0)
}
}
// val endpoint = (parentPath + /*api.value + */ pathFromMethod(method)).replace("//", "/")
// val endpoint = (parentPath + pathFromMethod(method)).replace("//", "/")
val endpoint = parentPath + api.value + pathFromMethod(method)
Option(returnType.getAnnotation(classOf[Api])) match {
case Some(e) => {
Expand All @@ -292,9 +331,9 @@ trait SpringMVCApiReader extends ClassReader with ClassReaderUtils {
parentMethods -= method
}
case _ => {
if(method.getAnnotation(classOf[ApiOperation]) != null) {
val op = readMethod(method, parentParams, parentMethods)
appendOperation(endpoint, path, op, operations)
readMethod(method, parentParams, parentMethods) match {
case Some(op) => appendOperation(endpoint, path, op, operations)
case None => None
}
}
}
Expand Down Expand Up @@ -329,7 +368,7 @@ trait SpringMVCApiReader extends ClassReader with ClassReaderUtils {
produces = produces,
consumes = consumes,
protocols = protocols,
position = api.position)
position = position)
)
}
else None
Expand Down Expand Up @@ -378,10 +417,11 @@ trait SpringMVCApiReader extends ClassReader with ClassReaderUtils {
}

def parseHttpMethod(method: Method, op: ApiOperation): String = {
if (op.httpMethod() != null && op.httpMethod().trim().length() > 0)
if (op != null && op.httpMethod() != null && op.httpMethod().trim().length() > 0)
op.httpMethod().trim
else {
val requestMapping = method.getAnnotation(classOf[RequestMapping]).method()(0)
val requestMappingAnnotation = method.getAnnotation(classOf[RequestMapping])
val requestMapping = if(requestMappingAnnotation != null && !requestMappingAnnotation.method().isEmpty) requestMappingAnnotation.method()(0) else "GET"
if(RequestMethod.GET.equals(requestMapping)) "GET"
else if(RequestMethod.DELETE.equals(requestMapping)) "DELETE"
// else if(method.getAnnotation(classOf[PATCH]) != RequestMethod.) "PATCH"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ public abstract class AbstractTest {

public static final String BASE_CONTROLLER_PACKAGE = "com.knappsack.swagger4springweb.testController";
public static final String EXCLUDE_LABEL = "exclude";
public static final List<String> END_POINT_PATHS = Arrays.asList("/doc/api/v1/partialExclude", "/doc/api/v1/test", "/doc/api/v1/exclude2", "/doc/com.knappsack.swagger4springweb.testController.NoClassLevelMappingController");
public static final List<String> END_POINT_PATHS = Arrays.asList("/doc/api/v1/partialExclude", "/doc/api/v1/test", "/doc/api/v1/exclude2", "/doc/com.knappsack.swagger4springweb.testController.NoClassLevelMappingController", "/doc/api/v1/empty");
public static final ApiInfo API_INFO = new ApiInfo("swagger4spring-web example app", "This is a basic web app for demonstrating swagger4spring-web", "http://localhost:8080/terms", "http://localhost:8080/contact", "MIT", "http://opensource.org/licenses/MIT");
}
Loading

0 comments on commit ead17dc

Please sign in to comment.