com.github.kongchen.swagger.docgen.reader.JaxrsReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swagger-maven-plugin
Show all versions of swagger-maven-plugin
A maven build plugin which helps you generate API document during build phase
package com.github.kongchen.swagger.docgen.reader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.apache.maven.plugin.logging.Log;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import com.github.kongchen.swagger.docgen.jaxrs.BeanParamInjectParamExtention;
import com.github.kongchen.swagger.docgen.jaxrs.JaxrsParameterExtension;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.Authorization;
import io.swagger.annotations.AuthorizationScope;
import io.swagger.annotations.SwaggerDefinition;
import io.swagger.converter.ModelConverters;
import io.swagger.jaxrs.ext.SwaggerExtension;
import io.swagger.jaxrs.ext.SwaggerExtensions;
import io.swagger.jersey.SwaggerJerseyJaxrs;
import io.swagger.models.Model;
import io.swagger.models.Operation;
import io.swagger.models.Response;
import io.swagger.models.SecurityRequirement;
import io.swagger.models.Swagger;
import io.swagger.models.Tag;
import io.swagger.models.parameters.Parameter;
import io.swagger.models.properties.Property;
import io.swagger.models.properties.RefProperty;
import io.swagger.util.ReflectionUtils;
public class JaxrsReader extends AbstractReader implements ClassSwaggerReader {
private static final Logger LOGGER = LoggerFactory.getLogger(JaxrsReader.class);
private static final ResponseContainerConverter RESPONSE_CONTAINER_CONVERTER = new ResponseContainerConverter();
public JaxrsReader(Swagger swagger, Log LOG) {
super(swagger, LOG);
}
@Override
protected void updateExtensionChain() {
List extensions = new ArrayList();
extensions.add(new BeanParamInjectParamExtention());
extensions.add(new SwaggerJerseyJaxrs());
extensions.add(new JaxrsParameterExtension());
SwaggerExtensions.setExtensions(extensions);
}
@Override
public Swagger read(Set> classes) {
for (Class> cls : classes) {
read(cls);
}
return swagger;
}
public Swagger getSwagger() {
return swagger;
}
public Swagger read(Class> cls) {
return read(cls, "", null, false, new String[0], new String[0], new HashMap(), new ArrayList());
}
protected Swagger read(Class> cls, String parentPath, String parentMethod, boolean readHidden, String[] parentConsumes, String[] parentProduces, Map parentTags, List parentParameters) {
if (swagger == null) {
swagger = new Swagger();
}
Api api = AnnotationUtils.findAnnotation(cls, Api.class);
Path apiPath = AnnotationUtils.findAnnotation(cls, Path.class);
// only read if allowing hidden apis OR api is not marked as hidden
if (!canReadApi(readHidden, api)) {
return swagger;
}
Map tags = updateTagsForApi(parentTags, api);
List securities = getSecurityRequirements(api);
Map discoveredTags = scanClasspathForTags();
// merge consumes, pro duces
// look for method-level annotated properties
// handle subresources by looking at return type
// parse the method
List filteredMethods = getFilteredMethods(cls);
for (Method method : filteredMethods) {
ApiOperation apiOperation = AnnotationUtils.findAnnotation(method, ApiOperation.class);
if (apiOperation != null && apiOperation.hidden()) {
continue;
}
Path methodPath = AnnotationUtils.findAnnotation(method, Path.class);
String parentPathValue = String.valueOf(parentPath);
//is method default handler within a subresource
if(apiPath == null && methodPath == null && parentPath != null && readHidden){
final String updatedMethodPath = String.valueOf(parentPath);
Path path = new Path(){
@Override
public String value(){
return updatedMethodPath;
}
@Override
public Class extends Annotation> annotationType() {
return Path.class;
}
};
methodPath = path;
parentPathValue = null;
}
String operationPath = getPath(apiPath, methodPath, parentPathValue);
if (operationPath != null) {
Map regexMap = new HashMap();
operationPath = parseOperationPath(operationPath, regexMap);
String httpMethod = extractOperationMethod(apiOperation, method, SwaggerExtensions.chain());
Operation operation = parseMethod(httpMethod, method);
updateOperationParameters(parentParameters, regexMap, operation);
updateOperationProtocols(apiOperation, operation);
String[] apiConsumes = new String[0];
String[] apiProduces = new String[0];
Consumes consumes = AnnotationUtils.findAnnotation(cls, Consumes.class);
if (consumes != null) {
apiConsumes = consumes.value();
}
Produces produces = AnnotationUtils.findAnnotation(cls, Produces.class);
if (produces != null) {
apiProduces = produces.value();
}
apiConsumes = updateOperationConsumes(parentConsumes, apiConsumes, operation);
apiProduces = updateOperationProduces(parentProduces, apiProduces, operation);
handleSubResource(apiConsumes, httpMethod, apiProduces, tags, method, operationPath, operation);
// can't continue without a valid http method
httpMethod = (httpMethod == null) ? parentMethod : httpMethod;
updateTagsForOperation(operation, apiOperation);
updateOperation(apiConsumes, apiProduces, tags, securities, operation);
updatePath(operationPath, httpMethod, operation);
}
updateTagDescriptions(discoveredTags);
}
return swagger;
}
private List getFilteredMethods(Class> cls) {
Method[] methods = cls.getMethods();
List filteredMethods = new ArrayList();
for (Method method : methods) {
if (!method.isBridge()) {
filteredMethods.add(method);
}
}
return filteredMethods;
}
private void updateTagDescriptions(Map discoveredTags) {
if (swagger.getTags() != null) {
for (Tag tag : swagger.getTags()) {
Tag rightTag = discoveredTags.get(tag.getName());
if (rightTag != null && rightTag.getDescription() != null) {
tag.setDescription(rightTag.getDescription());
}
}
}
}
private Map scanClasspathForTags() {
Map tags = new HashMap();
for (Class> aClass: new Reflections("").getTypesAnnotatedWith(SwaggerDefinition.class)) {
SwaggerDefinition swaggerDefinition = AnnotationUtils.findAnnotation(aClass, SwaggerDefinition.class);
for (io.swagger.annotations.Tag tag : swaggerDefinition.tags()) {
String tagName = tag.name();
if (!tagName.isEmpty()) {
tags.put(tag.name(), new Tag().name(tag.name()).description(tag.description()));
}
}
}
return tags;
}
private void handleSubResource(String[] apiConsumes, String httpMethod, String[] apiProduces, Map tags, Method method, String operationPath, Operation operation) {
if (isSubResource(httpMethod, method)) {
Class> responseClass = method.getReturnType();
read(responseClass, operationPath, httpMethod, true, apiConsumes, apiProduces, tags, operation.getParameters());
}
}
protected boolean isSubResource(String httpMethod, Method method) {
Class> responseClass = method.getReturnType();
return (responseClass != null) && (httpMethod == null) && (AnnotationUtils.findAnnotation(method, Path.class) != null);
}
private String getPath(Path classLevelPath, Path methodLevelPath, String parentPath) {
if (classLevelPath == null && methodLevelPath == null) {
return null;
}
StringBuilder stringBuilder = new StringBuilder();
if (parentPath != null && !parentPath.isEmpty() && !parentPath.equals("/")) {
if (!parentPath.startsWith("/")) {
parentPath = "/" + parentPath;
}
if (parentPath.endsWith("/")) {
parentPath = parentPath.substring(0, parentPath.length() - 1);
}
stringBuilder.append(parentPath);
}
if (classLevelPath != null) {
stringBuilder.append(classLevelPath.value());
}
if (methodLevelPath != null && !methodLevelPath.value().equals("/")) {
String methodPath = methodLevelPath.value();
if (!methodPath.startsWith("/") && !stringBuilder.toString().endsWith("/")) {
stringBuilder.append("/");
}
if (methodPath.endsWith("/")) {
methodPath = methodPath.substring(0, methodPath.length() - 1);
}
stringBuilder.append(methodPath);
}
String output = stringBuilder.toString();
if (!output.startsWith("/")) {
output = "/" + output;
}
if (output.endsWith("/") && output.length() > 1) {
return output.substring(0, output.length() - 1);
} else {
return output;
}
}
public Operation parseMethod(String httpMethod, Method method) {
int responseCode = 200;
Operation operation = new Operation();
ApiOperation apiOperation = AnnotationUtils.findAnnotation(method, ApiOperation.class);
String operationId = method.getName();
String responseContainer = null;
Type responseClassType = null;
Map defaultResponseHeaders = null;
if (apiOperation != null) {
if (apiOperation.hidden()) {
return null;
}
if (!apiOperation.nickname().isEmpty()) {
operationId = apiOperation.nickname();
}
defaultResponseHeaders = parseResponseHeaders(apiOperation.responseHeaders());
operation.summary(apiOperation.value()).description(apiOperation.notes());
Set