Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overhaul the mappings endpoint #9979

Closed
wilkinsona opened this issue Aug 8, 2017 · 10 comments
Closed

Overhaul the mappings endpoint #9979

wilkinsona opened this issue Aug 8, 2017 · 10 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@wilkinsona
Copy link
Member

wilkinsona commented Aug 8, 2017

The mappings endpoint is currently described as returning "a collated list of all @RequestMapping paths". It actually returns more than that as it introspects any AbstractUrlHandlerMapping and AbstractHandlerMethodMapping instances, not just those that are associated with @RequestMapping. However, there are some mappings that it doesn't currently return such as those configured by Spring Data REST.

Beyond the accuracy of the description, the content of the response is a little haphazard. It currently looks like this:

{
    "/**": {
        "bean": "resourceHandlerMapping"
    },
    "/**/favicon.ico": {
        "bean": "faviconHandlerMapping"
    },
    "/webjars/**": {
        "bean": "resourceHandlerMapping"
    },
    "{[/application/auditevents],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}": {
        "bean": "webEndpointServletHandlerMapping",
        "method": "public java.lang.Object org.springframework.boot.endpoint.web.mvc.WebEndpointServletHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)"
    },
    "{[/application/autoconfig],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}": {
        "bean": "webEndpointServletHandlerMapping",
        "method": "public java.lang.Object org.springframework.boot.endpoint.web.mvc.WebEndpointServletHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)"
    },
    "{[/application/beans],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}": {
        "bean": "webEndpointServletHandlerMapping",
        "method": "public java.lang.Object org.springframework.boot.endpoint.web.mvc.WebEndpointServletHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)"
    }
    // …
}

The keys in the map are just the toString() of the mapping object which can, essentially, be anything. As such, there's no guarantee of the format of the key. There's also, as far as I know, no guarantee that the keys will be unique across everything that's introspected so entries in the map may clash. Lastly, handler mappings are ordered and this ordering is lost by using a map.

We also need to figure out what, if anything, we want to do for WebFlux and Jersey. Perhaps they should be completely separate endpoints? However, if you're using a combination of MVC and Jersey it might be nice to have all mappings available from a single source.

@wilkinsona
Copy link
Member Author

I've opened some Framework issues that all relate to this:

@wilkinsona
Copy link
Member Author

Let's try and also include information about Filters and Servlets too (previously tracked by #2178).

@wilkinsona
Copy link
Member Author

wilkinsona commented Nov 1, 2017

Here's an example of a what the response might look like for an app using Spring MVC and Spring Data REST:

