Split WebEndpointTest infrastructure configuration

Issue: 46071
This commit is contained in:
Stéphane Nicoll 2025-05-22 17:03:13 +02:00 committed by Phillip Webb
parent 331bdbd586
commit d8f3a6e203
24 changed files with 492 additions and 202 deletions

View File

@ -62,7 +62,6 @@ include "spring-boot-project:spring-boot-actuator-autoconfigure"
include "spring-boot-project:spring-boot-actuator-autoconfigure-all"
include "spring-boot-project:spring-boot-actuator-docs"
include "spring-boot-project:spring-boot-actuator-integration-tests"
include "spring-boot-project:spring-boot-actuator-test-support"
include "spring-boot-project:spring-boot-amqp"
include "spring-boot-project:spring-boot-artemis"
include "spring-boot-project:spring-boot-autoconfigure"

View File

@ -24,7 +24,6 @@ description = "Spring Boot Actuator Integration Tests"
dependencies {
testImplementation(project(":spring-boot-project:spring-boot-actuator"))
testImplementation(project(":spring-boot-project:spring-boot-actuator-test-support"))
testImplementation(project(":spring-boot-project:spring-boot-autoconfigure"))
testImplementation(project(":spring-boot-project:spring-boot-http-converter"))
testImplementation(project(":spring-boot-project:spring-boot-jackson"))
@ -37,6 +36,9 @@ dependencies {
testImplementation(project(":spring-boot-project:spring-boot-web-server"))
testImplementation(project(":spring-boot-project:spring-boot-webflux"))
testImplementation(project(":spring-boot-project:spring-boot-webmvc"))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-jersey")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-webflux")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-webmvc")))
testImplementation("io.micrometer:micrometer-registry-prometheus")
testImplementation("io.prometheus:prometheus-metrics-exposition-formats")
testImplementation("net.minidev:json-smart")

View File

@ -1,54 +0,0 @@
/*
* Copyright 2012-present 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.
*/
plugins {
id "java-library"
id "org.springframework.boot.optional-dependencies"
}
description = "Spring Boot Actuator Testing Support"
dependencies {
api(project(":spring-boot-project:spring-boot-actuator"))
api(project(":spring-boot-project:spring-boot-autoconfigure"))
api(project(":spring-boot-project:spring-boot-http-converter"))
api(project(":spring-boot-project:spring-boot-jackson"))
api(project(":spring-boot-project:spring-boot-jersey"))
api(project(":spring-boot-project:spring-boot-reactor-netty"))
api(project(":spring-boot-project:spring-boot-test"))
api(project(":spring-boot-project:spring-boot-tomcat"))
api(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
api(project(":spring-boot-project:spring-boot-webflux"))
api(project(":spring-boot-project:spring-boot-webmvc"))
api("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
api("com.jayway.jsonpath:json-path")
api("org.assertj:assertj-core")
api("org.awaitility:awaitility")
api("org.hamcrest:hamcrest-core")
api("org.hamcrest:hamcrest-library")
api("org.junit.jupiter:junit-jupiter")
api("org.mockito:mockito-core")
api("org.mockito:mockito-junit-jupiter")
api("org.skyscreamer:jsonassert")
api("org.springframework:spring-core")
api("org.springframework:spring-test")
api("org.springframework:spring-core-test")
compileOnly("org.junit.platform:junit-platform-engine")
compileOnly("org.junit.platform:junit-platform-launcher")
compileOnly("org.springframework:spring-context")
}

View File

@ -16,6 +16,7 @@
plugins {
id "java-library"
id "java-test-fixtures"
id "org.springframework.boot.configuration-properties"
id "org.springframework.boot.optional-dependencies"
id "org.springframework.boot.deployed"
@ -61,6 +62,10 @@ dependencies {
optional("org.springframework.security:spring-security-core")
optional("org.springframework.security:spring-security-web")
testFixturesApi("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api")
testFixturesImplementation("org.springframework:spring-test")
testImplementation(project(":spring-boot-project:spring-boot-autoconfigure"))
testImplementation(project(":spring-boot-project:spring-boot-jackson"))
testImplementation(project(":spring-boot-project:spring-boot-jsonb"))

View File

@ -0,0 +1,46 @@
/*
* Copyright 2012-present 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.actuate.endpoint.web.test;
import java.util.List;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;
/**
* Strategy interface to provide the web endpoint configuration for a target
* {@linkplain Infrastructure infrastructure}.
*
* @author Stephane Nicoll
* @since 4.0.0
*/
public interface WebEndpointInfrastructureProvider {
/**
* Specify if the given {@link Infrastructure} is supported.
* @param infrastructure the infrastructure to target
* @return {@code true} if this instance can provide the configuration
*/
boolean supports(Infrastructure infrastructure);
/**
* Return the configuration to use for the given {@code infrastructure}.
* @param infrastructure the infrastructure to target
* @return the configuration for that infrastructure
*/
List<Class<?>> getInfrastructureConfiguration(Infrastructure infrastructure);
}

View File

@ -53,29 +53,27 @@ public @interface WebEndpointTest {
/**
* Actuator running on the Jersey-based infrastructure.
*/
JERSEY("Jersey", WebEndpointTestInvocationContextProvider::createJerseyContext),
JERSEY("Jersey"),
/**
* Actuator running on the WebMVC-based infrastructure.
*/
MVC("WebMvc", WebEndpointTestInvocationContextProvider::createWebMvcContext),
MVC("WebMvc"),
/**
* Actuator running on the WebFlux-based infrastructure.
*/
WEBFLUX("WebFlux", WebEndpointTestInvocationContextProvider::createWebFluxContext);
WEBFLUX("WebFlux");
private final String name;
private final Function<List<Class<?>>, ConfigurableApplicationContext> contextFactory;
Infrastructure(String name, Function<List<Class<?>>, ConfigurableApplicationContext> contextFactory) {
Infrastructure(String name) {
this.name = name;
this.contextFactory = contextFactory;
}
WebEndpointsInvocationContext createInvocationContext() {
return new WebEndpointsInvocationContext(this.name, this.contextFactory);
WebEndpointsInvocationContext createInvocationContext(
Function<List<Class<?>>, ConfigurableApplicationContext> contextFactory) {
return new WebEndpointsInvocationContext(this.name, contextFactory);
}
}

View File

@ -18,16 +18,14 @@ package org.springframework.boot.actuate.endpoint.web.test;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.Extension;
@ -38,29 +36,10 @@ import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;
import org.junit.platform.commons.util.AnnotationUtils;
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.jersey.actuate.endpoint.web.JerseyEndpointResourceFactory;
import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;
import org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;
import org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.context.WebServerInitializedEvent;
import org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigRegistry;
@ -68,12 +47,10 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.ClassUtils;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
@ -81,10 +58,29 @@ import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
* {@link TestTemplateInvocationContextProvider} for
* {@link WebEndpointTest @WebEndpointTest}.
*
* @author Andy Wilkinson
* @author Andy Wilkinson`
* @author Stephane Nicoll
*/
class WebEndpointTestInvocationContextProvider implements TestTemplateInvocationContextProvider {
private final Map<Infrastructure, List<Class<?>>> infrastructures;
private final Map<Infrastructure, Function<List<Class<?>>, ConfigurableApplicationContext>> contextFactories;
WebEndpointTestInvocationContextProvider() {
this.infrastructures = new HashMap<>();
List<WebEndpointInfrastructureProvider> providers = SpringFactoriesLoader
.loadFactories(WebEndpointInfrastructureProvider.class, getClass().getClassLoader());
Stream.of(Infrastructure.values())
.forEach((infrastructure) -> providers.stream()
.filter((provider) -> provider.supports(infrastructure))
.findFirst()
.ifPresent((provider) -> this.infrastructures.put(infrastructure,
provider.getInfrastructureConfiguration(infrastructure))));
this.contextFactories = Map.of(Infrastructure.JERSEY, this::createJerseyContext, Infrastructure.MVC,
this::createWebMvcContext, Infrastructure.WEBFLUX, this::createWebFluxContext);
}
@Override
public boolean supportsTestTemplate(ExtensionContext context) {
return true;
@ -97,33 +93,49 @@ class WebEndpointTestInvocationContextProvider implements TestTemplateInvocation
.findAnnotation(extensionContext.getRequiredTestMethod(), WebEndpointTest.class)
.orElseThrow(() -> new IllegalStateException("Unable to find WebEndpointTest annotation on %s"
.formatted(extensionContext.getRequiredTestMethod())));
return Stream.of(webEndpointTest.infrastructure()).distinct().map(Infrastructure::createInvocationContext);
return Stream.of(webEndpointTest.infrastructure()).distinct().map(this::createInvocationContext);
}
static ConfigurableApplicationContext createJerseyContext(List<Class<?>> classes) {
private WebEndpointsInvocationContext createInvocationContext(Infrastructure infrastructure) {
return infrastructure.createInvocationContext(this.contextFactories.get(infrastructure));
}
private ConfigurableApplicationContext createJerseyContext(List<Class<?>> classes) {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();
classes.add(JerseyEndpointConfiguration.class);
classes.addAll(getEndpointInfrastructureConfiguration(Infrastructure.JERSEY));
context.register(ClassUtils.toClassArray(classes));
context.refresh();
return context;
}
static ConfigurableApplicationContext createWebMvcContext(List<Class<?>> classes) {
private ConfigurableApplicationContext createWebMvcContext(List<Class<?>> classes) {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();
classes.add(WebMvcEndpointConfiguration.class);
classes.addAll(getEndpointInfrastructureConfiguration(Infrastructure.MVC));
context.register(ClassUtils.toClassArray(classes));
context.refresh();
return context;
}
static ConfigurableApplicationContext createWebFluxContext(List<Class<?>> classes) {
private ConfigurableApplicationContext createWebFluxContext(List<Class<?>> classes) {
AnnotationConfigReactiveWebServerApplicationContext context = new AnnotationConfigReactiveWebServerApplicationContext();
classes.add(WebFluxEndpointConfiguration.class);
classes.addAll(getEndpointInfrastructureConfiguration(Infrastructure.WEBFLUX));
context.register(ClassUtils.toClassArray(classes));
context.refresh();
return context;
}
private List<Class<?>> getEndpointInfrastructureConfiguration(Infrastructure infrastructure) {
List<Class<?>> configurationClasses = new ArrayList<>();
configurationClasses.add(EndpointBaseConfiguration.class);
List<Class<?>> endpointConfiguration = this.infrastructures.get(infrastructure);
if (endpointConfiguration == null) {
throw new IllegalStateException(
"No endpoint infrastructure configuration found for " + infrastructure.name());
}
configurationClasses.addAll(endpointConfiguration);
return configurationClasses;
}
static class WebEndpointsInvocationContext
implements TestTemplateInvocationContext, BeforeEachCallback, AfterEachCallback, ParameterResolver {
@ -206,69 +218,16 @@ class WebEndpointTestInvocationContextProvider implements TestTemplateInvocation
}
private int determinePort() {
if (this.context instanceof AnnotationConfigServletWebServerApplicationContext webServerContext) {
return webServerContext.getWebServer().getPort();
}
return this.context.getBean(PortHolder.class).getPort();
}
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ JacksonAutoConfiguration.class, JerseyAutoConfiguration.class })
static class JerseyEndpointConfiguration {
private final ApplicationContext applicationContext;
JerseyEndpointConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
TomcatServletWebServerFactory tomcat() {
return new TomcatServletWebServerFactory(0);
}
@Bean
ResourceConfig resourceConfig() {
return new ResourceConfig();
}
@Bean
ResourceConfigCustomizer webEndpointRegistrar() {
return this::customize;
}
private void customize(ResourceConfig config) {
EndpointMediaTypes endpointMediaTypes = EndpointMediaTypes.DEFAULT;
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,
new ConversionServiceParameterValueMapper(), endpointMediaTypes, null, Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
Collection<Resource> resources = new JerseyEndpointResourceFactory().createEndpointResources(
new EndpointMapping("/actuator"), discoverer.getEndpoints(), endpointMediaTypes,
new EndpointLinksResolver(discoverer.getEndpoints()), true);
config.registerResources(new HashSet<>(resources));
}
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ JacksonAutoConfiguration.class, WebFluxAutoConfiguration.class })
static class WebFluxEndpointConfiguration implements ApplicationListener<WebServerInitializedEvent> {
private final ApplicationContext applicationContext;
static class EndpointBaseConfiguration implements ApplicationListener<WebServerInitializedEvent> {
private final PortHolder portHolder = new PortHolder();
WebFluxEndpointConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
NettyReactiveWebServerFactory netty() {
return new NettyReactiveWebServerFactory(0);
}
@Bean
PortHolder portHolder() {
return this.portHolder;
@ -279,51 +238,6 @@ class WebEndpointTestInvocationContextProvider implements TestTemplateInvocation
this.portHolder.setPort(event.getWebServer().getPort());
}
@Bean
HttpHandler httpHandler(ApplicationContext applicationContext) {
return WebHttpHandlerBuilder.applicationContext(applicationContext).build();
}
@Bean
WebFluxEndpointHandlerMapping webEndpointReactiveHandlerMapping() {
EndpointMediaTypes endpointMediaTypes = EndpointMediaTypes.DEFAULT;
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,
new ConversionServiceParameterValueMapper(), endpointMediaTypes, Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
return new WebFluxEndpointHandlerMapping(new EndpointMapping("/actuator"), discoverer.getEndpoints(),
endpointMediaTypes, new CorsConfiguration(), new EndpointLinksResolver(discoverer.getEndpoints()),
true);
}
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class })
static class WebMvcEndpointConfiguration {
private final ApplicationContext applicationContext;
WebMvcEndpointConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
TomcatServletWebServerFactory tomcat() {
return new TomcatServletWebServerFactory(0);
}
@Bean
WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping() {
EndpointMediaTypes endpointMediaTypes = EndpointMediaTypes.DEFAULT;
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,
new ConversionServiceParameterValueMapper(), endpointMediaTypes, Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
return new WebMvcEndpointHandlerMapping(new EndpointMapping("/actuator"), discoverer.getEndpoints(),
endpointMediaTypes, new CorsConfiguration(), new EndpointLinksResolver(discoverer.getEndpoints()),
true);
}
}
private static final class PortHolder {

View File

@ -61,10 +61,12 @@ dependencies {
dockerTestImplementation("org.testcontainers:junit-jupiter")
dockerTestImplementation("org.testcontainers:testcontainers")
testImplementation(project(":spring-boot-project:spring-boot-actuator-test-support"))
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-autoconfigure")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-jersey")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-webmvc")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-webflux")))
testRuntimeOnly("ch.qos.logback:logback-classic")
}

View File

@ -40,11 +40,13 @@ dependencies {
optional("org.springframework.integration:spring-integration-jmx")
optional("org.springframework.integration:spring-integration-rsocket")
testImplementation(project(":spring-boot-project:spring-boot-actuator-test-support"))
testImplementation(project(":spring-boot-project:spring-boot-flyway"))
testImplementation(project(":spring-boot-project:spring-boot-rsocket"))
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-jersey")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-webflux")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-webmvc")))
testImplementation("org.springframework:spring-web")
testRuntimeOnly(project(":spring-boot-project:spring-boot-reactor-netty"))

View File

@ -17,6 +17,7 @@
plugins {
id "java-library"
id "java-test-fixtures"
id "org.springframework.boot.auto-configuration"
id "org.springframework.boot.configuration-properties"
id "org.springframework.boot.deployed"
@ -41,6 +42,9 @@ dependencies {
optional(project(":spring-boot-project:spring-boot-jackson"))
optional("io.projectreactor:reactor-core")
testFixturesApi(testFixtures(project(":spring-boot-project:spring-boot-actuator")))
testFixturesImplementation(project(":spring-boot-project:spring-boot-tomcat"))
testImplementation(project(":spring-boot-project:spring-boot-restclient"))
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tomcat"))

View File

@ -0,0 +1,83 @@
/*
* Copyright 2012-present 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.jersey.actuate.endpoint.web.test;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.jersey.actuate.endpoint.web.JerseyEndpointResourceFactory;
import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;
import org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Endpoint configuration for Jersey.
*
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ JacksonAutoConfiguration.class, JerseyAutoConfiguration.class })
class JerseyEndpointConfiguration {
private final ApplicationContext applicationContext;
JerseyEndpointConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
TomcatServletWebServerFactory tomcat() {
return new TomcatServletWebServerFactory(0);
}
@Bean
ResourceConfig resourceConfig() {
return new ResourceConfig();
}
@Bean
ResourceConfigCustomizer webEndpointRegistrar() {
return this::customize;
}
private void customize(ResourceConfig config) {
EndpointMediaTypes endpointMediaTypes = EndpointMediaTypes.DEFAULT;
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,
new ConversionServiceParameterValueMapper(), endpointMediaTypes, null, Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
Collection<Resource> resources = new JerseyEndpointResourceFactory().createEndpointResources(
new EndpointMapping("/actuator"), discoverer.getEndpoints(), endpointMediaTypes,
new EndpointLinksResolver(discoverer.getEndpoints()), true);
config.registerResources(new HashSet<>(resources));
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2012-present 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.jersey.actuate.endpoint.web.test;
import java.util.List;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;
/**
* {@link WebEndpointInfrastructureProvider} for Jersey.
*
* @author Stephane Nicoll
*/
class JerseyWebEndpointInfrastructureProvider implements WebEndpointInfrastructureProvider {
@Override
public boolean supports(Infrastructure infrastructure) {
return infrastructure == Infrastructure.JERSEY;
}
@Override
public List<Class<?>> getInfrastructureConfiguration(Infrastructure infrastructure) {
return List.of(JerseyEndpointConfiguration.class);
}
}

View File

@ -0,0 +1,2 @@
org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider=\
org.springframework.boot.jersey.actuate.endpoint.web.test.JerseyWebEndpointInfrastructureProvider

View File

@ -37,11 +37,13 @@ dependencies {
optional(project(":spring-boot-project:spring-boot-jdbc"))
optional(project(":spring-boot-project:spring-boot-jpa"))
testImplementation(project(":spring-boot-project:spring-boot-actuator-test-support"))
testImplementation(project(":spring-boot-project:spring-boot-flyway"))
testImplementation(project(":spring-boot-project:spring-boot-liquibase"))
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-jersey")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-webflux")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-webmvc")))
testImplementation("net.minidev:json-smart")
testImplementation("org.springframework:spring-web")

View File

@ -45,11 +45,13 @@ dependencies {
testFixturesImplementation(testFixtures(project(":spring-boot-project:spring-boot-web-server")))
testFixturesImplementation("io.projectreactor:reactor-core")
testImplementation(project(":spring-boot-project:spring-boot-actuator-test-support"))
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tomcat"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(project(":spring-boot-project:spring-boot-webflux"))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-jersey")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-webflux")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-webmvc")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-web-server")))
testImplementation("net.minidev:json-smart")
testImplementation("io.projectreactor:reactor-test")

View File

@ -17,6 +17,7 @@
plugins {
id "java-library"
id "java-test-fixtures"
id "org.springframework.boot.auto-configuration"
id "org.springframework.boot.configuration-properties"
id "org.springframework.boot.deployed"
@ -36,6 +37,10 @@ dependencies {
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
optional(project(":spring-boot-project:spring-boot-validation"))
testFixturesApi(testFixtures(project(":spring-boot-project:spring-boot-actuator")))
testFixturesImplementation(project(":spring-boot-project:spring-boot-jackson"))
testFixturesImplementation(project(":spring-boot-project:spring-boot-reactor-netty"))
testImplementation(project(":spring-boot-project:spring-boot-mustache"))
testImplementation(project(":spring-boot-project:spring-boot-reactor-netty"))
testImplementation(project(":spring-boot-project:spring-boot-test"))

View File

@ -0,0 +1,75 @@
/*
* Copyright 2012-present 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.webflux.actuate.endpoint.web.test;
import java.util.Collections;
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
/**
* Endpoint configuration for WebFlux.
*
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ JacksonAutoConfiguration.class, WebFluxAutoConfiguration.class })
class WebFluxEndpointConfiguration {
private final ApplicationContext applicationContext;
WebFluxEndpointConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
NettyReactiveWebServerFactory netty() {
return new NettyReactiveWebServerFactory(0);
}
@Bean
HttpHandler httpHandler(ApplicationContext applicationContext) {
return WebHttpHandlerBuilder.applicationContext(applicationContext).build();
}
@Bean
WebFluxEndpointHandlerMapping webEndpointReactiveHandlerMapping() {
EndpointMediaTypes endpointMediaTypes = EndpointMediaTypes.DEFAULT;
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,
new ConversionServiceParameterValueMapper(), endpointMediaTypes, Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
return new WebFluxEndpointHandlerMapping(new EndpointMapping("/actuator"), discoverer.getEndpoints(),
endpointMediaTypes, new CorsConfiguration(), new EndpointLinksResolver(discoverer.getEndpoints()),
true);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2012-present 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.webflux.actuate.endpoint.web.test;
import java.util.List;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;
/**
* {@link WebEndpointInfrastructureProvider} for WebFlux.
*
* @author Stephane Nicoll
*/
class WebFluxWebEndpointInfrastructureProvider implements WebEndpointInfrastructureProvider {
@Override
public boolean supports(Infrastructure infrastructure) {
return infrastructure == Infrastructure.WEBFLUX;
}
@Override
public List<Class<?>> getInfrastructureConfiguration(Infrastructure infrastructure) {
return List.of(WebFluxEndpointConfiguration.class);
}
}

View File

@ -0,0 +1,2 @@
org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider=\
org.springframework.boot.webflux.actuate.endpoint.web.test.WebFluxWebEndpointInfrastructureProvider

View File

@ -17,6 +17,7 @@
plugins {
id "java-library"
id "java-test-fixtures"
id "org.springframework.boot.auto-configuration"
id "org.springframework.boot.configuration-properties"
id "org.springframework.boot.deployed"
@ -41,6 +42,10 @@ dependencies {
optional(project(":spring-boot-project:spring-boot-validation"))
optional(project(":spring-boot-project:spring-boot-web-server"))
testFixturesApi(testFixtures(project(":spring-boot-project:spring-boot-actuator")))
testFixturesImplementation(project(":spring-boot-project:spring-boot-http-converter"))
testFixturesImplementation(project(":spring-boot-project:spring-boot-jackson"))
testImplementation(project(":spring-boot-project:spring-boot-freemarker"))
testImplementation(project(":spring-boot-project:spring-boot-restclient"))
testImplementation(project(":spring-boot-project:spring-boot-test"))

View File

@ -0,0 +1,71 @@
/*
* Copyright 2012-present 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.endpoint.web.test;
import java.util.Collections;
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
/**
* Endpoint configuration for WebMvc.
*
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class })
class WebMvcEndpointConfiguration {
private final ApplicationContext applicationContext;
WebMvcEndpointConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
TomcatServletWebServerFactory tomcat() {
return new TomcatServletWebServerFactory(0);
}
@Bean
WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping() {
EndpointMediaTypes endpointMediaTypes = EndpointMediaTypes.DEFAULT;
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,
new ConversionServiceParameterValueMapper(), endpointMediaTypes, Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
return new WebMvcEndpointHandlerMapping(new EndpointMapping("/actuator"), discoverer.getEndpoints(),
endpointMediaTypes, new CorsConfiguration(), new EndpointLinksResolver(discoverer.getEndpoints()),
true);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2012-present 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.endpoint.web.test;
import java.util.List;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;
/**
* {@link WebEndpointInfrastructureProvider} for MVC.
*
* @author Stephane Nicoll
*/
class WebMvcWebEndpointInfrastructureProvider implements WebEndpointInfrastructureProvider {
@Override
public boolean supports(Infrastructure infrastructure) {
return infrastructure == Infrastructure.MVC;
}
@Override
public List<Class<?>> getInfrastructureConfiguration(Infrastructure infrastructure) {
return List.of(WebMvcEndpointConfiguration.class);
}
}

View File

@ -0,0 +1,2 @@
org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider=\
org.springframework.boot.webmvc.actuate.endpoint.web.test.WebMvcWebEndpointInfrastructureProvider