com.github.kongchen.swagger.docgen.mavenplugin.SpringMavenDocumentSource.java Source code

Java tutorial

Introduction

Here is the source code for com.github.kongchen.swagger.docgen.mavenplugin.SpringMavenDocumentSource.java

Source

package com.github.kongchen.swagger.docgen.mavenplugin;

import com.github.kongchen.swagger.docgen.AbstractDocumentSource;
import com.github.kongchen.swagger.docgen.GenerateException;
import com.github.kongchen.swagger.docgen.LogAdapter;
import com.github.kongchen.swagger.docgen.spring.*;
import com.github.kongchen.swagger.docgen.util.Utils;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.config.FilterFactory;
import com.wordnik.swagger.config.FilterFactory$;
import com.wordnik.swagger.config.SwaggerConfig;
import com.wordnik.swagger.core.SwaggerSpec;
import com.wordnik.swagger.core.filter.SpecFilter;
import com.wordnik.swagger.core.filter.SwaggerSpecFilter;
import com.wordnik.swagger.jaxrs.reader.DefaultJaxrsApiReader;
import com.wordnik.swagger.model.*;
import com.wordnik.swagger.reader.ClassReader;

import org.apache.maven.plugin.logging.Log;
import org.springframework.web.bind.annotation.RequestMapping;

import scala.None;
import scala.Option;
import scala.collection.JavaConversions;
import scala.collection.immutable.Map$;
import scala.collection.mutable.Buffer;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * @author: chekong
 * 05/13/2013
 * 
 * @author tedleman
 * 01/21/15
 */
public class SpringMavenDocumentSource extends AbstractDocumentSource {
    private final ApiSource apiSource;

    private final SpecFilter specFilter = new SpecFilter();

    public SpringMavenDocumentSource(ApiSource apiSource, Log log) {
        super(new LogAdapter(log), apiSource.getOutputPath(), apiSource.getOutputTemplate(),
                apiSource.getSwaggerDirectory(), apiSource.mustacheFileRoot, apiSource.isUseOutputFlatStructure(),
                apiSource.getOverridingModels(), apiSource.getApiSortComparator());

        setApiVersion(apiSource.getApiVersion());
        setBasePath(apiSource.getBasePath());
        setApiInfo(apiSource.getApiInfo());
        this.apiSource = apiSource;
    }

    @Override
    public void loadDocuments() throws GenerateException {
        Map<String, SpringResource> resourceMap = new HashMap<String, SpringResource>();
        SwaggerConfig swaggerConfig = new SwaggerConfig();
        swaggerConfig.setApiVersion(apiSource.getApiVersion());
        swaggerConfig.setSwaggerVersion(SwaggerSpec.version());
        List<ApiListingReference> apiListingReferences = new ArrayList<ApiListingReference>();
        List<AuthorizationType> authorizationTypes = new ArrayList<AuthorizationType>();

        //relate all methods to one base request mapping if multiple controllers exist for that mapping
        //get all methods from each controller & find their request mapping
        //create map - resource string (after first slash) as key, new SpringResource as value
        for (Class<?> c : apiSource.getValidClasses()) {
            RequestMapping requestMapping = (RequestMapping) c.getAnnotation(RequestMapping.class);
            String description = "";
            if (c.isAnnotationPresent(Api.class)) {
                description = ((Api) c.getAnnotation(Api.class)).value();
            }
            if (requestMapping != null && requestMapping.value().length != 0) {
                //This try/catch block is to stop a bamboo build from failing due to NoClassDefFoundError
                //This occurs when a class or method loaded by reflections contains a type that has no dependency
                try {
                    resourceMap = analyzeController(c, resourceMap, description);
                    List<Method> mList = new ArrayList<Method>(Arrays.asList(c.getMethods()));
                    if (c.getSuperclass() != null) {
                        mList.addAll(Arrays.asList(c.getSuperclass().getMethods()));
                    }
                    for (Method m : mList) {
                        if (m.isAnnotationPresent(RequestMapping.class)) {
                            RequestMapping methodReq = m.getAnnotation(RequestMapping.class);
                            //isolate resource name - attempt first by the first part of the mapping
                            if (methodReq != null && methodReq.value().length != 0) {
                                for (int i = 0; i < methodReq.value().length; i++) {
                                    String resourceKey = "";
                                    String resourceName = Utils.parseResourceName(methodReq.value()[i]);
                                    if (!(resourceName.equals(""))) {
                                        String version = Utils.parseVersion(requestMapping.value()[0]);
                                        //get version - first try by class mapping, then method
                                        if (version.equals("")) {
                                            //class mapping failed - use method
                                            version = Utils.parseVersion(methodReq.value()[i]);
                                        }
                                        resourceKey = Utils.createResourceKey(resourceName, version);
                                        if ((!(resourceMap.containsKey(resourceKey)))) {
                                            resourceMap.put(resourceKey,
                                                    new SpringResource(c, resourceName, resourceKey, description));
                                        }
                                        resourceMap.get(resourceKey).addMethod(m);
                                    }
                                }
                            }
                        }
                    }
                } catch (NoClassDefFoundError e) {
                    LOG.error(e.getMessage());
                    LOG.info(c.getName());
                    //exception occurs when a method type or annotation is not recognized by the plugin
                } catch (ClassNotFoundException e) {
                    LOG.error(e.getMessage());
                    LOG.info(c.getName());
                }

            }
        }
        for (String str : resourceMap.keySet()) {
            ApiListing doc = null;
            SpringResource resource = resourceMap.get(str);

            try {
                doc = getDocFromSpringResource(resource, swaggerConfig);
                setBasePath(doc.basePath());
            } catch (Exception e) {
                LOG.error("DOC NOT GENERATED FOR: " + resource.getResourceName());
                e.printStackTrace();
            }
            if (doc == null)
                continue;
            ApiListingReference apiListingReference = new ApiListingReference(doc.resourcePath(), doc.description(),
                    doc.position());
            apiListingReferences.add(apiListingReference);
            acceptDocument(doc);

        }
        // sort apiListingRefernce by position
        Collections.sort(apiListingReferences, new Comparator<ApiListingReference>() {
            @Override
            public int compare(ApiListingReference o1, ApiListingReference o2) {
                if (o1 == null && o2 == null)
                    return 0;
                if (o1 == null && o2 != null)
                    return -1;
                if (o1 != null && o2 == null)
                    return 1;
                return o1.position() - o2.position();
            }
        });
        serviceDocument = new ResourceListing(swaggerConfig.apiVersion(), swaggerConfig.swaggerVersion(),
                scala.collection.immutable.List
                        .fromIterator(JavaConversions.asScalaIterator(apiListingReferences.iterator())),
                scala.collection.immutable.List.fromIterator(
                        JavaConversions.asScalaIterator(authorizationTypes.iterator())),
                swaggerConfig.info());
    }