{
    "dispatcherServlets": {
        "dispatcherServlet": [
            {
                "handler": "ResourceHttpRequestHandler [locations=[class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/], class path resource []], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@20de1a03]]",
                "predicate": "/**/favicon.ico"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/auditevents],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/beans],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/autoconfig],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/configprops],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/env/{toMatch}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/env],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/health],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/status],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/info],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/loggers],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/loggers/{name}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/loggers/{name}],methods=[POST],consumes=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/threaddump],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/metrics/{requiredMetricName}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/metrics],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/trace],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/mappings],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/heapdump],methods=[GET],produces=[application/octet-stream]}"
            },
            {
                "handler": "private java.util.Map<java.lang.String, java.util.Map<java.lang.String, org.springframework.boot.actuate.endpoint.web.Link>> org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.links(javax.servlet.http.HttpServletRequest)",
                "predicate": "{[/application],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)",
                "predicate": "{[/error]}"
            },
            {
                "handler": "public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)",
                "predicate": "{[/error],produces=[text/html]}"
            },
            {
                "handler": "org.springframework.http.HttpEntity<?> org.springframework.data.rest.webmvc.alps.AlpsController.alpsOptions()",
                "predicate": "{[/api/profile/{repository}],methods=[OPTIONS],produces=[application/alps+json]}"
            },
            {
                "handler": "org.springframework.http.HttpEntity<org.springframework.data.rest.webmvc.RootResourceInformation> org.springframework.data.rest.webmvc.alps.AlpsController.descriptor(org.springframework.data.rest.webmvc.RootResourceInformation)",
                "predicate": "{[/api/profile/{repository}],methods=[GET],produces=[application/alps+json || */*]}"
            },
            {
                "handler": "public org.springframework.http.HttpEntity<?> org.springframework.data.rest.webmvc.ProfileController.profileOptions()",
                "predicate": "{[/api/profile],methods=[OPTIONS]}"
            },
            {
                "handler": "org.springframework.http.HttpEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.ProfileController.listAllFormsOfMetadata()",
                "predicate": "{[/api/profile],methods=[GET]}"
            },
            {
                "handler": "public org.springframework.http.HttpEntity<org.springframework.data.rest.webmvc.json.JsonSchema> org.springframework.data.rest.webmvc.RepositorySchemaController.schema(org.springframework.data.rest.webmvc.RootResourceInformation)",
                "predicate": "{[/api/profile/{repository}],methods=[GET],produces=[application/schema+json]}"
            },
            {
                "handler": "public org.springframework.http.HttpEntity<?> org.springframework.data.rest.webmvc.RepositoryController.optionsForRepositories()",
                "predicate": "{[/api/ || /api],methods=[OPTIONS],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryController.headForRepositories()",
                "predicate": "{[/api/ || /api],methods=[HEAD],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.HttpEntity<org.springframework.data.rest.webmvc.RepositoryLinksResource> org.springframework.data.rest.webmvc.RepositoryController.listRepositories()",
                "predicate": "{[/api/ || /api],methods=[GET],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryEntityController.optionsForCollectionResource(org.springframework.data.rest.webmvc.RootResourceInformation)",
                "predicate": "{[/api/{repository}],methods=[OPTIONS],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryEntityController.headCollectionResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.support.DefaultedPageable) throws org.springframework.web.HttpRequestMethodNotSupportedException",
                "predicate": "{[/api/{repository}],methods=[HEAD],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.hateoas.Resources<?> org.springframework.data.rest.webmvc.RepositoryEntityController.getCollectionResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.support.DefaultedPageable,org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws org.springframework.data.rest.webmvc.ResourceNotFoundException,org.springframework.web.HttpRequestMethodNotSupportedException",
                "predicate": "{[/api/{repository}],methods=[GET],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.hateoas.Resources<?> org.springframework.data.rest.webmvc.RepositoryEntityController.getCollectionResourceCompact(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.support.DefaultedPageable,org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws org.springframework.data.rest.webmvc.ResourceNotFoundException,org.springframework.web.HttpRequestMethodNotSupportedException",
                "predicate": "{[/api/{repository}],methods=[GET],produces=[application/x-spring-data-compact+json || text/uri-list]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryEntityController.postCollectionResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.PersistentEntityResource,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler,java.lang.String) throws org.springframework.web.HttpRequestMethodNotSupportedException",
                "predicate": "{[/api/{repository}],methods=[POST],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryEntityController.optionsForItemResource(org.springframework.data.rest.webmvc.RootResourceInformation)",
                "predicate": "{[/api/{repository}/{id}],methods=[OPTIONS],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryEntityController.headForItemResource(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws org.springframework.web.HttpRequestMethodNotSupportedException",
                "predicate": "{[/api/{repository}/{id}],methods=[HEAD],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.Resource<?>> org.springframework.data.rest.webmvc.RepositoryEntityController.getItemResource(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler,org.springframework.http.HttpHeaders) throws org.springframework.web.HttpRequestMethodNotSupportedException",
                "predicate": "{[/api/{repository}/{id}],methods=[GET],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<? extends org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryEntityController.putItemResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.PersistentEntityResource,java.io.Serializable,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler,org.springframework.data.rest.webmvc.support.ETag,java.lang.String) throws org.springframework.web.HttpRequestMethodNotSupportedException",
                "predicate": "{[/api/{repository}/{id}],methods=[PUT],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryEntityController.patchItemResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.PersistentEntityResource,java.io.Serializable,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler,org.springframework.data.rest.webmvc.support.ETag,java.lang.String) throws org.springframework.web.HttpRequestMethodNotSupportedException,org.springframework.data.rest.webmvc.ResourceNotFoundException",
                "predicate": "{[/api/{repository}/{id}],methods=[PATCH],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryEntityController.deleteItemResource(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,org.springframework.data.rest.webmvc.support.ETag) throws org.springframework.data.rest.webmvc.ResourceNotFoundException,org.springframework.web.HttpRequestMethodNotSupportedException",
                "predicate": "{[/api/{repository}/{id}],methods=[DELETE],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.data.rest.webmvc.RepositorySearchesResource org.springframework.data.rest.webmvc.RepositorySearchController.listSearches(org.springframework.data.rest.webmvc.RootResourceInformation)",
                "predicate": "{[/api/{repository}/search],methods=[GET],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.HttpEntity<?> org.springframework.data.rest.webmvc.RepositorySearchController.optionsForSearches(org.springframework.data.rest.webmvc.RootResourceInformation)",
                "predicate": "{[/api/{repository}/search],methods=[OPTIONS],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.HttpEntity<?> org.springframework.data.rest.webmvc.RepositorySearchController.headForSearches(org.springframework.data.rest.webmvc.RootResourceInformation)",
                "predicate": "{[/api/{repository}/search],methods=[HEAD],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositorySearchController.executeSearch(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.util.MultiValueMap<java.lang.String, java.lang.Object>,java.lang.String,org.springframework.data.rest.webmvc.support.DefaultedPageable,org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler,org.springframework.http.HttpHeaders)",
                "predicate": "{[/api/{repository}/search/{search}],methods=[GET],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.hateoas.ResourceSupport org.springframework.data.rest.webmvc.RepositorySearchController.executeSearchCompact(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.http.HttpHeaders,org.springframework.util.MultiValueMap<java.lang.String, java.lang.Object>,java.lang.String,java.lang.String,org.springframework.data.rest.webmvc.support.DefaultedPageable,org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler)",
                "predicate": "{[/api/{repository}/search/{search}],methods=[GET],produces=[application/x-spring-data-compact+json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<java.lang.Object> org.springframework.data.rest.webmvc.RepositorySearchController.optionsForSearch(org.springframework.data.rest.webmvc.RootResourceInformation,java.lang.String)",
                "predicate": "{[/api/{repository}/search/{search}],methods=[OPTIONS],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<java.lang.Object> org.springframework.data.rest.webmvc.RepositorySearchController.headForSearch(org.springframework.data.rest.webmvc.RootResourceInformation,java.lang.String)",
                "predicate": "{[/api/{repository}/search/{search}],methods=[HEAD],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.followPropertyReference(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,java.lang.String,java.lang.String,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws java.lang.Exception",
                "predicate": "{[/api/{repository}/{id}/{property}/{propertyId}],methods=[GET],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.followPropertyReference(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,java.lang.String,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws java.lang.Exception",
                "predicate": "{[/api/{repository}/{id}/{property}],methods=[GET],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<? extends org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.deletePropertyReference(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,java.lang.String) throws java.lang.Exception",
                "predicate": "{[/api/{repository}/{id}/{property}],methods=[DELETE],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.followPropertyReferenceCompact(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,java.lang.String,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws java.lang.Exception",
                "predicate": "{[/api/{repository}/{id}/{property}],methods=[GET],produces=[application/x-spring-data-compact+json || text/uri-list]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<? extends org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.createPropertyReference(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.http.HttpMethod,org.springframework.hateoas.Resources<java.lang.Object>,java.io.Serializable,java.lang.String) throws java.lang.Exception",
                "predicate": "{[/api/{repository}/{id}/{property}],methods=[PATCH || PUT || POST],consumes=[application/json || application/x-spring-data-compact+json || text/uri-list],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.deletePropertyReferenceId(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,java.lang.String,java.lang.String) throws java.lang.Exception",
                "predicate": "{[/api/{repository}/{id}/{property}/{propertyId}],methods=[DELETE],produces=[application/hal+json || application/json]}"
            },
            {
                "handler": "ResourceHttpRequestHandler [locations=[class path resource [META-INF/resources/webjars/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@652dcdbd]]",
                "predicate": "/webjars/**"
            },
            {
                "handler": "ResourceHttpRequestHandler [locations=[class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@3573cd19]]",
                "predicate": "/**"
            }
        ]
    },
    "servletFilters": [
        {
            "className": "org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter",
            "name": "requestContextFilter",
            "servletNameMappings": [],
            "urlPatternMappings": [
                "/*"
            ]
        },
        {
            "className": "org.apache.tomcat.websocket.server.WsFilter",
            "name": "Tomcat WebSocket (JSR356) Filter",
            "servletNameMappings": [],
            "urlPatternMappings": [
                "/*"
            ]
        },
        {
            "className": "org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter",
            "name": "httpPutFormContentFilter",
            "servletNameMappings": [],
            "urlPatternMappings": [
                "/*"
            ]
        },
        {
            "className": "org.springframework.boot.web.servlet.filter.OrderedHiddenHttpMethodFilter",
            "name": "hiddenHttpMethodFilter",
            "servletNameMappings": [],
            "urlPatternMappings": [
                "/*"
            ]
        },
        {
            "className": "org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter",
            "name": "characterEncodingFilter",
            "servletNameMappings": [],
            "urlPatternMappings": [
                "/*"
            ]
        },
        {
            "className": "org.springframework.boot.actuate.trace.WebRequestTraceFilter",
            "name": "webRequestLoggingFilter",
            "servletNameMappings": [],
            "urlPatternMappings": [
                "/*"
            ]
        }
    ],
    "servlets": [
        {
            "className": "org.apache.catalina.servlets.DefaultServlet",
            "mappings": [],
            "name": "default"
        },
        {
            "className": "org.springframework.web.servlet.DispatcherServlet",
            "mappings": [
                "/"
            ],
            "name": "dispatcherServlet"
        }
    ]
}

