Reduce dependencies of spring-boot-actuator

This commit is contained in:
Andy Wilkinson
2025-05-21 14:39:59 +01:00
committed by Phillip Webb
parent 999002119c
commit 25bb313d91
65 changed files with 16356 additions and 82 deletions

View File

@@ -0,0 +1,145 @@
/*
* Copyright 2012-2025 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
*
* https://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.webmvc.actuate.mappings;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import jakarta.servlet.ServletException;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.core.StandardWrapper;
import org.springframework.boot.tomcat.TomcatWebServer;
import org.springframework.boot.undertow.servlet.UndertowServletWebServer;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;
import org.springframework.util.ClassUtils;
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 static final boolean TOMCAT_WEB_SERVER_PRESENT = ClassUtils.isPresent(
"org.springframework.boot.tomcat.TomcatWebServer", DispatcherServletHandlerMappings.class.getClassLoader());
private static final boolean UNDERTOW_WEB_SERVER_PRESENT = ClassUtils.isPresent(
"org.springframework.boot.undertow.UndertowWebServer",
DispatcherServletHandlerMappings.class.getClassLoader());
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;
}
List<HandlerMapping> getHandlerMappings() {
List<HandlerMapping> handlerMappings = this.dispatcherServlet.getHandlerMappings();
if (handlerMappings == null) {
initializeDispatcherServletIfPossible();
handlerMappings = this.dispatcherServlet.getHandlerMappings();
}
return (handlerMappings != null) ? handlerMappings : Collections.emptyList();
}
private void initializeDispatcherServletIfPossible() {
if (!(this.applicationContext instanceof ServletWebServerApplicationContext webServerApplicationContext)) {
return;
}
WebServer webServer = webServerApplicationContext.getWebServer();
if (UNDERTOW_WEB_SERVER_PRESENT && webServer instanceof UndertowServletWebServer undertowServletWebServer) {
new UndertowServletInitializer(undertowServletWebServer).initializeServlet(this.name);
}
else if (TOMCAT_WEB_SERVER_PRESENT && webServer instanceof TomcatWebServer tomcatWebServer) {
new TomcatServletInitializer(tomcatWebServer).initializeServlet(this.name);
}
}
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<Context> 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 wrapper) {
try {
wrapper.deallocate(wrapper.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
}
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2012-2019 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
*
* https://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.webmvc.actuate.mappings;
import org.springframework.web.servlet.DispatcherServlet;
/**
* A description of a mapping known to a {@link DispatcherServlet}.
*
* @author Andy Wilkinson
* @since 4.0.0
*/
public class DispatcherServletMappingDescription {
private final String handler;
private final String predicate;
private final DispatcherServletMappingDetails details;
DispatcherServletMappingDescription(String predicate, String handler, DispatcherServletMappingDetails details) {
this.handler = handler;
this.predicate = predicate;
this.details = details;
}
public String getHandler() {
return this.handler;
}
public String getPredicate() {
return this.predicate;
}
public DispatcherServletMappingDetails getDetails() {
return this.details;
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2012-2025 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
*
* https://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.webmvc.actuate.mappings;
import org.springframework.boot.actuate.web.mappings.HandlerMethodDescription;
import org.springframework.web.servlet.DispatcherServlet;
/**
* Details of a {@link DispatcherServlet} mapping.
*
* @author Andy Wilkinson
* @author Xiong Tang
* @since 4.0.0
*/
public class DispatcherServletMappingDetails {
private HandlerMethodDescription handlerMethod;
private HandlerFunctionDescription handlerFunction;
private RequestMappingConditionsDescription requestMappingConditions;
public HandlerMethodDescription getHandlerMethod() {
return this.handlerMethod;
}
void setHandlerMethod(HandlerMethodDescription handlerMethod) {
this.handlerMethod = handlerMethod;
}
public HandlerFunctionDescription getHandlerFunction() {
return this.handlerFunction;
}
void setHandlerFunction(HandlerFunctionDescription handlerFunction) {
this.handlerFunction = handlerFunction;
}
public RequestMappingConditionsDescription getRequestMappingConditions() {
return this.requestMappingConditions;
}
void setRequestMappingConditions(RequestMappingConditionsDescription requestMappingConditions) {
this.requestMappingConditions = requestMappingConditions;
}
}

View File

@@ -0,0 +1,282 @@
/*
* Copyright 2012-2025 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
*
* https://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.webmvc.actuate.mappings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;
import jakarta.servlet.Servlet;
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.actuate.web.mappings.HandlerMethodDescription;
import org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.webmvc.actuate.mappings.DispatcherServletsMappingDescriptionProvider.DispatcherServletsMappingDescriptionProviderRuntimeHints;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.core.io.Resource;
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.function.HandlerFunction;
import org.springframework.web.servlet.function.RequestPredicate;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.RouterFunctions.Visitor;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.support.RouterFunctionMapping;
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
* @author Stephane Nicoll
* @author Xiong Tang
* @since 4.0.0
*/
@ImportRuntimeHints(DispatcherServletsMappingDescriptionProviderRuntimeHints.class)
public class DispatcherServletsMappingDescriptionProvider implements MappingDescriptionProvider {
private static final List<HandlerMappingDescriptionProvider<?>> descriptionProviders;
static {
List<HandlerMappingDescriptionProvider<?>> providers = new ArrayList<>();
providers.add(new RequestMappingInfoHandlerMappingDescriptionProvider());
providers.add(new UrlHandlerMappingDescriptionProvider());
providers.add(new IterableDelegatesHandlerMappingDescriptionProvider(new ArrayList<>(providers)));
providers.add(new RouterFunctionMappingDescriptionProvider());
descriptionProviders = Collections.unmodifiableList(providers);
}
@Override
public String getMappingName() {
return "dispatcherServlets";
}
@Override
public Map<String, List<DispatcherServletMappingDescription>> describeMappings(ApplicationContext context) {
if (context instanceof WebApplicationContext webApplicationContext) {
return describeMappings(webApplicationContext);
}
return Collections.emptyMap();
}
private Map<String, List<DispatcherServletMappingDescription>> describeMappings(WebApplicationContext context) {
Map<String, List<DispatcherServletMappingDescription>> mappings = new HashMap<>();
determineDispatcherServlets(context).forEach((name, dispatcherServlet) -> mappings.put(name,
describeMappings(new DispatcherServletHandlerMappings(name, dispatcherServlet, context))));
return mappings;
}
private Map<String, DispatcherServlet> determineDispatcherServlets(WebApplicationContext context) {
Map<String, DispatcherServlet> dispatcherServlets = new LinkedHashMap<>();
context.getBeansOfType(ServletRegistrationBean.class).values().forEach((registration) -> {
Servlet servlet = registration.getServlet();
if (servlet instanceof DispatcherServlet && !dispatcherServlets.containsValue(servlet)) {
dispatcherServlets.put(registration.getServletName(), (DispatcherServlet) servlet);
}
});
context.getBeansOfType(DispatcherServlet.class).forEach((name, dispatcherServlet) -> {
if (!dispatcherServlets.containsValue(dispatcherServlet)) {
dispatcherServlets.put(name, dispatcherServlet);
}
});
return dispatcherServlets;
}
private List<DispatcherServletMappingDescription> describeMappings(DispatcherServletHandlerMappings mappings) {
return mappings.getHandlerMappings().stream().flatMap(this::describe).toList();
}
private <T> Stream<DispatcherServletMappingDescription> describe(T handlerMapping) {
return describe(handlerMapping, descriptionProviders).stream();
}
@SuppressWarnings("unchecked")
private static <T> List<DispatcherServletMappingDescription> describe(T handlerMapping,
List<HandlerMappingDescriptionProvider<?>> descriptionProviders) {
for (HandlerMappingDescriptionProvider<?> descriptionProvider : descriptionProviders) {
if (descriptionProvider.getMappingClass().isInstance(handlerMapping)) {
return ((HandlerMappingDescriptionProvider<T>) descriptionProvider).describe(handlerMapping);
}
}
return Collections.emptyList();
}
private interface HandlerMappingDescriptionProvider<T> {
Class<T> getMappingClass();
List<DispatcherServletMappingDescription> describe(T handlerMapping);
}
private static final class RequestMappingInfoHandlerMappingDescriptionProvider
implements HandlerMappingDescriptionProvider<RequestMappingInfoHandlerMapping> {
@Override
public Class<RequestMappingInfoHandlerMapping> getMappingClass() {
return RequestMappingInfoHandlerMapping.class;
}
@Override
public List<DispatcherServletMappingDescription> describe(RequestMappingInfoHandlerMapping handlerMapping) {
Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();
return handlerMethods.entrySet().stream().map(this::describe).toList();
}
private DispatcherServletMappingDescription describe(Entry<RequestMappingInfo, HandlerMethod> mapping) {
DispatcherServletMappingDetails mappingDetails = new DispatcherServletMappingDetails();
mappingDetails.setHandlerMethod(new HandlerMethodDescription(mapping.getValue()));
mappingDetails.setRequestMappingConditions(new RequestMappingConditionsDescription(mapping.getKey()));
return new DispatcherServletMappingDescription(mapping.getKey().toString(), mapping.getValue().toString(),
mappingDetails);
}
}
private static final class UrlHandlerMappingDescriptionProvider
implements HandlerMappingDescriptionProvider<AbstractUrlHandlerMapping> {
@Override
public Class<AbstractUrlHandlerMapping> getMappingClass() {
return AbstractUrlHandlerMapping.class;
}
@Override
public List<DispatcherServletMappingDescription> describe(AbstractUrlHandlerMapping handlerMapping) {
return handlerMapping.getHandlerMap().entrySet().stream().map(this::describe).toList();
}
private DispatcherServletMappingDescription describe(Entry<String, Object> mapping) {
return new DispatcherServletMappingDescription(mapping.getKey(), mapping.getValue().toString(), null);
}
}
@SuppressWarnings("rawtypes")
private static final class IterableDelegatesHandlerMappingDescriptionProvider
implements HandlerMappingDescriptionProvider<Iterable> {
private final List<HandlerMappingDescriptionProvider<?>> descriptionProviders;
private IterableDelegatesHandlerMappingDescriptionProvider(
List<HandlerMappingDescriptionProvider<?>> descriptionProviders) {
this.descriptionProviders = descriptionProviders;
}
@Override
public Class<Iterable> getMappingClass() {
return Iterable.class;
}
@Override
public List<DispatcherServletMappingDescription> describe(Iterable handlerMapping) {
List<DispatcherServletMappingDescription> descriptions = new ArrayList<>();
for (Object delegate : handlerMapping) {
descriptions
.addAll(DispatcherServletsMappingDescriptionProvider.describe(delegate, this.descriptionProviders));
}
return descriptions;
}
}
private static final class RouterFunctionMappingDescriptionProvider
implements HandlerMappingDescriptionProvider<RouterFunctionMapping> {
@Override
public Class<RouterFunctionMapping> getMappingClass() {
return RouterFunctionMapping.class;
}
@Override
public List<DispatcherServletMappingDescription> 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<DispatcherServletMappingDescription> descriptions = new ArrayList<>();
@Override
public void startNested(RequestPredicate predicate) {
}
@Override
public void endNested(RequestPredicate predicate) {
}
@Override
public void route(RequestPredicate predicate, HandlerFunction<?> handlerFunction) {
DispatcherServletMappingDetails details = new DispatcherServletMappingDetails();
details.setHandlerFunction(new HandlerFunctionDescription(handlerFunction));
this.descriptions.add(
new DispatcherServletMappingDescription(predicate.toString(), handlerFunction.toString(), details));
}
@Override
public void resources(Function<ServerRequest, Optional<Resource>> lookupFunction) {
}
@Override
public void attributes(Map<String, Object> attributes) {
}
@Override
public void unknown(RouterFunction<?> routerFunction) {
}
}
static class DispatcherServletsMappingDescriptionProviderRuntimeHints implements RuntimeHintsRegistrar {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
this.bindingRegistrar.registerReflectionHints(hints.reflection(),
DispatcherServletMappingDescription.class);
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2012-2025 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
*
* https://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.webmvc.actuate.mappings;
import org.springframework.web.servlet.function.HandlerFunction;
/**
* Description of a {@link HandlerFunction}.
*
* @author Xiong Tang
* @since 4.0.0
*/
public class HandlerFunctionDescription {
private final String className;
HandlerFunctionDescription(HandlerFunction<?> handlerFunction) {
this.className = getHandlerFunctionClassName(handlerFunction);
}
private static String getHandlerFunctionClassName(HandlerFunction<?> handlerFunction) {
Class<?> functionClass = handlerFunction.getClass();
String canonicalName = functionClass.getCanonicalName();
return (canonicalName != null) ? canonicalName : functionClass.getName();
}
public String getClassName() {
return this.className;
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright 2012-2025 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
*
* https://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.webmvc.actuate.mappings;
import java.util.List;
import java.util.Set;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.condition.MediaTypeExpression;
import org.springframework.web.servlet.mvc.condition.NameValueExpression;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
/**
* Description of the conditions of a {@link RequestMappingInfo}.
*
* @author Andy Wilkinson
* @since 4.0.0
*/
public class RequestMappingConditionsDescription {
private final List<MediaTypeExpressionDescription> consumes;
private final List<NameValueExpressionDescription> headers;
private final Set<RequestMethod> methods;
private final List<NameValueExpressionDescription> params;
private final Set<String> patterns;
private final List<MediaTypeExpressionDescription> produces;
RequestMappingConditionsDescription(RequestMappingInfo requestMapping) {
this.consumes = requestMapping.getConsumesCondition()
.getExpressions()
.stream()
.map(MediaTypeExpressionDescription::new)
.toList();
this.headers = requestMapping.getHeadersCondition()
.getExpressions()
.stream()
.map(NameValueExpressionDescription::new)
.toList();
this.methods = requestMapping.getMethodsCondition().getMethods();
this.params = requestMapping.getParamsCondition()
.getExpressions()
.stream()
.map(NameValueExpressionDescription::new)
.toList();
this.patterns = extractPathPatterns(requestMapping);
this.produces = requestMapping.getProducesCondition()
.getExpressions()
.stream()
.map(MediaTypeExpressionDescription::new)
.toList();
}
@SuppressWarnings({ "removal", "deprecation" })
private Set<String> extractPathPatterns(RequestMappingInfo requestMapping) {
org.springframework.web.servlet.mvc.condition.PatternsRequestCondition patternsCondition = requestMapping
.getPatternsCondition();
return (patternsCondition != null) ? patternsCondition.getPatterns()
: requestMapping.getPathPatternsCondition().getPatternValues();
}
public List<MediaTypeExpressionDescription> getConsumes() {
return this.consumes;
}
public List<NameValueExpressionDescription> getHeaders() {
return this.headers;
}
public Set<RequestMethod> getMethods() {
return this.methods;
}
public List<NameValueExpressionDescription> getParams() {
return this.params;
}
public Set<String> getPatterns() {
return this.patterns;
}
public List<MediaTypeExpressionDescription> getProduces() {
return this.produces;
}
/**
* A description of a {@link MediaTypeExpression} in a request mapping condition.
*/
public static class MediaTypeExpressionDescription {
private final String mediaType;
private final boolean negated;
MediaTypeExpressionDescription(MediaTypeExpression expression) {
this.mediaType = expression.getMediaType().toString();
this.negated = expression.isNegated();
}
public String getMediaType() {
return this.mediaType;
}
public boolean isNegated() {
return this.negated;
}
}
/**
* A description of a {@link NameValueExpression} in a request mapping condition.
*/
public static class NameValueExpressionDescription {
private final String name;
private final Object value;
private final boolean negated;
NameValueExpressionDescription(NameValueExpression<?> expression) {
this.name = expression.getName();
this.value = expression.getValue();
this.negated = expression.isNegated();
}
public String getName() {
return this.name;
}
public Object getValue() {
return this.value;
}
public boolean isNegated() {
return this.negated;
}
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2019 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
*
* https://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.
*/
/**
* Actuator request mappings support for Spring MVC.
*/
package org.springframework.boot.webmvc.actuate.mappings;

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2012-2025 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
*
* https://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.webmvc.actuate.mappings;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.boot.webmvc.actuate.mappings.DispatcherServletsMappingDescriptionProvider.DispatcherServletsMappingDescriptionProviderRuntimeHints;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DispatcherServletsMappingDescriptionProvider}.
*
* @author Moritz Halbritter
*/
class DispatcherServletsMappingDescriptionProviderTests {
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new DispatcherServletsMappingDescriptionProviderRuntimeHints().registerHints(runtimeHints,
getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection()
.onType(DispatcherServletMappingDescription.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);
}
}