    private Option<ApiInfo> toSwaggerApiInfo(ApiSourceInfo info) {
        if (info == null)
            return Option.empty();
        return Option.apply(new ApiInfo(info.getTitle(), info.getDescription(), info.getTermsOfServiceUrl(),
                info.getContact(), info.getLicense(), info.getLicenseUrl()));
    }

    private ApiListing getDocFromSpringResource(SpringResource res, SwaggerConfig swaggerConfig) throws Exception {
        SpringMvcApiReader reader = new SpringMvcApiReader(apiSource);
        ApiListing apiListing = reader.read(res, swaggerConfig);
        if (None.canEqual(apiListing))
            return null;
        return apiListing;
    }

    //Helper method for loadDocuments()
    private Map<String, SpringResource> analyzeController(Class<?> clazz, Map<String, SpringResource> resourceMap,
            String description) throws ClassNotFoundException {

        for (int i = 0; i < clazz.getAnnotation(RequestMapping.class).value().length; i++) {
            String controllerMapping = clazz.getAnnotation(RequestMapping.class).value()[i];
            String resourceName = Utils.parseResourceName(clazz);
            for (Method m : clazz.getMethods()) {
                if (m.isAnnotationPresent(RequestMapping.class)) {
                    RequestMapping methodReq = m.getAnnotation(RequestMapping.class);
                    if (methodReq.value() == null || methodReq.value().length == 0
                            || Utils.parseResourceName(methodReq.value()[0]).equals("")) {
                        if (resourceName.length() != 0) {
                            String resourceKey = Utils.createResourceKey(resourceName,
                                    Utils.parseVersion(controllerMapping));
                            if ((!(resourceMap.containsKey(resourceKey)))) {
                                resourceMap.put(resourceKey,
                                        new SpringResource(clazz, resourceName, resourceKey, description));
                            }
                            resourceMap.get(resourceKey).addMethod(m);
                        }
                    }
                }
            }
        }
        clazz.getFields();
        clazz.getDeclaredFields(); //<--In case developer declares a field without an associated getter/setter.
        //this will allow NoClassDefFoundError to be caught before it triggers bamboo failure.

        return resourceMap;
    }

    private ClassReader getApiReader() throws Exception {
        if (apiSource.getSwaggerApiReader() == null)
            return new DefaultJaxrsApiReader();
        try {
            LOG.info("Reading api reader configuration: " + apiSource.getSwaggerApiReader());
            return (ClassReader) Class.forName(apiSource.getSwaggerApiReader()).newInstance();
        } catch (Exception e) {
            throw new GenerateException("Cannot load swagger api reader: " + apiSource.getSwaggerApiReader(), e);
        }
    }
}