And here's an example for a WebFlux application:

{
    "dispatcherHandlers": {
        "webHandler": [
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/auditevents],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/beans],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/autoconfig],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/configprops],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/env/{toMatch}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/env],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/health],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/status],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/info],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/loggers],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/loggers/{name}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$WriteOperationHandler.handle(org.springframework.web.server.ServerWebExchange,java.util.Map<java.lang.String, java.lang.String>)",
                "predicate": "{[/application/loggers/{name}],methods=[POST],consumes=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/threaddump],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/metrics],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/metrics/{requiredMetricName}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/trace],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/mappings],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
                "predicate": "{[/application/heapdump],methods=[GET],produces=[application/octet-stream]}"
            },
            {
                "handler": "private java.util.Map<java.lang.String, java.util.Map<java.lang.String, org.springframework.boot.actuate.endpoint.web.Link>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping.links(org.springframework.http.server.reactive.ServerHttpRequest)",
                "predicate": "{[/application],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
            },
            {
                "handler": "sample.webflux.SampleWebFluxApplication$$Lambda$177/2063786038@49bd54f7",
                "predicate": "(POST && /echo)"
            },
            {
                "handler": "sample.webflux.SampleWebFluxApplication$$Lambda$179/1005093407@6b5f8707",
                "predicate": "(GET && /whatever)"
            },
            {
                "handler": "public java.lang.String sample.webflux.WelcomeController.welcome()",
                "predicate": "{[/],methods=[GET]}"
            },
            {
                "handler": "ResourceWebHandler [locations=[class path resource [META-INF/resources/webjars/]], resolvers=[org.springframework.web.reactive.resource.PathResourceResolver@3258b7d8]]",
                "predicate": "/webjars/**"
            },
            {
                "handler": "ResourceWebHandler [locations=[class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/]], resolvers=[org.springframework.web.reactive.resource.PathResourceResolver@6a38fa48]]",
                "predicate": "/**"
            }
        ]
    }
}

