org.jm.swagger.SpringMVCAPIReader.java Source code

Java tutorial

Introduction

Here is the source code for org.jm.swagger.SpringMVCAPIReader.java

Source

/*
 * Copyright 2002-2011 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jm.swagger;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.jm.spring.controller.EndpointDocumentationController;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.wordnik.swagger.core.ApiParam;
import com.wordnik.swagger.core.Documentation;
import com.wordnik.swagger.core.DocumentationEndPoint;
import com.wordnik.swagger.core.DocumentationOperation;
import com.wordnik.swagger.core.DocumentationParameter;

/**
 * 
 * @author Justin Musgrove
 *
 */
public class SpringMVCAPIReader {

    private String apiVersion;
    private String swaggerVersion;
    private String basePath;
    private String resourcePath;

    @SuppressWarnings({ "rawtypes", "serial" })
    private Set<Class> excludeControllers = new HashSet<Class>() {
        {
            add(EndpointDocumentationController.class);
        }
    };

    /**
     * @param apiVersion
     * @param swaggerVersion
     * @param basePath
     * @param resourcePath
     * @param mapping
     */
    public SpringMVCAPIReader(String apiVersion, String swaggerVersion, String basePath, String resourcePath) {
        this.apiVersion = apiVersion;
        this.swaggerVersion = swaggerVersion;
        this.basePath = basePath;
        this.resourcePath = resourcePath;
    }

    /**
     * This method will create the resources from controllers that have
     * request mappings and pull the base path for {@link DocumentationEndPoint}   
     * from the classess {@link RequestMapping} if it is not contained in the excludeControllers
     * list.
     * 
     * @param mapping
     * @return 
     */
    public Documentation createResources(RequestMappingHandlerMapping mapping) {

        Documentation documentation = new Documentation(this.apiVersion, this.swaggerVersion, this.basePath,
                this.resourcePath);

        Map<String, Object> beansWithAnnotation = mapping.getApplicationContext()
                .getBeansWithAnnotation(Controller.class);
        for (Entry<String, Object> entry : beansWithAnnotation.entrySet()) {

            if (!excludeControllers.contains(entry.getValue().getClass())) {
                RequestMapping classRequestMapping = AnnotationUtils.findAnnotation(entry.getValue().getClass(),
                        RequestMapping.class);
                if (classRequestMapping != null && classRequestMapping.value().length > 0) {
                    String path = classRequestMapping.value()[0];
                    DocumentationEndPoint documentationEndPoint = new DocumentationEndPoint(path,
                            entry.getValue().getClass().getSimpleName());

                    documentation.addApi(documentationEndPoint);
                }
            }
        }
        return documentation;
    }

    /**
     * This method should create a {@link Documentation} object that should represent a similiar object to 
     * http://petstore.swagger.wordnik.com/api/pet.json
     * 
     * 
     * @param mapping
     * @param classRequestMapping
     * @return
     */
    public Documentation processMethods(RequestMappingHandlerMapping mapping, String classRequestMapping) {

        Documentation documentation = new Documentation(this.apiVersion, this.swaggerVersion, this.basePath,
                this.resourcePath);

        for (Entry<RequestMappingInfo, HandlerMethod> entry : mapping.getHandlerMethods().entrySet()) {

            RequestMappingInfo requestMappingInfo = entry.getKey();
            HandlerMethod handlerMethod = entry.getValue();

            // find bean that has a matching classRequestMapping value
            RequestMapping requestMapping = handlerMethod.getBeanType().getAnnotation(RequestMapping.class);
            if (requestMapping.value()[0].contains(classRequestMapping)) {

                String path = null;
                for (String pt : requestMappingInfo.getPatternsCondition().getPatterns()) {
                    path = pt;
                }

                //TODO - how to get description for the method
                DocumentationEndPoint documentationEndPoint = new DocumentationEndPoint(path + "{format}",
                        "description");

                DocumentationOperation documentationOperation = processRequestMapping(requestMappingInfo,
                        handlerMethod.getMethod().getName());
                List<DocumentationParameter> documentationParamaters = convertHandlerMethod(handlerMethod);
                documentationOperation.setParameters(documentationParamaters);

                documentationEndPoint.addOperation(documentationOperation);
                documentation.addApi(documentationEndPoint);
            }
        }

        return documentation;
    }

    /**
     * NickName right now defaults to the method name
     * 
     * @param requestMappingInfo
     * @return
     */
    private DocumentationOperation processRequestMapping(RequestMappingInfo requestMappingInfo, String nickName) {
        DocumentationOperation documentationOperation = new DocumentationOperation();

        //GET/POST
        Set<RequestMethod> requestMethods = requestMappingInfo.getMethodsCondition().getMethods();
        String value = Joiner.on(",").join(requestMethods);
        documentationOperation.setHttpMethod(value);

        documentationOperation.setNickname(nickName);
        documentationOperation.setSummary("summary");

        return documentationOperation;
    }

    /**
     * Loop through each method parameter and convert to DocumentationParameter
     * 
     * @param handlerMethod
     * @return
     */
    private List<DocumentationParameter> convertHandlerMethod(HandlerMethod handlerMethod) {
        List<DocumentationParameter> documentationParameters = Lists.newArrayList();
        MethodParameter[] methParameters = handlerMethod.getMethodParameters();
        for (MethodParameter methodParamater : methParameters) {
            if (methodParamater.hasParameterAnnotations()) {
                documentationParameters.add(convertMethodParameter(methodParamater));
            }
        }
        return documentationParameters;
    }

    /**
     * Create {@link DocumentationParameter} from {@link MethodParameter}
     * 
     * @param methodParamater
     * @return
     */
    private DocumentationParameter convertMethodParameter(MethodParameter methodParamater) {

        DocumentationParameter documentationParameter = new DocumentationParameter();
        documentationParameter.setDataType(methodParamater.getParameterType().getSimpleName());

        methodParamater.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
        documentationParameter.setName(methodParamater.getParameterName());

        documentationParameter.setDescription("description");
        documentationParameter.setNotes("notes");
        documentationParameter.setParamType("path");
        documentationParameter.setDefaultValue("default value");
        documentationParameter.setAllowMultiple(false);

        PathVariable pathVariable = methodParamater.getParameterAnnotation(PathVariable.class);

        if (pathVariable != null) {
            documentationParameter.setRequired(true);
        }

        RequestParam requestParam = methodParamater.getParameterAnnotation(RequestParam.class);
        if (requestParam != null) {
            documentationParameter.setRequired(requestParam.required());
            documentationParameter.setDefaultValue(requestParam.defaultValue());
        }

        ApiParam apiParam = methodParamater.getParameterAnnotation(ApiParam.class);
        if (apiParam != null) {
            documentationParameter.setName(apiParam.name());
            documentationParameter.setDescription(apiParam.value());
            //          documentationParameter.setAllowableValues(apiParam.allowableValues());
        }

        return documentationParameter;
    }

    /**
     * @param excludeControllers the excludeControllers to set
     */
    @SuppressWarnings("rawtypes")
    public void setExcludeControllers(Set<Class> excludeControllers) {
        if (this.excludeControllers != null) {
            this.excludeControllers.addAll(excludeControllers);
        }
    }
}