mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Guard against WebServerApplicationContext not being present
Update security matchers and WebFlux actuator support to guard against the `WebServerApplicationContext` class not being present. Fixes gh-48388
This commit is contained in:
@@ -27,6 +27,7 @@ description = "Spring Boot Actuator"
|
||||
dependencies {
|
||||
api(project(":core:spring-boot"))
|
||||
|
||||
optional(project(":module:spring-boot-web-server"))
|
||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||
optional("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
|
||||
optional("com.github.ben-manes.caffeine:caffeine")
|
||||
|
||||
+20
@@ -18,6 +18,9 @@ package org.springframework.boot.actuate.endpoint.web;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.web.server.context.WebServerApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -30,6 +33,8 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public final class WebServerNamespace {
|
||||
|
||||
private static final String WEB_SERVER_CONTEXT_CLASS = "org.springframework.boot.web.server.context.WebServerApplicationContext";
|
||||
|
||||
/**
|
||||
* {@link WebServerNamespace} that represents the main server.
|
||||
*/
|
||||
@@ -76,6 +81,21 @@ public final class WebServerNamespace {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link WebServerNamespace} from a value. If the
|
||||
* context is {@code null} or not a web server context then {@link #SERVER} is
|
||||
* returned.
|
||||
* @param context the application context
|
||||
* @return the web server namespace
|
||||
* @since 4.0.1
|
||||
*/
|
||||
public static WebServerNamespace from(@Nullable ApplicationContext context) {
|
||||
if (!ClassUtils.isPresent(WEB_SERVER_CONTEXT_CLASS, null)) {
|
||||
return SERVER;
|
||||
}
|
||||
return from(WebServerApplicationContext.getServerNamespace(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link WebServerNamespace} from a value. If the
|
||||
* value is empty or {@code null} then {@link #SERVER} is returned.
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ class WebServerNamespaceTests {
|
||||
|
||||
@Test
|
||||
void fromWhenValueIsNull() {
|
||||
assertThat(WebServerNamespace.from(null)).isEqualTo(WebServerNamespace.SERVER);
|
||||
assertThat(WebServerNamespace.from((String) null)).isEqualTo(WebServerNamespace.SERVER);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+2
-3
@@ -38,7 +38,6 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.security.web.reactive.ApplicationContextServerWebExchangeMatcher;
|
||||
import org.springframework.boot.web.server.context.WebServerApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
@@ -221,14 +220,14 @@ public final class EndpointRequest {
|
||||
|
||||
protected final boolean hasWebServerNamespace(@Nullable ApplicationContext applicationContext,
|
||||
WebServerNamespace webServerNamespace) {
|
||||
return WebServerApplicationContext.hasServerNamespace(applicationContext, webServerNamespace.getValue())
|
||||
return hasServerNamespace(applicationContext, webServerNamespace.getValue())
|
||||
|| hasImplicitServerNamespace(applicationContext, webServerNamespace);
|
||||
}
|
||||
|
||||
private boolean hasImplicitServerNamespace(@Nullable ApplicationContext applicationContext,
|
||||
WebServerNamespace webServerNamespace) {
|
||||
return WebServerNamespace.SERVER.equals(webServerNamespace)
|
||||
&& WebServerApplicationContext.getServerNamespace(applicationContext) == null
|
||||
&& getServerNamespace(applicationContext) == null
|
||||
&& getApplicationContextParent(applicationContext) == null;
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -38,7 +38,6 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.security.web.servlet.ApplicationContextRequestMatcher;
|
||||
import org.springframework.boot.web.server.context.WebServerApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
@@ -183,15 +182,14 @@ public final class EndpointRequest {
|
||||
|
||||
protected final boolean hasWebServerNamespace(ApplicationContext applicationContext,
|
||||
WebServerNamespace webServerNamespace) {
|
||||
return WebServerApplicationContext.hasServerNamespace(applicationContext, webServerNamespace.getValue())
|
||||
return hasServerNamespace(applicationContext, webServerNamespace.getValue())
|
||||
|| hasImplicitServerNamespace(applicationContext, webServerNamespace);
|
||||
}
|
||||
|
||||
private boolean hasImplicitServerNamespace(ApplicationContext applicationContext,
|
||||
WebServerNamespace webServerNamespace) {
|
||||
return WebServerNamespace.SERVER.equals(webServerNamespace)
|
||||
&& WebServerApplicationContext.getServerNamespace(applicationContext) == null
|
||||
&& applicationContext.getParent() == null;
|
||||
&& getServerNamespace(applicationContext) == null && applicationContext.getParent() == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-2
@@ -24,7 +24,6 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.boot.h2console.autoconfigure.H2ConsoleProperties;
|
||||
import org.springframework.boot.security.autoconfigure.web.StaticResourceLocation;
|
||||
import org.springframework.boot.security.web.servlet.ApplicationContextRequestMatcher;
|
||||
import org.springframework.boot.web.server.context.WebServerApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
@@ -76,7 +75,7 @@ public final class PathRequest {
|
||||
|
||||
@Override
|
||||
protected boolean ignoreApplicationContext(WebApplicationContext applicationContext) {
|
||||
return WebServerApplicationContext.hasServerNamespace(applicationContext, "management");
|
||||
return hasServerNamespace(applicationContext, "management");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-2
@@ -27,7 +27,6 @@ import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.security.autoconfigure.web.StaticResourceLocation;
|
||||
import org.springframework.boot.security.web.servlet.ApplicationContextRequestMatcher;
|
||||
import org.springframework.boot.web.server.context.WebServerApplicationContext;
|
||||
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
@@ -148,7 +147,7 @@ public final class StaticResourceRequest {
|
||||
|
||||
@Override
|
||||
protected boolean ignoreApplicationContext(WebApplicationContext applicationContext) {
|
||||
return WebServerApplicationContext.hasServerNamespace(applicationContext, "management");
|
||||
return hasServerNamespace(applicationContext, "management");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+34
@@ -22,9 +22,11 @@ import org.jspecify.annotations.Nullable;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.boot.web.server.context.WebServerApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
@@ -41,6 +43,8 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
*/
|
||||
public abstract class ApplicationContextServerWebExchangeMatcher<C> implements ServerWebExchangeMatcher {
|
||||
|
||||
private static final String WEB_SERVER_CONTEXT_CLASS = "org.springframework.boot.web.server.context.WebServerApplicationContext";
|
||||
|
||||
private final Class<? extends C> contextClass;
|
||||
|
||||
private volatile @Nullable Supplier<C> context;
|
||||
@@ -111,4 +115,34 @@ public abstract class ApplicationContextServerWebExchangeMatcher<C> implements S
|
||||
return () -> context.getBean(this.contextClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the specified context is a
|
||||
* {@link WebServerApplicationContext} with a matching server namespace.
|
||||
* @param context the context to check
|
||||
* @param serverNamespace the server namespace to match against
|
||||
* @return {@code true} if the server namespace of the context matches
|
||||
* @since 4.0.1
|
||||
*/
|
||||
protected final boolean hasServerNamespace(@Nullable ApplicationContext context, String serverNamespace) {
|
||||
if (!ClassUtils.isPresent(WEB_SERVER_CONTEXT_CLASS, null)) {
|
||||
return false;
|
||||
}
|
||||
return WebServerApplicationContext.hasServerNamespace(context, serverNamespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server namespace if the specified context is a
|
||||
* {@link WebServerApplicationContext}.
|
||||
* @param context the context
|
||||
* @return the server namespace or {@code null} if the context is not a
|
||||
* {@link WebServerApplicationContext}
|
||||
* @since 4.0.1
|
||||
*/
|
||||
protected final @Nullable String getServerNamespace(@Nullable ApplicationContext context) {
|
||||
if (!ClassUtils.isPresent(WEB_SERVER_CONTEXT_CLASS, null)) {
|
||||
return null;
|
||||
}
|
||||
return WebServerApplicationContext.getServerNamespace(context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+35
@@ -19,11 +19,14 @@ package org.springframework.boot.security.web.servlet;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.boot.web.server.context.WebServerApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
@@ -41,6 +44,8 @@ import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
*/
|
||||
public abstract class ApplicationContextRequestMatcher<C> implements RequestMatcher {
|
||||
|
||||
private static final String WEB_SERVER_CONTEXT_CLASS = "org.springframework.boot.web.server.context.WebServerApplicationContext";
|
||||
|
||||
private final Class<? extends C> contextClass;
|
||||
|
||||
private volatile boolean initialized;
|
||||
@@ -110,4 +115,34 @@ public abstract class ApplicationContextRequestMatcher<C> implements RequestMatc
|
||||
*/
|
||||
protected abstract boolean matches(HttpServletRequest request, Supplier<C> context);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the specified context is a
|
||||
* {@link WebServerApplicationContext} with a matching server namespace.
|
||||
* @param context the context to check
|
||||
* @param serverNamespace the server namespace to match against
|
||||
* @return {@code true} if the server namespace of the context matches
|
||||
* @since 4.0.1
|
||||
*/
|
||||
protected final boolean hasServerNamespace(@Nullable ApplicationContext context, String serverNamespace) {
|
||||
if (!ClassUtils.isPresent(WEB_SERVER_CONTEXT_CLASS, null)) {
|
||||
return false;
|
||||
}
|
||||
return WebServerApplicationContext.hasServerNamespace(context, serverNamespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server namespace if the specified context is a
|
||||
* {@link WebServerApplicationContext}.
|
||||
* @param context the context
|
||||
* @return the server namespace or {@code null} if the context is not a
|
||||
* {@link WebServerApplicationContext}
|
||||
* @since 4.0.1
|
||||
*/
|
||||
protected final @Nullable String getServerNamespace(@Nullable ApplicationContext context) {
|
||||
if (!ClassUtils.isPresent(WEB_SERVER_CONTEXT_CLASS, null)) {
|
||||
return null;
|
||||
}
|
||||
return WebServerApplicationContext.getServerNamespace(context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+26
-4
@@ -22,14 +22,19 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.h2console.autoconfigure.H2ConsoleProperties;
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
|
||||
import org.springframework.boot.web.server.context.WebServerApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link PathRequest}.
|
||||
@@ -59,14 +64,31 @@ class PathRequestTests {
|
||||
assertMatcher(matcher, "management").doesNotMatch("/js/file.js");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ClassPathExclusions(packages = "org.springframework.boot.web.server.context")
|
||||
void toH2ConsoleWhenNoWebServerContextClassPresent() {
|
||||
assertThatExceptionOfType(NoClassDefFoundError.class)
|
||||
.isThrownBy(() -> WebServerApplicationContext.class.getName());
|
||||
RequestMatcher matcher = PathRequest.toH2Console();
|
||||
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
||||
assertMatcher(matcher, context).matches("/h2-console");
|
||||
assertMatcher(matcher, context).matches("/h2-console/subpath");
|
||||
assertMatcher(matcher, context).doesNotMatch("/js/file.js");
|
||||
}
|
||||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher) {
|
||||
return assertMatcher(matcher, null);
|
||||
return assertMatcher(matcher, (String) null);
|
||||
}
|
||||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, @Nullable String serverNamespace) {
|
||||
TestWebApplicationContext context = new TestWebApplicationContext(serverNamespace);
|
||||
context.registerBean(ServerProperties.class);
|
||||
context.registerBean(H2ConsoleProperties.class);
|
||||
StaticWebApplicationContext context = new TestWebApplicationContext(serverNamespace);
|
||||
return assertMatcher(matcher, context);
|
||||
}
|
||||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, WebApplicationContext context) {
|
||||
GenericApplicationContext genericContext = (GenericApplicationContext) context;
|
||||
genericContext.registerBean(ServerProperties.class);
|
||||
genericContext.registerBean(H2ConsoleProperties.class);
|
||||
return assertThat(new RequestMatcherAssert(context, matcher));
|
||||
}
|
||||
|
||||
|
||||
+23
-9
@@ -52,6 +52,7 @@ import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicat
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.web.server.context.WebServerApplicationContext;
|
||||
import org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping.AbstractWebFluxEndpointHandlerMappingRuntimeHints;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -372,19 +373,32 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
|
||||
|
||||
@Override
|
||||
public Mono<ResponseEntity<Object>> handle(ServerWebExchange exchange, @Nullable Map<String, String> body) {
|
||||
Map<String, Object> arguments = getArguments(exchange, body);
|
||||
OperationArgumentResolver serverNamespaceArgumentResolver = OperationArgumentResolver
|
||||
.of(WebServerNamespace.class, () -> WebServerNamespace
|
||||
.from(WebServerApplicationContext.getServerNamespace(exchange.getApplicationContext())));
|
||||
return this.securityContextSupplier.get()
|
||||
.map((securityContext) -> new InvocationContext(securityContext, arguments,
|
||||
serverNamespaceArgumentResolver,
|
||||
new ProducibleOperationArgumentResolver(
|
||||
() -> exchange.getRequest().getHeaders().get("Accept"))))
|
||||
.flatMap((invocationContext) -> handleResult((Publisher<?>) this.invoker.invoke(invocationContext),
|
||||
.map((securityContext) -> getInvocationContext(securityContext, exchange, body))
|
||||
.flatMap((invocationContext) -> handleResult(invoke(invocationContext),
|
||||
exchange.getRequest().getMethod()));
|
||||
}
|
||||
|
||||
private InvocationContext getInvocationContext(SecurityContext securityContext, ServerWebExchange exchange,
|
||||
@Nullable Map<String, String> body) {
|
||||
Map<String, Object> arguments = getArguments(exchange, body);
|
||||
OperationArgumentResolver serverNamespaceResolver = OperationArgumentResolver.of(WebServerNamespace.class,
|
||||
() -> getServerNamespace(exchange));
|
||||
OperationArgumentResolver producibleOperationResolver = new ProducibleOperationArgumentResolver(
|
||||
() -> exchange.getRequest().getHeaders().get("Accept"));
|
||||
return new InvocationContext(securityContext, arguments, serverNamespaceResolver,
|
||||
producibleOperationResolver);
|
||||
}
|
||||
|
||||
private WebServerNamespace getServerNamespace(ServerWebExchange exchange) {
|
||||
ApplicationContext context = exchange.getApplicationContext();
|
||||
return WebServerNamespace.from(WebServerApplicationContext.getServerNamespace(context));
|
||||
}
|
||||
|
||||
private @Nullable Publisher<?> invoke(InvocationContext invocationContext) {
|
||||
return (@Nullable Publisher<?>) this.invoker.invoke(invocationContext);
|
||||
}
|
||||
|
||||
private Map<String, Object> getArguments(ServerWebExchange exchange, @Nullable Map<String, String> body) {
|
||||
Map<String, Object> arguments = new LinkedHashMap<>(getTemplateVariables(exchange));
|
||||
String matchAllRemainingPathSegmentsVariable = this.operation.getRequestPredicate()
|
||||
|
||||
+16
-15
@@ -51,7 +51,6 @@ import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.web.server.context.WebServerApplicationContext;
|
||||
import org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping.AbstractWebMvcEndpointHandlerMappingRuntimeHints;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@@ -323,13 +322,9 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
public @Nullable Object handle(HttpServletRequest request,
|
||||
@RequestBody(required = false) @Nullable Map<String, String> body) {
|
||||
HttpHeaders headers = new ServletServerHttpRequest(request).getHeaders();
|
||||
Map<String, Object> arguments = getArguments(request, body);
|
||||
try {
|
||||
ServletSecurityContext securityContext = new ServletSecurityContext(request);
|
||||
ProducibleOperationArgumentResolver producibleOperationArgumentResolver = new ProducibleOperationArgumentResolver(
|
||||
() -> headers.get("Accept"));
|
||||
InvocationContext invocationContext = new InvocationContext(securityContext, arguments,
|
||||
serverNamespaceArgumentResolver(request), producibleOperationArgumentResolver);
|
||||
InvocationContext invocationContext = getInvocationContext(request, body, headers, securityContext);
|
||||
return handleResult(this.operation.invoke(invocationContext), HttpMethod.valueOf(request.getMethod()));
|
||||
}
|
||||
catch (InvalidEndpointRequestException ex) {
|
||||
@@ -337,15 +332,21 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
}
|
||||
}
|
||||
|
||||
private OperationArgumentResolver serverNamespaceArgumentResolver(HttpServletRequest request) {
|
||||
if (ClassUtils.isPresent("org.springframework.boot.web.server.context.WebServerApplicationContext", null)) {
|
||||
return OperationArgumentResolver.of(WebServerNamespace.class, () -> {
|
||||
WebApplicationContext applicationContext = WebApplicationContextUtils
|
||||
.getRequiredWebApplicationContext(request.getServletContext());
|
||||
return WebServerNamespace.from(WebServerApplicationContext.getServerNamespace(applicationContext));
|
||||
});
|
||||
}
|
||||
return OperationArgumentResolver.of(WebServerNamespace.class, () -> null);
|
||||
private InvocationContext getInvocationContext(HttpServletRequest request, @Nullable Map<String, String> body,
|
||||
HttpHeaders headers, ServletSecurityContext securityContext) {
|
||||
Map<String, Object> arguments = getArguments(request, body);
|
||||
OperationArgumentResolver serverNamespaceResolver = OperationArgumentResolver.of(WebServerNamespace.class,
|
||||
() -> getServerNamespace(request));
|
||||
ProducibleOperationArgumentResolver producibleOperationResolver = new ProducibleOperationArgumentResolver(
|
||||
() -> headers.get("Accept"));
|
||||
return new InvocationContext(securityContext, arguments, serverNamespaceResolver,
|
||||
producibleOperationResolver);
|
||||
}
|
||||
|
||||
private @Nullable WebServerNamespace getServerNamespace(HttpServletRequest request) {
|
||||
WebApplicationContext context = WebApplicationContextUtils
|
||||
.getRequiredWebApplicationContext(request.getServletContext());
|
||||
return WebServerNamespace.from(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user