A few notes about the example responses:

  • dispatcherServlets and dispatcherHandlers are as there may be more than one DispatcherServlet or DispatcherHandler bean in the application context.
  • The keys in the dispatcherServlets and dispatcherHandlers maps are the names of the beans.
  • The values in the dispatcherServlets and dispatcherHandlers maps are arrays of the known handlers. The order of the array reflects the order of the handlers in the dispatcher.
  • The top-level keys (dispatcherServlets, dispatcherHandlers, servlets, servletFilters) are named such that they are unique even when a client might be dealing with a mixture of servlet and reactive web applications.
  • It would be nice to be able to list WebFilters used by WebFlux but that doesn't appear to be possible (at the moment at least) without resorting to reflective hacks.
  • The code that produced the above is in this branch of my fork.

@wilkinsona wilkinsona added the for: team-attention An issue we'd like other members of the team to review label Nov 1, 2017
@kaleev
Copy link

kaleev commented Nov 2, 2017

Mapping endpoint's output contains endpoints entries (e.g beans, health) when management port is equal to application port, and it doesn’t contain them when management port differs from application port.
It seems like a bug. So it should be possible to distinguish management request mappings and application request mappings in json output, since IDEA as well as STS need to build correct URLs for entries from the output in order to get an ability to navigate to them.
I suppose top-level 'context' keys would be enough.

