Reduce dependencies of spring-boot-actuator
This commit is contained in:
committed by
Phillip Webb
parent
999002119c
commit
25bb313d91
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user