diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml
index 2d793ae266..de859f77c1 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml
@@ -435,6 +435,11 @@
spring-restdocs-mockmvc
test
+
+ org.springframework.restdocs
+ spring-restdocs-webtestclient
+ test
+
org.springframework.security
spring-security-test
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/mappings.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/mappings.adoc
new file mode 100644
index 0000000000..2ef662f1a5
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/mappings.adoc
@@ -0,0 +1,80 @@
+[[mappings]]
+= Mappings (`mappings`)
+
+The `mappings` endpoint provides information about the application's request mappings.
+
+
+
+[[mappings-retrieving]]
+== Retrieving the Mappings
+
+To retrieve the mappings, make a `GET` request to `/actuator/mappings`, as shown in the
+following curl-based example:
+
+include::{snippets}mappings/curl-request.adoc[]
+
+The resulting response is similar to the following:
+
+include::{snippets}mappings/http-response.adoc[]
+
+
+
+[[mappings-retrieving-response-structure]]
+=== Response Structure
+
+The response contains details of the application's mappings. The items found in the
+response depend on the type of web application (reactive or Servlet-based). The
+following table describes the structure of the common elements of the response:
+
+[cols="2,1,3"]
+include::{snippets}mappings/response-fields.adoc[]
+
+The entries that may be found in `contexts.*.mappings` are described in the
+following sections.
+
+
+[[mappings-retrieving-response-structure-dispatcher-servlets]]
+=== Dispatcher Servlets Response Structure
+
+When using Spring MVC, the response contains details of any `DispatcherServlet`
+request mappings beneath `contexts.*.mappings.dispatcherServlets`. The following
+table describes the structure of this section of the response:
+
+[cols="2,1,3"]
+include::{snippets}mappings/response-fields-dispatcher-servlets.adoc[]
+
+
+
+[[mappings-retrieving-response-structure-servlets]]
+=== Servlets Response Structure
+
+When using the Servlet stack, the response contains details of any `Servlet` mappings
+beneath `contexts.*.mappings.servlets`. The following table describes the structure of
+this section of the response:
+
+[cols="2,1,3"]
+include::{snippets}mappings/response-fields-servlets.adoc[]
+
+
+
+[[mappings-retrieving-response-structure-servlet-filters]]
+=== Servlet Filters Response Structure
+
+When using the Servlet stack, the response contains details of any `Filter` mappings
+beneath `contexts.*.mappings.servletFilters`. The following table describes the
+structure of this section of the response:
+
+[cols="2,1,3"]
+include::{snippets}mappings/response-fields-servlet-filters.adoc[]
+
+
+
+[[mappings-retrieving-response-structure-dispatcher-servlets]]
+=== Dispatcher Handlers Response Structure
+
+When using Spring WebFlux, the response contains details of any `DispatcherHandler`
+request mappings beneath `contexts.*.mappings.dispatcherHandlers`. The following
+table describes the structure of this section of the response:
+
+[cols="2,1,3"]
+include::{snippets}mappings/response-fields-dispatcher-handlers.adoc[]
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc
index 14af3216ef..c0d6a3ac04 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc
@@ -61,6 +61,7 @@ include::endpoints/info.adoc[leveloffset=+1]
include::endpoints/liquibase.adoc[leveloffset=+1]
include::endpoints/logfile.adoc[leveloffset=+1]
include::endpoints/loggers.adoc[leveloffset=+1]
+include::endpoints/mappings.adoc[leveloffset=+1]
include::endpoints/metrics.adoc[leveloffset=+1]
include::endpoints/prometheus.adoc[leveloffset=+1]
include::endpoints/scheduledtasks.adoc[leveloffset=+1]
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/MappingsEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/MappingsEndpointAutoConfiguration.java
new file mode 100644
index 0000000000..52aa8e73fa
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/MappingsEndpointAutoConfiguration.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.web;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
+import org.springframework.boot.actuate.web.MappingDescriptionProvider;
+import org.springframework.boot.actuate.web.MappingsEndpoint;
+import org.springframework.boot.actuate.web.reactive.DispatcherHandlersMappingDescriptionProvider;
+import org.springframework.boot.actuate.web.servlet.DispatcherServletsMappingDescriptionProvider;
+import org.springframework.boot.actuate.web.servlet.FiltersMappingDescriptionProvider;
+import org.springframework.boot.actuate.web.servlet.ServletsMappingDescriptionProvider;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.reactive.DispatcherHandler;
+import org.springframework.web.servlet.DispatcherServlet;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for {@link MappingsEndpoint}.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+@ManagementContextConfiguration
+public class MappingsEndpointAutoConfiguration {
+
+ @Bean
+ @ConditionalOnEnabledEndpoint
+ public MappingsEndpoint mappingsEndpoint(ApplicationContext applicationContext,
+ ObjectProvider> descriptionProviders) {
+ return new MappingsEndpoint(
+ descriptionProviders.getIfAvailable(Collections::emptyList),
+ applicationContext);
+ }
+
+ @Configuration
+ @ConditionalOnWebApplication(type = Type.SERVLET)
+ static class ServletWebConfiguration {
+
+ @Bean
+ ServletsMappingDescriptionProvider servletMappingDescriptionProvider() {
+ return new ServletsMappingDescriptionProvider();
+ }
+
+ @Bean
+ FiltersMappingDescriptionProvider filterMappingDescriptionProvider() {
+ return new FiltersMappingDescriptionProvider();
+ }
+
+ @Configuration
+ @ConditionalOnClass(DispatcherServlet.class)
+ @ConditionalOnBean(DispatcherServlet.class)
+ static class SpringMvcConfiguration {
+
+ @Bean
+ DispatcherServletsMappingDescriptionProvider dispatcherServletMappingDescriptionProvider(
+ ApplicationContext applicationContext) {
+ return new DispatcherServletsMappingDescriptionProvider();
+ }
+
+ }
+
+ }
+
+ @Configuration
+ @ConditionalOnWebApplication(type = Type.REACTIVE)
+ @ConditionalOnClass(DispatcherHandler.class)
+ @ConditionalOnBean(DispatcherHandler.class)
+ static class ReactiveWebConfiguration {
+
+ @Bean
+ public DispatcherHandlersMappingDescriptionProvider dispatcherHandlerMappingDescriptionProvider(
+ ApplicationContext applicationContext) {
+ return new DispatcherHandlersMappingDescriptionProvider();
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/servlet/RequestMappingEndpoint.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/servlet/RequestMappingEndpoint.java
deleted file mode 100644
index 5ac5864932..0000000000
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/servlet/RequestMappingEndpoint.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2012-2017 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.boot.actuate.autoconfigure.web.servlet;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.springframework.aop.support.AopUtils;
-import org.springframework.beans.BeansException;
-import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
-import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
-import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
-
-/**
- * {@link Endpoint} to expose Spring MVC mappings.
- *
- * @author Dave Syer
- * @author Andy Wilkinson
- * @since 2.0.0
- */
-@Endpoint(id = "mappings")
-public class RequestMappingEndpoint implements ApplicationContextAware {
-
- private List handlerMappings = Collections.emptyList();
-
- private List> methodMappings = Collections
- .emptyList();
-
- private ApplicationContext applicationContext;
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext)
- throws BeansException {
- this.applicationContext = applicationContext;
- }
-
- /**
- * Set the handler mappings.
- * @param handlerMappings the handler mappings
- */
- public void setHandlerMappings(List handlerMappings) {
- this.handlerMappings = handlerMappings;
- }
-
- /**
- * Set the method mappings.
- * @param methodMappings the method mappings
- */
- public void setMethodMappings(List> methodMappings) {
- this.methodMappings = methodMappings;
- }
-
- @ReadOperation
- public Map mappings() {
- Map result = new LinkedHashMap<>();
- extractHandlerMappings(this.handlerMappings, result);
- extractHandlerMappings(this.applicationContext, result);
- extractMethodMappings(this.methodMappings, result);
- extractMethodMappings(this.applicationContext, result);
- return result;
- }
-
- @SuppressWarnings("rawtypes")
- protected void extractMethodMappings(ApplicationContext applicationContext,
- Map result) {
- if (applicationContext != null) {
- for (Entry bean : applicationContext
- .getBeansOfType(AbstractHandlerMethodMapping.class).entrySet()) {
- @SuppressWarnings("unchecked")
- Map, HandlerMethod> methods = bean.getValue().getHandlerMethods();
- for (Entry, HandlerMethod> method : methods.entrySet()) {
- Map map = new LinkedHashMap<>();
- map.put("bean", bean.getKey());
- map.put("method", method.getValue().toString());
- result.put(method.getKey().toString(), map);
- }
- }
- }
- }
-
- protected void extractHandlerMappings(ApplicationContext applicationContext,
- Map result) {
- if (applicationContext != null) {
- Map mappings = applicationContext
- .getBeansOfType(AbstractUrlHandlerMapping.class);
- for (Entry mapping : mappings.entrySet()) {
- Map handlers = getHandlerMap(mapping.getValue());
- for (Entry handler : handlers.entrySet()) {
- result.put(handler.getKey(),
- Collections.singletonMap("bean", mapping.getKey()));
- }
- }
- }
- }
-
- private Map getHandlerMap(AbstractUrlHandlerMapping mapping) {
- if (AopUtils.isCglibProxy(mapping)) {
- // If the AbstractUrlHandlerMapping is a cglib proxy we can't call
- // the final getHandlerMap() method.
- return Collections.emptyMap();
- }
- return mapping.getHandlerMap();
- }
-
- protected void extractHandlerMappings(
- Collection handlerMappings,
- Map result) {
- for (AbstractUrlHandlerMapping mapping : handlerMappings) {
- Map handlers = mapping.getHandlerMap();
- for (Map.Entry entry : handlers.entrySet()) {
- Class extends Object> handlerClass = entry.getValue().getClass();
- result.put(entry.getKey(),
- Collections.singletonMap("type", handlerClass.getName()));
- }
- }
- }
-
- protected void extractMethodMappings(
- Collection> methodMappings,
- Map result) {
- for (AbstractHandlerMethodMapping> mapping : methodMappings) {
- Map, HandlerMethod> methods = mapping.getHandlerMethods();
- for (Map.Entry, HandlerMethod> entry : methods.entrySet()) {
- result.put(String.valueOf(entry.getKey()), Collections
- .singletonMap("method", String.valueOf(entry.getValue())));
- }
- }
- }
-
-}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/servlet/RequestMappingEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/servlet/RequestMappingEndpointAutoConfiguration.java
deleted file mode 100644
index 04bac88a4f..0000000000
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/servlet/RequestMappingEndpointAutoConfiguration.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2012-2017 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.boot.actuate.autoconfigure.web.servlet;
-
-import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
-
-/**
- * {@link EnableAutoConfiguration Auto-configuration} for {@link RequestMappingEndpoint}.
- *
- * @author Phillip Webb
- * @since 2.0.0
- */
-@Configuration
-@ConditionalOnClass(AbstractHandlerMethodMapping.class)
-public class RequestMappingEndpointAutoConfiguration {
-
- @Bean
- @ConditionalOnMissingBean
- @ConditionalOnEnabledEndpoint
- public RequestMappingEndpoint requestMappingEndpoint() {
- return new RequestMappingEndpoint();
- }
-
-}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories
index d76062be20..6bd280cc93 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -41,10 +41,10 @@ org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthIndicatorAu
org.springframework.boot.actuate.autoconfigure.trace.TraceEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.trace.TraceRepositoryAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.trace.TraceWebFilterAutoConfiguration,\
+org.springframework.boot.actuate.autoconfigure.web.MappingsEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementContextAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration,\
-org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration,\
-org.springframework.boot.actuate.autoconfigure.web.servlet.RequestMappingEndpointAutoConfiguration
+org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=\
org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration,\
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AbstractEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AbstractEndpointDocumentationTests.java
index 2ff5eb4234..46c5e7eca2 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AbstractEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AbstractEndpointDocumentationTests.java
@@ -26,33 +26,26 @@ import java.util.stream.Stream;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
+import org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
+import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration;
+import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
-import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
-import org.springframework.restdocs.JUnitRestDocumentation;
-import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.operation.preprocess.ContentModifyingOperationPreprocessor;
import org.springframework.restdocs.operation.preprocess.OperationPreprocessor;
import org.springframework.restdocs.payload.FieldDescriptor;
import org.springframework.restdocs.payload.JsonFieldType;
-import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.test.context.TestPropertySource;
import org.springframework.util.StringUtils;
-import org.springframework.web.context.WebApplicationContext;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
@@ -62,30 +55,9 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWit
*
* @author Andy Wilkinson
*/
-@RunWith(SpringRunner.class)
-@SpringBootTest(properties = { "spring.jackson.serialization.indent_output=true",
+@TestPropertySource(properties = { "spring.jackson.serialization.indent_output=true",
"management.endpoints.web.expose=*" })
-public abstract class AbstractEndpointDocumentationTests {
-
- @Rule
- public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
-
- protected MockMvc mockMvc;
-
- @Autowired
- private WebApplicationContext applicationContext;
-
- @Before
- public void before() {
- this.mockMvc = MockMvcBuilders.webAppContextSetup(this.applicationContext)
- .apply(MockMvcRestDocumentation
- .documentationConfiguration(this.restDocumentation).uris())
- .build();
- }
-
- protected WebApplicationContext getApplicationContext() {
- return this.applicationContext;
- }
+public class AbstractEndpointDocumentationTests {
protected String describeEnumValues(Class extends Enum>> enumType) {
return StringUtils
@@ -160,7 +132,9 @@ public abstract class AbstractEndpointDocumentationTests {
DispatcherServletAutoConfiguration.class, EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class,
WebMvcEndpointManagementContextConfiguration.class,
- PropertyPlaceholderAutoConfiguration.class })
+ WebFluxEndpointManagementContextConfiguration.class,
+ PropertyPlaceholderAutoConfiguration.class, WebFluxAutoConfiguration.class,
+ HttpHandlerAutoConfiguration.class })
static class BaseDocumentationConfiguration {
}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AuditEventsEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AuditEventsEndpointDocumentationTests.java
index 1edc267296..bfe6c6f080 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AuditEventsEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AuditEventsEndpointDocumentationTests.java
@@ -49,7 +49,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
public class AuditEventsEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
@MockBean
private AuditEventRepository repository;
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/BeansEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/BeansEndpointDocumentationTests.java
index 96d9fc1fc3..e1a1e76b2f 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/BeansEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/BeansEndpointDocumentationTests.java
@@ -45,7 +45,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*
* @author Andy Wilkinson
*/
-public class BeansEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
+public class BeansEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
@Test
public void beans() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ConditionsReportEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ConditionsReportEndpointDocumentationTests.java
index e7afb97f2c..4bdf8b64ac 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ConditionsReportEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ConditionsReportEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,7 +51,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
public class ConditionsReportEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ConfigurationPropertiesReportEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ConfigurationPropertiesReportEndpointDocumentationTests.java
index c80ee76dde..fb14a8a431 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ConfigurationPropertiesReportEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ConfigurationPropertiesReportEndpointDocumentationTests.java
@@ -38,7 +38,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
public class ConfigurationPropertiesReportEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
@Test
public void configProps() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/EnvironmentEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/EnvironmentEndpointDocumentationTests.java
index 531895e733..1c44b54bc7 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/EnvironmentEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/EnvironmentEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -58,7 +58,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
@TestPropertySource(properties = "spring.config.location=classpath:/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/")
public class EnvironmentEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
private static final FieldDescriptor activeProfiles = fieldWithPath("activeProfiles")
.description("Names of the active profiles, if any.");
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/FlywayEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/FlywayEndpointDocumentationTests.java
index 55a198d4df..334e4fe6ea 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/FlywayEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/FlywayEndpointDocumentationTests.java
@@ -45,7 +45,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
@AutoConfigureTestDatabase
-public class FlywayEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
+public class FlywayEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
@Test
public void flyway() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java
index aad70d26f5..9aebee4c93 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,7 +47,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*
* @author Andy Wilkinson
*/
-public class HealthEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
+public class HealthEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
@Test
public void health() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HeapDumpWebEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HeapDumpWebEndpointDocumentationTests.java
index 2e0f7e2222..20d5dc5889 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HeapDumpWebEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HeapDumpWebEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
public class HeapDumpWebEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
@Test
public void heapDump() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/InfoEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/InfoEndpointDocumentationTests.java
index 9342bc1163..82725e71ee 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/InfoEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/InfoEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*
* @author Andy Wilkinson
*/
-public class InfoEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
+public class InfoEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
@Test
public void info() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LiquibaseEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LiquibaseEndpointDocumentationTests.java
index 1056b603af..abaddf1a6f 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LiquibaseEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LiquibaseEndpointDocumentationTests.java
@@ -43,7 +43,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
public class LiquibaseEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
@Test
public void liquibase() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LogFileWebEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LogFileWebEndpointDocumentationTests.java
index 8b8d263a91..dd0c0ed71c 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LogFileWebEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LogFileWebEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
@TestPropertySource(properties = "logging.file=src/test/resources/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/sample.log")
public class LogFileWebEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
@Test
public void logFile() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LoggersEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LoggersEndpointDocumentationTests.java
index 441ca4b978..08f6e48b00 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LoggersEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LoggersEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
public class LoggersEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
private static final List levelFields = Arrays.asList(
fieldWithPath("configuredLevel")
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MappingsEndpointReactiveDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MappingsEndpointReactiveDocumentationTests.java
new file mode 100644
index 0000000000..8e98a0f1e8
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MappingsEndpointReactiveDocumentationTests.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation;
+
+import java.util.Collection;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.boot.actuate.web.MappingDescriptionProvider;
+import org.springframework.boot.actuate.web.MappingsEndpoint;
+import org.springframework.boot.actuate.web.reactive.DispatcherHandlersMappingDescriptionProvider;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.restdocs.JUnitRestDocumentation;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
+import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
+import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
+import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
+import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.documentationConfiguration;
+
+/**
+ * Tests for generating documentation describing {@link MappingsEndpoint}.
+ *
+ * @author Andy Wilkinson
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=reactive")
+public class MappingsEndpointReactiveDocumentationTests
+ extends AbstractEndpointDocumentationTests {
+
+ @Rule
+ public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
+
+ @LocalServerPort
+ private int port;
+
+ private WebTestClient client;
+
+ @Before
+ public void webTestClient() {
+ this.client = WebTestClient
+ .bindToServer().filter(documentationConfiguration(this.restDocumentation)
+ .snippets().withDefaults())
+ .baseUrl("http://localhost:" + this.port).build();
+ }
+
+ @Test
+ public void mappings() throws Exception {
+ this.client.get().uri("/actuator/mappings").exchange().expectStatus().isOk()
+ .expectBody()
+ .consumeWith(document("mappings",
+ responseFields(
+ beneathPath("contexts.*.mappings.dispatcherHandlers")
+ .withSubsectionId("dispatcher-handlers"),
+ fieldWithPath("*").description(
+ "Dispatcher handler mappings, if any, keyed by "
+ + "dispatcher handler bean name."),
+ fieldWithPath("*.[].handler")
+ .description("Handler for the mapping."),
+ fieldWithPath("*.[].predicate")
+ .description("Predicate for the mapping."))));
+ }
+
+ @Configuration
+ @Import(BaseDocumentationConfiguration.class)
+ static class TestConfiguration {
+
+ @Bean
+ public NettyReactiveWebServerFactory netty() {
+ return new NettyReactiveWebServerFactory(0);
+ }
+
+ @Bean
+ public DispatcherHandlersMappingDescriptionProvider dispatcherHandlersMappingDescriptionProvider() {
+ return new DispatcherHandlersMappingDescriptionProvider();
+ }
+
+ @Bean
+ public MappingsEndpoint mappingsEndpoint(
+ Collection descriptionProviders,
+ ConfigurableApplicationContext context) {
+ return new MappingsEndpoint(descriptionProviders, context);
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MappingsEndpointServletDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MappingsEndpointServletDocumentationTests.java
new file mode 100644
index 0000000000..8d64ec9557
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MappingsEndpointServletDocumentationTests.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation;
+
+import java.util.Collection;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.boot.actuate.web.MappingDescriptionProvider;
+import org.springframework.boot.actuate.web.MappingsEndpoint;
+import org.springframework.boot.actuate.web.servlet.DispatcherServletsMappingDescriptionProvider;
+import org.springframework.boot.actuate.web.servlet.FiltersMappingDescriptionProvider;
+import org.springframework.boot.actuate.web.servlet.ServletsMappingDescriptionProvider;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.restdocs.JUnitRestDocumentation;
+import org.springframework.restdocs.payload.JsonFieldType;
+import org.springframework.restdocs.payload.ResponseFieldsSnippet;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
+import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
+import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
+import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
+import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
+import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.documentationConfiguration;
+
+/**
+ * Tests for generating documentation describing {@link MappingsEndpoint}.
+ *
+ * @author Andy Wilkinson
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+public class MappingsEndpointServletDocumentationTests
+ extends AbstractEndpointDocumentationTests {
+
+ @Rule
+ public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
+
+ @LocalServerPort
+ private int port;
+
+ private WebTestClient client;
+
+ @Before
+ public void webTestClient() {
+ this.client = WebTestClient.bindToServer()
+ .filter(documentationConfiguration(this.restDocumentation))
+ .baseUrl("http://localhost:" + this.port).build();
+ }
+
+ @Test
+ public void mappings() throws Exception {
+ ResponseFieldsSnippet commonResponseFields = responseFields(
+ fieldWithPath("contexts")
+ .description("Application contexts keyed by id."),
+ fieldWithPath("contexts.*.mappings")
+ .description("Mappings in the context, keyed by mapping type."),
+ subsectionWithPath("contexts.*.mappings.dispatcherServlets")
+ .description("Dispatcher servlet mappings, if any."),
+ subsectionWithPath("contexts.*.mappings.servletFilters")
+ .description("Servlet filter mappings, if any."),
+ subsectionWithPath("contexts.*.mappings.servlets")
+ .description("Servlet mappings, if any."),
+ subsectionWithPath("contexts.*.mappings.dispatcherHandlers")
+ .description("Dispatcher handler mappings, if any.").optional()
+ .type(JsonFieldType.OBJECT),
+ parentIdField());
+ this.client.get().uri("/actuator/mappings").exchange().expectBody()
+ .consumeWith(document("mappings", commonResponseFields,
+ responseFields(
+ beneathPath("contexts.*.mappings.dispatcherServlets")
+ .withSubsectionId("dispatcher-servlets"),
+ fieldWithPath("*").description(
+ "Dispatcher servlet mappings, if any, keyed by "
+ + "dispatcher servlet bean name."),
+ fieldWithPath("*.[].handler")
+ .description("Handler for the mapping."),
+ fieldWithPath("*.[].predicate")
+ .description("Predicate for the mapping.")),
+ responseFields(
+ beneathPath("contexts.*.mappings.servletFilters")
+ .withSubsectionId("servlet-filters"),
+ fieldWithPath("[].servletNameMappings").description(
+ "Names of the servlets to which the filter is mapped."),
+ fieldWithPath("[].urlPatternMappings").description(
+ "URL pattern to which the filter is mapped."),
+ fieldWithPath("[].name")
+ .description("Name of the filter."),
+ fieldWithPath("[].className")
+ .description("Class name of the filter")),
+ responseFields(
+ beneathPath("contexts.*.mappings.servlets")
+ .withSubsectionId("servlets"),
+ fieldWithPath("[].mappings")
+ .description("Mappings of the servlet."),
+ fieldWithPath("[].name")
+ .description("Name of the servlet."),
+ fieldWithPath("[].className")
+ .description("Class name of the servlet"))));
+ }
+
+ @Configuration
+ @Import(BaseDocumentationConfiguration.class)
+ static class TestConfiguration {
+
+ @Bean
+ public TomcatServletWebServerFactory tomcat() {
+ return new TomcatServletWebServerFactory(0);
+ }
+
+ @Bean
+ public DispatcherServletsMappingDescriptionProvider dispatcherServletsMappingDescriptionProvider() {
+ return new DispatcherServletsMappingDescriptionProvider();
+ }
+
+ @Bean
+ public ServletsMappingDescriptionProvider servletsMappingDescriptionProvider() {
+ return new ServletsMappingDescriptionProvider();
+ }
+
+ @Bean
+ public FiltersMappingDescriptionProvider filtersMappingDescriptionProvider() {
+ return new FiltersMappingDescriptionProvider();
+ }
+
+ @Bean
+ public MappingsEndpoint mappingsEndpoint(
+ Collection descriptionProviders,
+ ConfigurableApplicationContext context) {
+ return new MappingsEndpoint(descriptionProviders, context);
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MetricsEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MetricsEndpointDocumentationTests.java
index 0a2c96fc4b..d242b91d14 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MetricsEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MetricsEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
public class MetricsEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
@Test
public void metricNames() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MockMvcEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MockMvcEndpointDocumentationTests.java
new file mode 100644
index 0000000000..674bcf0f88
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/MockMvcEndpointDocumentationTests.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.restdocs.JUnitRestDocumentation;
+import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+/**
+ * Abstract base class for tests that generate endpoint documentation using Spring REST
+ * Docs and {@link MockMvc}.
+ *
+ * @author Andy Wilkinson
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(properties = { "spring.jackson.serialization.indent_output=true",
+ "management.endpoints.web.expose=*" })
+public abstract class MockMvcEndpointDocumentationTests
+ extends AbstractEndpointDocumentationTests {
+
+ @Rule
+ public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
+
+ protected MockMvc mockMvc;
+
+ @Autowired
+ private WebApplicationContext applicationContext;
+
+ @Before
+ public void before() {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.applicationContext)
+ .apply(MockMvcRestDocumentation
+ .documentationConfiguration(this.restDocumentation).uris())
+ .build();
+ }
+
+ protected WebApplicationContext getApplicationContext() {
+ return this.applicationContext;
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/PrometheusScrapeEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/PrometheusScrapeEndpointDocumentationTests.java
index ef5d921aff..cc5f2945db 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/PrometheusScrapeEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/PrometheusScrapeEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
public class PrometheusScrapeEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
@Test
public void prometheus() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ScheduledTasksEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ScheduledTasksEndpointDocumentationTests.java
index 825abe5428..65901ed546 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ScheduledTasksEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ScheduledTasksEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
public class ScheduledTasksEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
@Test
public void scheduledTasks() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/SessionsEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/SessionsEndpointDocumentationTests.java
index d9976084c4..242a9419c0 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/SessionsEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/SessionsEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,7 +55,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
@TestPropertySource(properties = "spring.jackson.serialization.write-dates-as-timestamps=false")
public class SessionsEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
private static final Session sessionOne = createSession(
Instant.now().minusSeconds(60 * 60 * 12), Instant.now().minusSeconds(45));
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ShutdownEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ShutdownEndpointDocumentationTests.java
index 23af808169..02684dbb05 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ShutdownEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ShutdownEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
public class ShutdownEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
@Test
public void shutdown() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ThreadDumpEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ThreadDumpEndpointDocumentationTests.java
index 1e2be9d71c..84741b4b8f 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ThreadDumpEndpointDocumentationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/ThreadDumpEndpointDocumentationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Andy Wilkinson
*/
public class ThreadDumpEndpointDocumentationTests
- extends AbstractEndpointDocumentationTests {
+ extends MockMvcEndpointDocumentationTests {
@Test
public void threadDump() throws Exception {
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/EndpointAutoConfigurationClasses.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/EndpointAutoConfigurationClasses.java
index 65d2a5ea0c..e9b346bb2c 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/EndpointAutoConfigurationClasses.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/EndpointAutoConfigurationClasses.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoC
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.trace.TraceEndpointAutoConfiguration;
-import org.springframework.boot.actuate.autoconfigure.web.servlet.RequestMappingEndpointAutoConfiguration;
+import org.springframework.boot.actuate.autoconfigure.web.MappingsEndpointAutoConfiguration;
/**
* A list of all endpoint auto-configuration classes for use in tests.
@@ -50,7 +50,7 @@ final class EndpointAutoConfigurationClasses {
all.add(InfoEndpointAutoConfiguration.class);
all.add(ThreadDumpEndpointAutoConfiguration.class);
all.add(TraceEndpointAutoConfiguration.class);
- all.add(RequestMappingEndpointAutoConfiguration.class);
+ all.add(MappingsEndpointAutoConfiguration.class);
ALL = all.toArray(new Class>[] {});
}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/RequestMappingEndpointTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/RequestMappingEndpointTests.java
deleted file mode 100644
index 8d6ecb4a76..0000000000
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/RequestMappingEndpointTests.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright 2012-2017 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.boot.actuate.autoconfigure.web.servlet;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
-
-import org.junit.Test;
-
-import org.springframework.boot.actuate.endpoint.EndpointInfo;
-import org.springframework.boot.actuate.endpoint.OperationType;
-import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
-import org.springframework.boot.actuate.endpoint.web.OperationRequestPredicate;
-import org.springframework.boot.actuate.endpoint.web.WebEndpointHttpMethod;
-import org.springframework.boot.actuate.endpoint.web.WebOperation;
-import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
-import org.springframework.boot.endpoint.web.EndpointMapping;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.context.annotation.Scope;
-import org.springframework.context.annotation.ScopedProxyMode;
-import org.springframework.context.support.StaticApplicationContext;
-import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
-import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Tests for {@link RequestMappingEndpoint}.
- *
- * @author Dave Syer
- */
-public class RequestMappingEndpointTests {
-
- private RequestMappingEndpoint endpoint = new RequestMappingEndpoint();
-
- @Test
- public void concreteUrlMappings() {
- SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
- mapping.setUrlMap(Collections.singletonMap("/foo", new Object()));
- mapping.setApplicationContext(new StaticApplicationContext());
- mapping.initApplicationContext();
- this.endpoint.setHandlerMappings(Collections.singletonList(mapping));
- Map result = this.endpoint.mappings();
- assertThat(result).hasSize(1);
- @SuppressWarnings("unchecked")
- Map map = (Map) result.get("/foo");
- assertThat(map.get("type")).isEqualTo("java.lang.Object");
- }
-
- @Test
- public void beanUrlMappings() {
- StaticApplicationContext context = new StaticApplicationContext();
- SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
- mapping.setUrlMap(Collections.singletonMap("/foo", new Object()));
- mapping.setApplicationContext(context);
- mapping.initApplicationContext();
- context.getDefaultListableBeanFactory().registerSingleton("mapping", mapping);
- this.endpoint.setApplicationContext(context);
- Map result = this.endpoint.mappings();
- assertThat(result).hasSize(1);
- @SuppressWarnings("unchecked")
- Map map = (Map) result.get("/foo");
- assertThat(map.get("bean")).isEqualTo("mapping");
- }
-
- @Test
- public void beanUrlMappingsProxy() {
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
- MappingConfiguration.class);
- this.endpoint.setApplicationContext(context);
- Map result = this.endpoint.mappings();
- assertThat(result).hasSize(1);
- @SuppressWarnings("unchecked")
- Map map = (Map) result.get("/foo");
- assertThat(map.get("bean")).isEqualTo("scopedTarget.mapping");
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void beanMethodMappings() {
- StaticApplicationContext context = new StaticApplicationContext();
- context.getDefaultListableBeanFactory().registerSingleton("mapping",
- createHandlerMapping());
- this.endpoint.setApplicationContext(context);
- Map result = this.endpoint.mappings();
- assertThat(result).hasSize(2);
- assertThat(result.keySet()).filteredOn((key) -> key.contains("[/actuator/test]"))
- .hasOnlyOneElementSatisfying(
- (key) -> assertThat((Map) result.get(key))
- .containsOnlyKeys("bean", "method"));
- assertThat(result.keySet()).filteredOn((key) -> key.contains("[/actuator]"))
- .hasOnlyOneElementSatisfying(
- (key) -> assertThat((Map) result.get(key))
- .containsOnlyKeys("bean", "method"));
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void concreteMethodMappings() {
- WebMvcEndpointHandlerMapping mapping = createHandlerMapping();
- this.endpoint.setMethodMappings(Collections.singletonList(mapping));
- Map result = this.endpoint.mappings();
- assertThat(result).hasSize(2);
- assertThat(result.keySet()).filteredOn((key) -> key.contains("[/actuator/test]"))
- .hasOnlyOneElementSatisfying(
- (key) -> assertThat((Map) result.get(key))
- .containsOnlyKeys("method"));
- assertThat(result.keySet()).filteredOn((key) -> key.contains("[/actuator]"))
- .hasOnlyOneElementSatisfying(
- (key) -> assertThat((Map) result.get(key))
- .containsOnlyKeys("method"));
- }
-
- private WebMvcEndpointHandlerMapping createHandlerMapping() {
- OperationRequestPredicate requestPredicate = new OperationRequestPredicate("test",
- WebEndpointHttpMethod.GET, Collections.singletonList("application/json"),
- Collections.singletonList("application/json"));
- WebOperation operation = new WebOperation(OperationType.READ,
- (arguments) -> "Invoked", true, requestPredicate, "test");
- WebMvcEndpointHandlerMapping mapping = new WebMvcEndpointHandlerMapping(
- new EndpointMapping("actuator"),
- Collections.singleton(new EndpointInfo<>("test", true,
- Collections.singleton(operation))),
- new EndpointMediaTypes(Arrays.asList("application/vnd.test+json"),
- Arrays.asList("application/vnd.test+json")));
- mapping.setApplicationContext(new StaticApplicationContext());
- mapping.afterPropertiesSet();
- return mapping;
- }
-
- @Configuration
- protected static class MappingConfiguration {
-
- @Bean
- @Lazy
- @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
- public AbstractUrlHandlerMapping mapping() {
- SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
- mapping.setUrlMap(Collections.singletonMap("/foo", new Object()));
- return mapping;
- }
-
- }
-
-}
diff --git a/spring-boot-project/spring-boot-actuator/pom.xml b/spring-boot-project/spring-boot-actuator/pom.xml
index 9d5e6a65f4..3eacb314c6 100644
--- a/spring-boot-project/spring-boot-actuator/pom.xml
+++ b/spring-boot-project/spring-boot-actuator/pom.xml
@@ -66,6 +66,17 @@
jest
true
+
+ io.undertow
+ undertow-servlet
+ true
+
+
+ org.jboss.spec.javax.servlet
+ jboss-servlet-api_3.1_spec
+
+
+
javax.cache
cache-api
@@ -191,6 +202,11 @@
spring-data-redis
true
+
+ org.springframework.data
+ spring-data-rest-webmvc
+ true
+
org.springframework.data
spring-data-solr
@@ -281,22 +297,6 @@
reactor-netty
test
-
- io.undertow
- undertow-core
- test
-
-
- io.undertow
- undertow-servlet
- test
-
-
- org.jboss.spec.javax.servlet
- jboss-servlet-api_3.1_spec
-
-
-
org.hsqldb
hsqldb
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/MappingDescriptionProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/MappingDescriptionProvider.java
new file mode 100644
index 0000000000..09e2eb074d
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/MappingDescriptionProvider.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web;
+
+import java.util.List;
+
+import org.springframework.context.ApplicationContext;
+
+/**
+ * A {@link MappingDescriptionProvider} provides a {@link List} of mapping descriptions
+ * via implementation-specific introspection of an application context.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+public interface MappingDescriptionProvider {
+
+ /**
+ * Returns the name of the mappings described by this provider.
+ *
+ * @return the name of the mappings
+ */
+ String getMappingName();
+
+ /**
+ * Produce the descriptions of the mappings identified by this provider in the given
+ * {@code context}.
+ * @param context the application context to introspect
+ * @return the mapping descriptions
+ */
+ Object describeMappings(ApplicationContext context);
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/MappingsEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/MappingsEndpoint.java
new file mode 100644
index 0000000000..65e4a4001b
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/MappingsEndpoint.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
+import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * {@link Endpoint} to expose HTTP request mappings.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+@Endpoint(id = "mappings")
+public class MappingsEndpoint {
+
+ private final Collection descriptionProviders;
+
+ private final ApplicationContext context;
+
+ public MappingsEndpoint(Collection descriptionProviders,
+ ApplicationContext context) {
+ this.descriptionProviders = descriptionProviders;
+ this.context = context;
+ }
+
+ @ReadOperation
+ public ApplicationMappings mappings() {
+ ApplicationContext target = this.context;
+ Map contextMappings = new HashMap<>();
+ while (target != null) {
+ contextMappings.put(target.getId(), mappingsForContext(target));
+ target = target.getParent();
+ }
+ return new ApplicationMappings(contextMappings);
+ }
+
+ private ContextMappings mappingsForContext(ApplicationContext applicationContext) {
+ Map mappings = new HashMap<>();
+ this.descriptionProviders
+ .forEach((provider) -> mappings.put(provider.getMappingName(),
+ provider.describeMappings(applicationContext)));
+ return new ContextMappings(mappings, applicationContext.getParent() == null ? null
+ : applicationContext.getId());
+ }
+
+ /**
+ * A description of an application's request mappings. Primarily intended for
+ * serialization to JSON.
+ */
+ public static final class ApplicationMappings {
+
+ private final Map contextMappings;
+
+ private ApplicationMappings(Map contextMappings) {
+ this.contextMappings = contextMappings;
+ }
+
+ public Map getContexts() {
+ return this.contextMappings;
+ }
+
+ }
+
+ /**
+ * A description of an application context's request mappings. Primarily intended for
+ * serialization to JSON.
+ */
+ public static final class ContextMappings {
+
+ private final Map mappings;
+
+ private final String parentId;
+
+ private ContextMappings(Map mappings, String parentId) {
+ this.mappings = mappings;
+ this.parentId = parentId;
+ }
+
+ public String getParentId() {
+ return this.parentId;
+ }
+
+ public Map getMappings() {
+ return this.mappings;
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/reactive/DispatcherHandlerMappingDescription.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/reactive/DispatcherHandlerMappingDescription.java
new file mode 100644
index 0000000000..44316a9b34
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/reactive/DispatcherHandlerMappingDescription.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web.reactive;
+
+import org.springframework.web.servlet.DispatcherServlet;
+
+/**
+ * A description of a mapping known to a {@link DispatcherServlet}.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+public class DispatcherHandlerMappingDescription {
+
+ private final String predicate;
+
+ private final String handler;
+
+ DispatcherHandlerMappingDescription(String predicate, String handler) {
+ this.predicate = predicate;
+ this.handler = handler;
+ }
+
+ public String getHandler() {
+ return this.handler;
+ }
+
+ public String getPredicate() {
+ return this.predicate;
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/reactive/DispatcherHandlersMappingDescriptionProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/reactive/DispatcherHandlersMappingDescriptionProvider.java
new file mode 100644
index 0000000000..3085048f80
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/reactive/DispatcherHandlersMappingDescriptionProvider.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web.reactive;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import reactor.core.publisher.Mono;
+
+import org.springframework.boot.actuate.web.MappingDescriptionProvider;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.io.Resource;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.reactive.DispatcherHandler;
+import org.springframework.web.reactive.HandlerMapping;
+import org.springframework.web.reactive.function.server.HandlerFunction;
+import org.springframework.web.reactive.function.server.RequestPredicate;
+import org.springframework.web.reactive.function.server.RouterFunction;
+import org.springframework.web.reactive.function.server.RouterFunctions.Visitor;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.reactive.function.server.support.RouterFunctionMapping;
+import org.springframework.web.reactive.handler.AbstractUrlHandlerMapping;
+import org.springframework.web.reactive.result.method.RequestMappingInfo;
+import org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping;
+import org.springframework.web.util.pattern.PathPattern;
+
+/**
+ * A {@link MappingDescriptionProvider} that introspects the {@link HandlerMapping
+ * HandlerMappings} that are known to a {@link DispatcherHandler}.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+public class DispatcherHandlersMappingDescriptionProvider
+ implements MappingDescriptionProvider {
+
+ private static final List> descriptionProviders = Arrays
+ .asList(new RequestMappingInfoHandlerMappingDescriptionProvider(),
+ new UrlHandlerMappingDescriptionProvider(),
+ new RouterFunctionMappingDescriptionProvider());
+
+ @Override
+ public String getMappingName() {
+ return "dispatcherHandlers";
+ }
+
+ @Override
+ public Map> describeMappings(
+ ApplicationContext context) {
+ Map> mappings = new HashMap<>();
+ context.getBeansOfType(DispatcherHandler.class).forEach(
+ (name, handler) -> mappings.put(name, describeMappings(handler)));
+ return mappings;
+ }
+
+ private List describeMappings(
+ DispatcherHandler dispatcherHandler) {
+ return dispatcherHandler.getHandlerMappings().stream().flatMap(this::describe)
+ .collect(Collectors.toList());
+ }
+
+ @SuppressWarnings("unchecked")
+ private Stream describe(
+ T handlerMapping) {
+ for (HandlerMappingDescriptionProvider> descriptionProvider : descriptionProviders) {
+ if (descriptionProvider.getMappingClass().isInstance(handlerMapping)) {
+ return ((HandlerMappingDescriptionProvider) descriptionProvider)
+ .describe(handlerMapping).stream();
+
+ }
+ }
+ return Stream.empty();
+ }
+
+ private interface HandlerMappingDescriptionProvider {
+
+ Class getMappingClass();
+
+ List describe(T handlerMapping);
+
+ }
+
+ private static final class RequestMappingInfoHandlerMappingDescriptionProvider
+ implements
+ HandlerMappingDescriptionProvider {
+
+ @Override
+ public Class getMappingClass() {
+ return RequestMappingInfoHandlerMapping.class;
+ }
+
+ @Override
+ public List describe(
+ RequestMappingInfoHandlerMapping handlerMapping) {
+ Map handlerMethods = handlerMapping
+ .getHandlerMethods();
+ return handlerMethods.entrySet().stream().map(this::describe)
+ .collect(Collectors.toList());
+ }
+
+ private DispatcherHandlerMappingDescription describe(
+ Entry mapping) {
+ return new DispatcherHandlerMappingDescription(mapping.getKey().toString(),
+ mapping.getValue().toString());
+ }
+
+ }
+
+ private static final class UrlHandlerMappingDescriptionProvider
+ implements HandlerMappingDescriptionProvider {
+
+ @Override
+ public Class getMappingClass() {
+ return AbstractUrlHandlerMapping.class;
+ }
+
+ @Override
+ public List describe(
+ AbstractUrlHandlerMapping handlerMapping) {
+ return handlerMapping.getHandlerMap().entrySet().stream().map(this::describe)
+ .collect(Collectors.toList());
+ }
+
+ private DispatcherHandlerMappingDescription describe(
+ Entry mapping) {
+ return new DispatcherHandlerMappingDescription(
+ mapping.getKey().getPatternString(), mapping.getValue().toString());
+ }
+
+ }
+
+ private static final class RouterFunctionMappingDescriptionProvider
+ implements HandlerMappingDescriptionProvider {
+
+ @Override
+ public Class getMappingClass() {
+ return RouterFunctionMapping.class;
+ }
+
+ @Override
+ public List describe(
+ RouterFunctionMapping handlerMapping) {
+ MappingDescriptionVisitor visitor = new MappingDescriptionVisitor();
+ RouterFunction> routerFunction = handlerMapping.getRouterFunction();
+ if (routerFunction != null) {
+ routerFunction.accept(visitor);
+ }
+ return visitor.descriptions;
+ }
+
+ }
+
+ private static final class MappingDescriptionVisitor implements Visitor {
+
+ private final List descriptions = new ArrayList<>();
+
+ @Override
+ public void startNested(RequestPredicate predicate) {
+ }
+
+ @Override
+ public void endNested(RequestPredicate predicate) {
+ }
+
+ @Override
+ public void route(RequestPredicate predicate,
+ HandlerFunction> handlerFunction) {
+ this.descriptions.add(new DispatcherHandlerMappingDescription(
+ predicate.toString(), handlerFunction.toString()));
+ }
+
+ @Override
+ public void resources(Function> lookupFunction) {
+ }
+
+ @Override
+ public void unknown(RouterFunction> routerFunction) {
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/DispatcherServletHandlerMappings.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/DispatcherServletHandlerMappings.java
new file mode 100644
index 0000000000..07855073df
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/DispatcherServletHandlerMappings.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web.servlet;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import javax.servlet.ServletException;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.core.StandardWrapper;
+
+import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
+import org.springframework.boot.web.embedded.undertow.UndertowServletWebServer;
+import org.springframework.boot.web.server.WebServer;
+import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.HandlerMapping;
+
+/**
+ * {@code DispatcherServletHandlerMappings} provides access to a {@link DispatcherServlet
+ * DispatcherServlet's} handler mappings, triggering initialization of the dispatcher
+ * servlet if necessary.
+ *
+ * @author Andy Wilkinson
+ */
+final class DispatcherServletHandlerMappings {
+
+ private final String name;
+
+ private final DispatcherServlet dispatcherServlet;
+
+ private final WebApplicationContext applicationContext;
+
+ DispatcherServletHandlerMappings(String name, DispatcherServlet dispatcherServlet,
+ WebApplicationContext applicationContext) {
+ this.name = name;
+ this.dispatcherServlet = dispatcherServlet;
+ this.applicationContext = applicationContext;
+ }
+
+ public List getHandlerMappings() {
+ List handlerMappings = this.dispatcherServlet
+ .getHandlerMappings();
+ if (handlerMappings == null) {
+ initializeDispatcherServletIfPossible();
+ handlerMappings = this.dispatcherServlet.getHandlerMappings();
+ }
+ return handlerMappings == null ? Collections.emptyList() : handlerMappings;
+ }
+
+ private void initializeDispatcherServletIfPossible() {
+ if (!(this.applicationContext instanceof ServletWebServerApplicationContext)) {
+ return;
+ }
+ WebServer webServer = ((ServletWebServerApplicationContext) this.applicationContext)
+ .getWebServer();
+ if (webServer instanceof UndertowServletWebServer) {
+ new UndertowServletInitializer((UndertowServletWebServer) webServer)
+ .initializeServlet(this.name);
+ }
+ else if (webServer instanceof TomcatWebServer) {
+ new TomcatServletInitializer((TomcatWebServer) webServer)
+ .initializeServlet(this.name);
+ }
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ private static final class TomcatServletInitializer {
+
+ private final TomcatWebServer webServer;
+
+ private TomcatServletInitializer(TomcatWebServer webServer) {
+ this.webServer = webServer;
+ }
+
+ void initializeServlet(String name) {
+ findContext().ifPresent((context) -> initializeServlet(context, name));
+ }
+
+ private Optional findContext() {
+ return Stream.of(this.webServer.getTomcat().getHost().findChildren())
+ .filter(Context.class::isInstance).map(Context.class::cast)
+ .findFirst();
+ }
+
+ private void initializeServlet(Context context, String name) {
+ Container child = context.findChild(name);
+ if (child instanceof StandardWrapper) {
+ try {
+ ((StandardWrapper) child).allocate();
+ }
+ catch (ServletException ex) {
+ // Continue
+ }
+ }
+ }
+
+ }
+
+ private static final class UndertowServletInitializer {
+
+ private final UndertowServletWebServer webServer;
+
+ private UndertowServletInitializer(UndertowServletWebServer webServer) {
+ this.webServer = webServer;
+ }
+
+ void initializeServlet(String name) {
+ try {
+ this.webServer.getDeploymentManager().getDeployment().getServlets()
+ .getManagedServlet(name).forceInit();
+ }
+ catch (ServletException ex) {
+ // Continue
+ }
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/DispatcherServletMappingDescription.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/DispatcherServletMappingDescription.java
new file mode 100644
index 0000000000..3084b10fd4
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/DispatcherServletMappingDescription.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web.servlet;
+
+import org.springframework.web.servlet.DispatcherServlet;
+
+/**
+ * A description of a mapping known to a {@link DispatcherServlet}.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+public class DispatcherServletMappingDescription {
+
+ private final String handler;
+
+ private final String predicate;
+
+ /**
+ * Creates a new {@code DispatcherServletMappingDescription} for the given
+ * {@code handler} that will receives requests that match the given {@code predicate}.
+ *
+ * @param predicate the predicate
+ * @param handler the handler
+ */
+ public DispatcherServletMappingDescription(String predicate, String handler) {
+ this.handler = handler;
+ this.predicate = predicate;
+ }
+
+ /**
+ * Returns the handler for the described mapping.
+ * @return the handler
+ */
+ public String getHandler() {
+ return this.handler;
+ }
+
+ /**
+ * Returns the predicate for the described mapping.
+ * @return the predicate
+ */
+ public String getPredicate() {
+ return this.predicate;
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/DispatcherServletsMappingDescriptionProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/DispatcherServletsMappingDescriptionProvider.java
new file mode 100644
index 0000000000..0d59de3c34
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/DispatcherServletsMappingDescriptionProvider.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web.servlet;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.springframework.boot.actuate.web.MappingDescriptionProvider;
+import org.springframework.context.ApplicationContext;
+import org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping;
+import org.springframework.util.ClassUtils;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.HandlerMapping;
+import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
+
+/**
+ * A {@link MappingDescriptionProvider} that introspects the {@link HandlerMapping
+ * HandlerMappings} that are known to one or more {@link DispatcherServlet
+ * DispatcherServlets}.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+public class DispatcherServletsMappingDescriptionProvider
+ implements MappingDescriptionProvider {
+
+ private static final List> descriptionProviders;
+
+ static {
+ List> providers = new ArrayList<>();
+ providers.add(new RequestMappingInfoHandlerMappingDescriptionProvider());
+ providers.add(new UrlHandlerMappingDescriptionProvider());
+ if (ClassUtils.isPresent(
+ "org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping",
+ null)) {
+ providers.add(new DelegatingHandlerMappingDescriptionProvider(
+ new ArrayList<>(providers)));
+ }
+ descriptionProviders = Collections.unmodifiableList(providers);
+ }
+
+ @Override
+ public String getMappingName() {
+ return "dispatcherServlets";
+ }
+
+ @Override
+ public Map> describeMappings(
+ ApplicationContext context) {
+ if (context instanceof WebApplicationContext) {
+ return describeMappings((WebApplicationContext) context);
+ }
+ return Collections.emptyMap();
+ }
+
+ private Map> describeMappings(
+ WebApplicationContext context) {
+ Map> mappings = new HashMap<>();
+ context.getBeansOfType(DispatcherServlet.class)
+ .forEach((name, dispatcherServlet) -> mappings.put(name,
+ describeMappings(new DispatcherServletHandlerMappings(name,
+ dispatcherServlet, context))));
+ return mappings;
+ }
+
+ private List describeMappings(
+ DispatcherServletHandlerMappings mappings) {
+ return mappings.getHandlerMappings().stream().flatMap(this::describe)
+ .collect(Collectors.toList());
+ }
+
+ private Stream describe(
+ T handlerMapping) {
+ return describe(handlerMapping, descriptionProviders).stream();
+ }
+
+ @SuppressWarnings("unchecked")
+ private static List describe(
+ T handlerMapping,
+ List> descriptionProviders) {
+ for (HandlerMappingDescriptionProvider> descriptionProvider : descriptionProviders) {
+ if (descriptionProvider.getMappingClass().isInstance(handlerMapping)) {
+ return ((HandlerMappingDescriptionProvider) descriptionProvider)
+ .describe(handlerMapping);
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ private interface HandlerMappingDescriptionProvider {
+
+ Class getMappingClass();
+
+ List describe(T handlerMapping);
+
+ }
+
+ private static final class RequestMappingInfoHandlerMappingDescriptionProvider
+ implements
+ HandlerMappingDescriptionProvider {
+
+ @Override
+ public Class getMappingClass() {
+ return RequestMappingInfoHandlerMapping.class;
+ }
+
+ @Override
+ public List describe(
+ RequestMappingInfoHandlerMapping handlerMapping) {
+ Map handlerMethods = handlerMapping
+ .getHandlerMethods();
+ return handlerMethods.entrySet().stream().map(this::describe)
+ .collect(Collectors.toList());
+ }
+
+ private DispatcherServletMappingDescription describe(
+ Entry mapping) {
+ return new DispatcherServletMappingDescription(mapping.getKey().toString(),
+ mapping.getValue().toString());
+ }
+
+ }
+
+ private static final class UrlHandlerMappingDescriptionProvider
+ implements HandlerMappingDescriptionProvider {
+
+ @Override
+ public Class getMappingClass() {
+ return AbstractUrlHandlerMapping.class;
+ }
+
+ @Override
+ public List describe(
+ AbstractUrlHandlerMapping handlerMapping) {
+ return handlerMapping.getHandlerMap().entrySet().stream().map(this::describe)
+ .collect(Collectors.toList());
+ }
+
+ private DispatcherServletMappingDescription describe(
+ Entry mapping) {
+ return new DispatcherServletMappingDescription(mapping.getKey().toString(),
+ mapping.getValue().toString());
+ }
+
+ }
+
+ private static final class DelegatingHandlerMappingDescriptionProvider
+ implements HandlerMappingDescriptionProvider {
+
+ private final List> descriptionProviders;
+
+ private DelegatingHandlerMappingDescriptionProvider(
+ List> descriptionProviders) {
+ this.descriptionProviders = descriptionProviders;
+ }
+
+ @Override
+ public Class getMappingClass() {
+ return DelegatingHandlerMapping.class;
+ }
+
+ @Override
+ public List describe(
+ DelegatingHandlerMapping handlerMapping) {
+ List descriptions = new ArrayList<>();
+ for (HandlerMapping delegate : handlerMapping.getDelegates()) {
+ descriptions.addAll(DispatcherServletsMappingDescriptionProvider
+ .describe(delegate, this.descriptionProviders));
+ }
+ return descriptions;
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/FilterRegistrationMappingDescription.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/FilterRegistrationMappingDescription.java
new file mode 100644
index 0000000000..dcd6c0d5f2
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/FilterRegistrationMappingDescription.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web.servlet;
+
+import java.util.Collection;
+
+import javax.servlet.FilterRegistration;
+
+/**
+ * A {@link RegistrationMappingDescription} derived from a {@link FilterRegistration}.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+public class FilterRegistrationMappingDescription
+ extends RegistrationMappingDescription {
+
+ /**
+ * Creates a new {@code FilterRegistrationMappingDescription} derived from the given
+ * {@code filterRegistration}.
+ * @param filterRegistration the filter registration
+ */
+ public FilterRegistrationMappingDescription(FilterRegistration filterRegistration) {
+ super(filterRegistration);
+ }
+
+ /**
+ * Returns the servlet name mappings for the registered filter.
+ *
+ * @return the mappings
+ */
+ public Collection getServletNameMappings() {
+ return this.getRegistration().getServletNameMappings();
+ }
+
+ /**
+ * Returns the URL pattern mappings for the registered filter.
+ *
+ * @return the mappings
+ */
+ public Collection getUrlPatternMappings() {
+ return this.getRegistration().getUrlPatternMappings();
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/FiltersMappingDescriptionProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/FiltersMappingDescriptionProvider.java
new file mode 100644
index 0000000000..83522138b7
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/FiltersMappingDescriptionProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web.servlet;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.servlet.Filter;
+import javax.servlet.ServletContext;
+
+import org.springframework.boot.actuate.web.MappingDescriptionProvider;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.WebApplicationContext;
+
+/**
+ * A {@link MappingDescriptionProvider} that describes that mappings of any {@link Filter
+ * Filters} registered with a {@link ServletContext}.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+public class FiltersMappingDescriptionProvider implements MappingDescriptionProvider {
+
+ @Override
+ public List describeMappings(
+ ApplicationContext context) {
+ if (!(context instanceof WebApplicationContext)) {
+ return Collections.emptyList();
+ }
+ return ((WebApplicationContext) context).getServletContext()
+ .getFilterRegistrations().values().stream()
+ .map(FilterRegistrationMappingDescription::new)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public String getMappingName() {
+ return "servletFilters";
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/RegistrationMappingDescription.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/RegistrationMappingDescription.java
new file mode 100644
index 0000000000..45fb38454a
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/RegistrationMappingDescription.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web.servlet;
+
+import javax.servlet.Registration;
+
+/**
+ * A mapping description derived from a {@link Registration}.
+ *
+ * @param type of the registration
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+public class RegistrationMappingDescription {
+
+ private final T registration;
+
+ /**
+ * Creates a new {@link RegistrationMappingDescription} derived from the given
+ * {@code registration} and with the given {@code predicate}.
+ * @param registration the registration
+ */
+ public RegistrationMappingDescription(T registration) {
+ this.registration = registration;
+ }
+
+ /**
+ * Returns the name of the registered Filter or Servlet.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return this.registration.getName();
+ }
+
+ /**
+ * Returns the class name of the registered Filter or Servlet.
+ *
+ * @return the class name
+ */
+ public String getClassName() {
+ return this.registration.getClassName();
+ }
+
+ /**
+ * Returns the registration that is being described.
+ * @return the registration
+ */
+ protected final T getRegistration() {
+ return this.registration;
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/ServletRegistrationMappingDescription.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/ServletRegistrationMappingDescription.java
new file mode 100644
index 0000000000..6c2a0affd5
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/ServletRegistrationMappingDescription.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web.servlet;
+
+import java.util.Collection;
+
+import javax.servlet.ServletRegistration;
+
+/**
+ * A mapping description derived from a {@link ServletRegistration}.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+public class ServletRegistrationMappingDescription
+ extends RegistrationMappingDescription {
+
+ /**
+ * Creates a new {@code ServletRegistrationMappingDescription} derived from the given
+ * {@code servletRegistration}.
+ * @param servletRegistration the servlet registration
+ */
+ public ServletRegistrationMappingDescription(
+ ServletRegistration servletRegistration) {
+ super(servletRegistration);
+ }
+
+ /**
+ * Returns the mappings for the registered servlet.
+ *
+ * @return the mappings
+ */
+ public Collection getMappings() {
+ return getRegistration().getMappings();
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/ServletsMappingDescriptionProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/ServletsMappingDescriptionProvider.java
new file mode 100644
index 0000000000..adeab11d89
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/servlet/ServletsMappingDescriptionProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web.servlet;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+
+import org.springframework.boot.actuate.web.MappingDescriptionProvider;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.WebApplicationContext;
+
+/**
+ * A {@link MappingDescriptionProvider} that describes that mappings of any {@link Servlet
+ * Servlets} registered with a {@link ServletContext}.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0
+ */
+public class ServletsMappingDescriptionProvider implements MappingDescriptionProvider {
+
+ @Override
+ public List describeMappings(
+ ApplicationContext context) {
+ if (!(context instanceof WebApplicationContext)) {
+ return Collections.emptyList();
+ }
+ return ((WebApplicationContext) context).getServletContext()
+ .getServletRegistrations().values().stream()
+ .map(ServletRegistrationMappingDescription::new)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public String getMappingName() {
+ return "servlets";
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/MappingsEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/MappingsEndpointTests.java
new file mode 100644
index 0000000000..6eb84f0e78
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/MappingsEndpointTests.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.web;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.servlet.FilterRegistration;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+
+import org.junit.Test;
+
+import org.springframework.boot.actuate.web.MappingsEndpoint.ApplicationMappings;
+import org.springframework.boot.actuate.web.MappingsEndpoint.ContextMappings;
+import org.springframework.boot.actuate.web.reactive.DispatcherHandlerMappingDescription;
+import org.springframework.boot.actuate.web.reactive.DispatcherHandlersMappingDescriptionProvider;
+import org.springframework.boot.actuate.web.servlet.DispatcherServletMappingDescription;
+import org.springframework.boot.actuate.web.servlet.DispatcherServletsMappingDescriptionProvider;
+import org.springframework.boot.actuate.web.servlet.FilterRegistrationMappingDescription;
+import org.springframework.boot.actuate.web.servlet.FiltersMappingDescriptionProvider;
+import org.springframework.boot.actuate.web.servlet.ServletRegistrationMappingDescription;
+import org.springframework.boot.actuate.web.servlet.ServletsMappingDescriptionProvider;
+import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
+import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.mock.web.MockServletConfig;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+import org.springframework.web.reactive.config.EnableWebFlux;
+import org.springframework.web.reactive.function.server.RequestPredicates;
+import org.springframework.web.reactive.function.server.RouterFunction;
+import org.springframework.web.reactive.function.server.RouterFunctions;
+import org.springframework.web.reactive.function.server.ServerResponse;
+import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link MappingsEndpoint}.
+ *
+ * @author Andy Wilkinson
+ */
+public class MappingsEndpointTests {
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void servletWebMappings() {
+ ServletContext servletContext = mock(ServletContext.class);
+ given(servletContext.getInitParameterNames())
+ .willReturn(new Vector().elements());
+ given(servletContext.getAttributeNames())
+ .willReturn(new Vector().elements());
+ FilterRegistration filterRegistration = mock(FilterRegistration.class);
+ given((Map) servletContext.getFilterRegistrations())
+ .willReturn(Collections.singletonMap("testFilter", filterRegistration));
+ ServletRegistration servletRegistration = mock(ServletRegistration.class);
+ given((Map) servletContext.getServletRegistrations())
+ .willReturn(Collections.singletonMap("testServlet", servletRegistration));
+ WebApplicationContextRunner runner = new WebApplicationContextRunner(() -> {
+ AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
+ context.setServletContext(servletContext);
+ return context;
+ }).withUserConfiguration(EndpointConfiguration.class,
+ ServletWebConfiguration.class);
+ runner.run((context) -> {
+ ContextMappings contextMappings = contextMappings(context);
+ assertThat(contextMappings.getParentId()).isNull();
+ assertThat(contextMappings.getMappings())
+ .containsOnlyKeys("dispatcherServlets", "servletFilters", "servlets");
+ Map> dispatcherServlets = mappings(
+ contextMappings, "dispatcherServlets");
+ assertThat(dispatcherServlets).containsOnlyKeys("dispatcherServlet");
+ List handlerMappings = dispatcherServlets
+ .get("dispatcherServlet");
+ assertThat(handlerMappings).hasSize(1);
+ List servlets = mappings(
+ contextMappings, "servlets");
+ assertThat(servlets).hasSize(1);
+ List filters = mappings(contextMappings,
+ "servletFilters");
+ assertThat(filters).hasSize(1);
+ });
+ }
+
+ @Test
+ public void reactiveWebMappings() {
+ ReactiveWebApplicationContextRunner runner = new ReactiveWebApplicationContextRunner()
+ .withUserConfiguration(EndpointConfiguration.class,
+ ReactiveWebConfiguration.class);
+ runner.run((context) -> {
+ ContextMappings contextMappings = contextMappings(context);
+ assertThat(contextMappings.getParentId()).isNull();
+ assertThat(contextMappings.getMappings())
+ .containsOnlyKeys("dispatcherHandlers");
+ Map> dispatcherHandlers = mappings(
+ contextMappings, "dispatcherHandlers");
+ assertThat(dispatcherHandlers).containsOnlyKeys("webHandler");
+ List handlerMappings = dispatcherHandlers
+ .get("webHandler");
+ assertThat(handlerMappings).hasSize(3);
+ });
+ }
+
+ private ContextMappings contextMappings(ApplicationContext context) {
+ ApplicationMappings applicationMappings = context.getBean(MappingsEndpoint.class)
+ .mappings();
+ assertThat(applicationMappings.getContexts()).containsOnlyKeys(context.getId());
+ return applicationMappings.getContexts().get(context.getId());
+ }
+
+ @SuppressWarnings("unchecked")
+ private T mappings(ContextMappings contextMappings, String key) {
+ return (T) contextMappings.getMappings().get(key);
+ }
+
+ @Configuration
+ static class EndpointConfiguration {
+
+ @Bean
+ public MappingsEndpoint mappingsEndpoint(
+ Collection descriptionProviders,
+ ApplicationContext context) {
+ return new MappingsEndpoint(descriptionProviders, context);
+ }
+
+ }
+
+ @Configuration
+ @EnableWebFlux
+ @Controller
+ static class ReactiveWebConfiguration {
+
+ @Bean
+ public DispatcherHandlersMappingDescriptionProvider dispatcherHandlersMappingDescriptionProvider() {
+ return new DispatcherHandlersMappingDescriptionProvider();
+ }
+
+ @Bean
+ public RouterFunction routerFunction() {
+ return RouterFunctions
+ .route(RequestPredicates.GET("/one"),
+ (request) -> ServerResponse.ok().build())
+ .andRoute(RequestPredicates.POST("/two"),
+ (request) -> ServerResponse.ok().build());
+ }
+
+ @RequestMapping("/three")
+ public void three() {
+
+ }
+
+ }
+
+ @Configuration
+ @EnableWebMvc
+ @Controller
+ static class ServletWebConfiguration {
+
+ @Bean
+ public DispatcherServletsMappingDescriptionProvider dispatcherServletsMappingDescriptionProvider() {
+ return new DispatcherServletsMappingDescriptionProvider();
+ }
+
+ @Bean
+ public ServletsMappingDescriptionProvider servletsMappingDescriptionProvider() {
+ return new ServletsMappingDescriptionProvider();
+ }
+
+ @Bean
+ public FiltersMappingDescriptionProvider filtersMappingDescriptionProvider() {
+ return new FiltersMappingDescriptionProvider();
+ }
+
+ @Bean
+ public DispatcherServlet dispatcherServlet(WebApplicationContext context)
+ throws ServletException {
+ DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
+ dispatcherServlet.init(new MockServletConfig());
+ return dispatcherServlet;
+ }
+
+ @RequestMapping("/three")
+ public void three() {
+
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java
index ed04430d71..847ede37c5 100644
--- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java
+++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -168,6 +168,12 @@ public class UndertowServletWebServer implements WebServer {
}
}
+ public DeploymentManager getDeploymentManager() {
+ synchronized (this.monitor) {
+ return this.manager;
+ }
+ }
+
private void stopSilently() {
try {
if (this.undertow != null) {