@wilkinsona
Copy link
Member Author

Thank you, @kaleev. Given that the change proposed here is going to be a breaking change to the JSON's structure, and fixing the problem you've described would also require a breaking change, doing both at the same time makes a lot of sense. I'll see what we can do.

@wilkinsona
Copy link
Member Author

The problem with the mappings not being visible when there's a context hierarchy (as there is when the management port is set) is a specific case of the problem tracked by #5312.

@wilkinsona wilkinsona added the status: blocked An issue that's blocked on an external project change label Nov 2, 2017
@wilkinsona
Copy link
Member Author

There's a problem with the proposed implementation when the management port has been configured. If a request to the mappings endpoint is made before the application's dispatcher servlet has handled any request, it's handler mappings will be null as they are only initialized on first request by default. I've asked @rstoyanchev if there's anything that could be done in the Framework to remove this restriction.

@wilkinsona wilkinsona modified the milestones: 2.0.0.M6, 2.0.0.RC1 Nov 3, 2017
@wilkinsona wilkinsona removed for: team-attention An issue we'd like other members of the team to review status: blocked An issue that's blocked on an external project change labels Nov 11, 2017
@wilkinsona
Copy link
Member Author

Nothing can be done in DispatcherServlet to address the problem described above however it's possible to write some container-specific logic to trigger initialisation of the DispatcherServlet when needed.

@philwebb philwebb modified the milestones: 2.0.0.M7, 2.0.0.RC1 Nov 22, 2017
@wilkinsona wilkinsona self-assigned this Jan 4, 2018
@wilkinsona wilkinsona added the status: blocked An issue that's blocked on an external project change label Jan 4, 2018
@wilkinsona wilkinsona removed the status: blocked An issue that's blocked on an external project change label Jan 12, 2018
@wilkinsona
Copy link
Member Author

The response structure has changed to align with the recent changes for better handling of context hierarchies. Here's an example of the updated structure:

