wkennedy / swagger4spring-web

Swagger support for Spring MVC
89 stars 46 forks source link

Multiple controllers sharing the same request mapping path mutually exclude each other from showing up in the documentation #61

Open MartinAhrer opened 10 years ago

MartinAhrer commented 10 years ago

Two controllers mapping to the same base URL are not recognized by swagger4spring (0.3.3). Controller 1: /dictionaries/userAccount

@RestController
@RequestMapping(value = "/dictionaries", produces = {"application/json"})
public class UserAccountDictionaryController {
    @RequestMapping(value = "/userAccount", method = RequestMethod.GET)
    public ResponseEntity<ResourceMetadata> resourceMetadata()

Controller 2: /dictionaries/userGroup

@RestController
@RequestMapping(value = "/dictionaries", produces = {"application/json"})
public class UserGroupDictionaryController {
    @RequestMapping(value = "/userGroup", method = RequestMethod.GET)
    public ResponseEntity<ResourceMetadata> resourceMetadata()

This will result in just one controller to be included. I guess from the internal implementation, one map entry replaces the other and so forth. They probably need to be merged together.

MartinAhrer commented 10 years ago

Anything going on here? I have tried to look at the responsible code:

    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();
        }

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

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

        return new ApiListing(apiVersion, swaggerVersion, basePath, resourcePath, null, null, null, null, null, null,
                null, 0);
    }

There is a sequence which I suspect is attempting to detected if there is already a matching request path but it only returns the existing one rather than joining the API's of the existing and the currently processed controller.

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

Is it related to issue #53 ?