Package com.knappsack.swagger4springweb.parser

Source Code of com.knappsack.swagger4springweb.parser.ApiParserImpl

package com.knappsack.swagger4springweb.parser;

import com.knappsack.swagger4springweb.controller.ApiDocumentationController;
import com.knappsack.swagger4springweb.filter.ApiExcludeFilter;
import com.knappsack.swagger4springweb.filter.Filter;
import com.knappsack.swagger4springweb.util.AnnotationUtils;
import com.knappsack.swagger4springweb.util.ApiListingUtil;
import com.knappsack.swagger4springweb.util.JavaToScalaUtil;
import com.knappsack.swagger4springweb.util.ScalaToJavaUtil;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.config.SwaggerConfig;
import com.wordnik.swagger.model.*;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import scala.Option;

import java.lang.reflect.Method;
import java.util.*;

public class ApiParserImpl implements ApiParser {

    private static final Logger LOGGER = LoggerFactory.getLogger(ApiParserImpl.class);

    private static final String swaggerVersion = com.wordnik.swagger.core.SwaggerSpec.version();

    private final Map<String, ApiListing> apiListingMap = new HashMap<String, ApiListing>();

    private final List<String> controllerPackages;
    private final List<String> ignorableAnnotations;
    private final List<Filter> filters;

    private String basePath = "";
    private String apiVersion = "v1";
    private boolean ignoreUnusedPathVariables;
    private SwaggerConfig swaggerConfig;

    public ApiParserImpl(ApiInfo apiInfo, List<AuthorizationType> authorizationTypes, List<String> baseControllerPackage, String basePath, String servletPath,
            String apiVersion, List<String> ignorableAnnotations, boolean ignoreUnusedPathVariables,
            List<Filter> filters) {

        this.controllerPackages = baseControllerPackage;
        this.ignorableAnnotations = ignorableAnnotations;
        this.ignoreUnusedPathVariables = ignoreUnusedPathVariables;
        this.basePath = basePath;
        this.apiVersion = apiVersion;

        swaggerConfig = new SwaggerConfig();
        if (apiInfo != null) {
            swaggerConfig.setApiInfo(apiInfo);
        }
        swaggerConfig.setApiPath(servletPath);
        swaggerConfig.setApiVersion(apiVersion);
        swaggerConfig.setBasePath(basePath);
        swaggerConfig.setSwaggerVersion(swaggerVersion);
        swaggerConfig.setAuthorizations(JavaToScalaUtil.toScalaList(authorizationTypes));

        this.filters = new ArrayList<Filter>();
        this.filters.add(new ApiExcludeFilter()); // @ApiExclude filter
        if (filters != null) {
            this.filters.addAll(filters);
        }
    }

    public ResourceListing getResourceListing(Map<String, ApiListing> apiListingMap) {
        List<ApiListingReference> apiListingReferences = new ArrayList<ApiListingReference>();
        for (String key : apiListingMap.keySet()) {
            ApiListing apiListing = apiListingMap.get(key);
            String docPath = "/doc"; //servletPath + "/doc"; //"/api/doc";
            ApiListingReference apiListingReference = new ApiListingReference(docPath + key, apiListing.description(),
                    apiListing.position());

            apiListingReferences.add(apiListingReference);
        }

        Collections.sort(apiListingReferences, new Comparator<ApiListingReference>() {
            @Override
            public int compare(ApiListingReference o1, ApiListingReference o2) {
                if (o1.position() == o2.position())
                    return 0;
                else if(o1.position() == 0)
                    return 1;
                else if(o2.position() == 0)
                    return -1;
                else if (o1.position() < o2.position())
                    return -1;
                else if (o1.position() > o2.position())
                    return 1;
                return 0;
            }
        });

        return new ResourceListing(apiVersion, swaggerVersion, JavaToScalaUtil.toScalaList(apiListingReferences), null,
                swaggerConfig.info());
    }

    public Map<String, ApiListing> createApiListings() {
        Set<Class<?>> controllerClasses = new HashSet<Class<?>>();
        for (String controllerPackage : controllerPackages) {
            Reflections reflections = new Reflections(controllerPackage);
            controllerClasses.addAll(reflections.getTypesAnnotatedWith(Controller.class));
            try {
                controllerClasses.addAll(reflections.getTypesAnnotatedWith(RestController.class));
            } catch (NoClassDefFoundError  e) {
                //Check for NoClassDefFoundError in the case that this is being used in a Spring 3 project where the RestController does not exist.
                LOGGER.debug("No RestController found.  RestController is found in Spring 4.  This is potentially an earlier version of Spring", e);
            }
        }

        return processControllers(controllerClasses);
    }

    private Map<String, ApiListing> processControllers(Set<Class<?>> controllerClasses) {
        //Loop over end points (controllers)
        for (Class<?> controllerClass : controllerClasses) {
            if (ApiDocumentationController.class.isAssignableFrom(controllerClass)) {
                continue;
            }

            Set<Method> requestMappingMethods = AnnotationUtils.getAnnotatedMethods(controllerClass, RequestMapping.class);
            ApiListing apiListing = processControllerApi(controllerClass);
            String description = "";
            Api controllerApi = controllerClass.getAnnotation(Api.class);
            if (controllerApi != null) {
                description = controllerApi.description();
            }

            if (apiListing.apis().size() == 0) {
                apiListing = processMethods(requestMappingMethods, controllerClass, apiListing, description);
            }

            //Allow for multiple controllers having the same resource path.
            ApiListing existingApiListing = apiListingMap.get(apiListing.resourcePath());
            if (existingApiListing != null) {
                apiListing = ApiListingUtil.mergeApiListing(existingApiListing, apiListing);
            }

            // controllers without any operations are excluded from the apiListingMap list
            if (apiListing.apis() != null && !apiListing.apis().isEmpty()) {
                apiListingMap.put(apiListing.resourcePath(), apiListing);
            }
        }

        return apiListingMap;
    }

    private ApiListing processControllerApi(Class<?> controllerClass) {
        String resourcePath = "";
        Api controllerApi = controllerClass.getAnnotation(Api.class);
        if (controllerApi != null) {
            resourcePath = controllerApi.basePath();
        }

        if (controllerApi == null || resourcePath.isEmpty()) {
            RequestMapping controllerRequestMapping = controllerClass.getAnnotation(RequestMapping.class);
            if (controllerRequestMapping != null && controllerRequestMapping.value() != null &&
                    controllerRequestMapping.value().length > 0) {
                resourcePath = controllerRequestMapping.value()[0];
            } else {
                resourcePath = controllerClass.getName();
            }
        }
        if (!resourcePath.startsWith("/")) {
            resourcePath = "/" + resourcePath;
        }

        String docRoot = resourcePath;
        if(docRoot.contains(controllerClass.getName())) {
            docRoot = docRoot.replace(controllerClass.getName(), "");
        }
        SpringApiReader reader = new SpringApiReader();
        Option<ApiListing> apiListingOption = reader.read(docRoot, controllerClass, swaggerConfig);
        ApiListing apiListing = null;
        if (apiListingOption.nonEmpty()) {
            apiListing = apiListingOption.get();
        }

        if (apiListing != null) {
            return apiListing;
        }

        return ApiListingUtil.baseApiListing(apiVersion, swaggerVersion, basePath, resourcePath);
    }

    private ApiListing processMethods(Collection<Method> methods, Class<?> controllerClass, ApiListing apiListing, String description) {

        Map<String, ApiDescription> endpoints = new HashMap<String, ApiDescription>();
        Map<String, Model> models = new HashMap<String, Model>();
        Map<String, List<Operation>> operations = new HashMap<String, List<Operation>>();
        List<ApiDescription> descriptions = new ArrayList<ApiDescription>();

        populateApiDescriptionMapForApiListing(apiListing, endpoints);

        ApiModelParser apiModelParser = new ApiModelParser(models);

        //This is for the case where there is no request mapping at the class level. When this occurs, the resourcePath
        //is the class name, which we don't want to be appended to the path of the operation.  Therefore, we replace
        //the class name.
        String resourcePath = apiListing.resourcePath();
        if(resourcePath.contains(controllerClass.getName())) {
            resourcePath = resourcePath.replace("/" + controllerClass.getName(), "");
        }
        for (Method method : methods) {
            if (ignore(method)) {
                continue;
            }

            String value = AnnotationUtils.getMethodRequestMappingValue(method);
            ApiDescriptionParser documentationEndPointParser = new ApiDescriptionParser();
            ApiDescription apiDescription = documentationEndPointParser
                    .parseApiDescription(method, description, resourcePath);
            if (!endpoints.containsKey(value)) {
                endpoints.put(value, apiDescription);
            }

            List<Operation> ops = operations.get(value);
            if (ops == null) {
                ops = new ArrayList<Operation>();
                operations.put(value, ops);
            }

            ApiOperationParser apiOperationParser = new ApiOperationParser(resourcePath,
                    ignorableAnnotations, ignoreUnusedPathVariables, models);
            Operation operation = apiOperationParser.parseDocumentationOperation(method);
            ops.add(operation);

            apiModelParser.parseResponseBodyModels(method);
        }

        for (String key : endpoints.keySet()) {
            ApiDescription apiDescription = endpoints.get(key);
            ApiDescription newApiDescription = new ApiDescription(apiDescription.path(), apiDescription.description(),
                    JavaToScalaUtil.toScalaList(operations.get(key)));
            descriptions.add(newApiDescription);
        }

        Option<scala.collection.immutable.Map<String, Model>> modelOptions = Option
                .apply(JavaToScalaUtil.toScalaImmutableMap(models));

        return new ApiListing(apiListing.apiVersion(), apiListing.swaggerVersion(), apiListing.basePath(),
                apiListing.resourcePath(), apiListing.produces(), apiListing.consumes(), apiListing.protocols(),
                apiListing.authorizations(), JavaToScalaUtil.toScalaList(descriptions), modelOptions,
                apiListing.description(), apiListing.position());
    }

    private void populateApiDescriptionMapForApiListing(ApiListing apiListing,
            Map<String, ApiDescription> apiDescriptionMap) {
        if (apiListing.apis() != null) {

            List<ApiDescription> apiDescriptions = ScalaToJavaUtil.toJavaList(apiListing.apis());
            for (ApiDescription apiDescription : apiDescriptions) {
                apiDescriptionMap.put(apiDescription.path(), apiDescription);
            }
        }
    }

    private boolean ignore(Method method) {
        for (Filter filter : filters) {
            if (filter.isApplicable(method) && filter.ignore(method)) {
                return true;
            }
        }
        return false;
    }
}
TOP

Related Classes of com.knappsack.swagger4springweb.parser.ApiParserImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.