{
    "contexts": {
        "application": {
            "mappings": {
                "dispatcherServlets": {
                    "dispatcherServlet": [
                        {
                            "handler": "ResourceHttpRequestHandler [locations=[class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/], class path resource []], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@282c6b8]]",
                            "predicate": "/**/favicon.ico"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)",
                            "predicate": "{[/error]}"
                        },
                        {
                            "handler": "public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)",
                            "predicate": "{[/error],produces=[text/html]}"
                        },
                        {
                            "handler": "org.springframework.http.HttpEntity<org.springframework.data.rest.webmvc.RootResourceInformation> org.springframework.data.rest.webmvc.alps.AlpsController.descriptor(org.springframework.data.rest.webmvc.RootResourceInformation)",
                            "predicate": "{[/api/profile/{repository}],methods=[GET],produces=[application/alps+json || */*]}"
                        },
                        {
                            "handler": "org.springframework.http.HttpEntity<?> org.springframework.data.rest.webmvc.alps.AlpsController.alpsOptions()",
                            "predicate": "{[/api/profile/{repository}],methods=[OPTIONS],produces=[application/alps+json]}"
                        },
                        {
                            "handler": "public org.springframework.http.HttpEntity<org.springframework.data.rest.webmvc.json.JsonSchema> org.springframework.data.rest.webmvc.RepositorySchemaController.schema(org.springframework.data.rest.webmvc.RootResourceInformation)",
                            "predicate": "{[/api/profile/{repository}],methods=[GET],produces=[application/schema+json]}"
                        },
                        {
                            "handler": "public org.springframework.http.HttpEntity<?> org.springframework.data.rest.webmvc.ProfileController.profileOptions()",
                            "predicate": "{[/api/profile],methods=[OPTIONS]}"
                        },
                        {
                            "handler": "org.springframework.http.HttpEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.ProfileController.listAllFormsOfMetadata()",
                            "predicate": "{[/api/profile],methods=[GET]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.followPropertyReference(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,java.lang.String,java.lang.String,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws java.lang.Exception",
                            "predicate": "{[/api/{repository}/{id}/{property}/{propertyId}],methods=[GET],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.followPropertyReference(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,java.lang.String,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws java.lang.Exception",
                            "predicate": "{[/api/{repository}/{id}/{property}],methods=[GET],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<? extends org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.deletePropertyReference(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,java.lang.String) throws java.lang.Exception",
                            "predicate": "{[/api/{repository}/{id}/{property}],methods=[DELETE],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.followPropertyReferenceCompact(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,java.lang.String,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws java.lang.Exception",
                            "predicate": "{[/api/{repository}/{id}/{property}],methods=[GET],produces=[application/x-spring-data-compact+json || text/uri-list]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<? extends org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.createPropertyReference(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.http.HttpMethod,org.springframework.hateoas.Resources<java.lang.Object>,java.io.Serializable,java.lang.String) throws java.lang.Exception",
                            "predicate": "{[/api/{repository}/{id}/{property}],methods=[PATCH || PUT || POST],consumes=[application/json || application/x-spring-data-compact+json || text/uri-list],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.deletePropertyReferenceId(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,java.lang.String,java.lang.String) throws java.lang.Exception",
                            "predicate": "{[/api/{repository}/{id}/{property}/{propertyId}],methods=[DELETE],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.HttpEntity<?> org.springframework.data.rest.webmvc.RepositoryController.optionsForRepositories()",
                            "predicate": "{[/api/ || /api],methods=[OPTIONS],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryController.headForRepositories()",
                            "predicate": "{[/api/ || /api],methods=[HEAD],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.HttpEntity<org.springframework.data.rest.webmvc.RepositoryLinksResource> org.springframework.data.rest.webmvc.RepositoryController.listRepositories()",
                            "predicate": "{[/api/ || /api],methods=[GET],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryEntityController.optionsForCollectionResource(org.springframework.data.rest.webmvc.RootResourceInformation)",
                            "predicate": "{[/api/{repository}],methods=[OPTIONS],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryEntityController.headCollectionResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.support.DefaultedPageable) throws org.springframework.web.HttpRequestMethodNotSupportedException",
                            "predicate": "{[/api/{repository}],methods=[HEAD],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.hateoas.Resources<?> org.springframework.data.rest.webmvc.RepositoryEntityController.getCollectionResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.support.DefaultedPageable,org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws org.springframework.data.rest.webmvc.ResourceNotFoundException,org.springframework.web.HttpRequestMethodNotSupportedException",
                            "predicate": "{[/api/{repository}],methods=[GET],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.hateoas.Resources<?> org.springframework.data.rest.webmvc.RepositoryEntityController.getCollectionResourceCompact(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.support.DefaultedPageable,org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws org.springframework.data.rest.webmvc.ResourceNotFoundException,org.springframework.web.HttpRequestMethodNotSupportedException",
                            "predicate": "{[/api/{repository}],methods=[GET],produces=[application/x-spring-data-compact+json || text/uri-list]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryEntityController.postCollectionResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.PersistentEntityResource,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler,java.lang.String) throws org.springframework.web.HttpRequestMethodNotSupportedException",
                            "predicate": "{[/api/{repository}],methods=[POST],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryEntityController.optionsForItemResource(org.springframework.data.rest.webmvc.RootResourceInformation)",
                            "predicate": "{[/api/{repository}/{id}],methods=[OPTIONS],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryEntityController.headForItemResource(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws org.springframework.web.HttpRequestMethodNotSupportedException",
                            "predicate": "{[/api/{repository}/{id}],methods=[HEAD],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.Resource<?>> org.springframework.data.rest.webmvc.RepositoryEntityController.getItemResource(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler,org.springframework.http.HttpHeaders) throws org.springframework.web.HttpRequestMethodNotSupportedException",
                            "predicate": "{[/api/{repository}/{id}],methods=[GET],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<? extends org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryEntityController.putItemResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.PersistentEntityResource,java.io.Serializable,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler,org.springframework.data.rest.webmvc.support.ETag,java.lang.String) throws org.springframework.web.HttpRequestMethodNotSupportedException",
                            "predicate": "{[/api/{repository}/{id}],methods=[PUT],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<org.springframework.hateoas.ResourceSupport> org.springframework.data.rest.webmvc.RepositoryEntityController.patchItemResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.PersistentEntityResource,java.io.Serializable,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler,org.springframework.data.rest.webmvc.support.ETag,java.lang.String) throws org.springframework.web.HttpRequestMethodNotSupportedException,org.springframework.data.rest.webmvc.ResourceNotFoundException",
                            "predicate": "{[/api/{repository}/{id}],methods=[PATCH],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositoryEntityController.deleteItemResource(org.springframework.data.rest.webmvc.RootResourceInformation,java.io.Serializable,org.springframework.data.rest.webmvc.support.ETag) throws org.springframework.data.rest.webmvc.ResourceNotFoundException,org.springframework.web.HttpRequestMethodNotSupportedException",
                            "predicate": "{[/api/{repository}/{id}],methods=[DELETE],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.data.rest.webmvc.RepositorySearchesResource org.springframework.data.rest.webmvc.RepositorySearchController.listSearches(org.springframework.data.rest.webmvc.RootResourceInformation)",
                            "predicate": "{[/api/{repository}/search],methods=[GET],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.HttpEntity<?> org.springframework.data.rest.webmvc.RepositorySearchController.optionsForSearches(org.springframework.data.rest.webmvc.RootResourceInformation)",
                            "predicate": "{[/api/{repository}/search],methods=[OPTIONS],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.HttpEntity<?> org.springframework.data.rest.webmvc.RepositorySearchController.headForSearches(org.springframework.data.rest.webmvc.RootResourceInformation)",
                            "predicate": "{[/api/{repository}/search],methods=[HEAD],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<?> org.springframework.data.rest.webmvc.RepositorySearchController.executeSearch(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.util.MultiValueMap<java.lang.String, java.lang.Object>,java.lang.String,org.springframework.data.rest.webmvc.support.DefaultedPageable,org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler,org.springframework.http.HttpHeaders)",
                            "predicate": "{[/api/{repository}/search/{search}],methods=[GET],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.hateoas.ResourceSupport org.springframework.data.rest.webmvc.RepositorySearchController.executeSearchCompact(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.http.HttpHeaders,org.springframework.util.MultiValueMap<java.lang.String, java.lang.Object>,java.lang.String,java.lang.String,org.springframework.data.rest.webmvc.support.DefaultedPageable,org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler)",
                            "predicate": "{[/api/{repository}/search/{search}],methods=[GET],produces=[application/x-spring-data-compact+json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<java.lang.Object> org.springframework.data.rest.webmvc.RepositorySearchController.optionsForSearch(org.springframework.data.rest.webmvc.RootResourceInformation,java.lang.String)",
                            "predicate": "{[/api/{repository}/search/{search}],methods=[OPTIONS],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "public org.springframework.http.ResponseEntity<java.lang.Object> org.springframework.data.rest.webmvc.RepositorySearchController.headForSearch(org.springframework.data.rest.webmvc.RootResourceInformation,java.lang.String)",
                            "predicate": "{[/api/{repository}/search/{search}],methods=[HEAD],produces=[application/hal+json || application/json]}"
                        },
                        {
                            "handler": "ResourceHttpRequestHandler [locations=[class path resource [META-INF/resources/webjars/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@72f56ddf]]",
                            "predicate": "/webjars/**"
                        },
                        {
                            "handler": "ResourceHttpRequestHandler [locations=[class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@6656c23f]]",
                            "predicate": "/**"
                        }
                    ]
                },
                "servletFilters": [
                    {
                        "className": "org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter",
                        "name": "requestContextFilter",
                        "servletNameMappings": [],
                        "urlPatternMappings": [
                            "/*"
                        ]
                    },
                    {
                        "className": "org.apache.tomcat.websocket.server.WsFilter",
                        "name": "Tomcat WebSocket (JSR356) Filter",
                        "servletNameMappings": [],
                        "urlPatternMappings": [
                            "/*"
                        ]
                    },
                    {
                        "className": "org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter",
                        "name": "httpPutFormContentFilter",
                        "servletNameMappings": [],
                        "urlPatternMappings": [
                            "/*"
                        ]
                    },
                    {
                        "className": "org.springframework.boot.web.servlet.filter.OrderedHiddenHttpMethodFilter",
                        "name": "hiddenHttpMethodFilter",
                        "servletNameMappings": [],
                        "urlPatternMappings": [
                            "/*"
                        ]
                    },
                    {
                        "className": "org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter",
                        "name": "characterEncodingFilter",
                        "servletNameMappings": [],
                        "urlPatternMappings": [
                            "/*"
                        ]
                    },
                    {
                        "className": "org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter",
                        "name": "webMetricsFilter",
                        "servletNameMappings": [],
                        "urlPatternMappings": [
                            "/*"
                        ]
                    },
                    {
                        "className": "org.springframework.boot.actuate.trace.WebRequestTraceFilter",
                        "name": "webRequestLoggingFilter",
                        "servletNameMappings": [],
                        "urlPatternMappings": [
                            "/*"
                        ]
                    }
                ],
                "servlets": [
                    {
                        "className": "org.apache.catalina.servlets.DefaultServlet",
                        "mappings": [],
                        "name": "default"
                    },
                    {
                        "className": "org.springframework.web.servlet.DispatcherServlet",
                        "mappings": [
                            "/"
                        ],
                        "name": "dispatcherServlet"
                    }
                ]
            },
            "parentId": null
        }
    }
}

contexts is a new top-level entry. This map contains an entry for each application context, keyed by id, that's known to the endpoint. Each entry for a specific context has two keys: parentId and mappings. parentId is the id of the parent context, if any. mappings is a map of the context's mappings with entries that use the same 4 possible keys as described above (dispatcherServlets, dispatcherHandlers, servlets, servletFilters).

@wilkinsona
Copy link
Member Author

wilkinsona commented Jan 22, 2018

The code would benefit from being in a mappings-specific package rather than the more general-purpose actuate.web package that it's currently in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants