From 8f72ca65214586b02ae3eef6f868995e5c2df9da Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 26 Feb 2021 14:25:24 +0000 Subject: [PATCH] Use ResourceConfig customization to register endpoints with Jersey Previously, actuator endpoints were registered with Jersey upon injection of the ResourceConfig bean into a registrar class rather than using a ResourceConfigCustomizer. This was done to fix a problem when running the Actuator on a separate port where the main application context's customizers were also applied to the management context, breaking the singleton contract for those resources. This approach meant that the registration could be performed at any point after the ResourceConfig had been created. When Jersey's configured as a Filter this resulted in the registration failing as the attempt was being made after the Filter lifecyle callbacks which make the ResourceConfig immutable. This commit reworks the endpoint registration to be performed using a ManagementContextResourceConfigCustomizer, a resource config customizer that's only applied to the ResourceConfig that's used by the Actuator. When there's a separate management context, this ResourceConfig is created by the Actuator's auto-configuration and the management context resource config customizers are applied to it during its creation. The main application's customizers are not applied. When the actuator is using the same context as the main application, this ResourceConfig is created by the main application. In this case a ResourceConfigCustomizer is defined that delegates to all ManagementContextResourceConfigCustomizers, allowing them to register the actuator endpoints with the main ResourceConfig. Fixes gh-25262 --- ...ndpointManagementContextConfiguration.java | 49 +++++------- ...eyChildManagementContextConfiguration.java | 10 ++- .../JerseyManagementContextConfiguration.java | 7 +- ...seySameManagementContextConfiguration.java | 33 ++++++-- ...gementContextResourceConfigCustomizer.java | 36 +++++++++ .../JerseyWebEndpointIntegrationTests.java | 78 +++++++++++++++++++ ...ldManagementContextConfigurationTests.java | 27 ++++++- ...meManagementContextConfigurationTests.java | 24 +++++- ...va => AbstractJerseyApplicationTests.java} | 6 +- ...=> AbstractJerseyManagementPortTests.java} | 27 ++++++- .../jersey/JerseyFilterApplicationTests.java | 29 +++++++ .../JerseyFilterManagementPortTests.java | 30 +++++++ .../jersey/JerseyServletApplicationTests.java | 26 +++++++ .../JerseyServletManagementPortTests.java | 27 +++++++ 14 files changed, 358 insertions(+), 51 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/ManagementContextResourceConfigCustomizer.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointIntegrationTests.java rename spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/{SampleJerseyApplicationTests.java => AbstractJerseyApplicationTests.java} (90%) rename spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/{JerseyManagementPortTests.java => AbstractJerseyManagementPortTests.java} (72%) create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyFilterApplicationTests.java create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyFilterManagementPortTests.java create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyServletApplicationTests.java create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyServletManagementPortTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfiguration.java index 3d18efd431c..221439edc95 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -24,9 +24,9 @@ import java.util.List; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.model.Resource; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration; +import org.springframework.boot.actuate.autoconfigure.web.jersey.ManagementContextResourceConfigCustomizer; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -43,7 +43,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; @@ -67,14 +66,13 @@ class JerseyWebEndpointManagementContextConfiguration { @Bean JerseyWebEndpointsResourcesRegistrar jerseyWebEndpointsResourcesRegistrar(Environment environment, - ObjectProvider resourceConfig, WebEndpointsSupplier webEndpointsSupplier, - ServletEndpointsSupplier servletEndpointsSupplier, EndpointMediaTypes endpointMediaTypes, - WebEndpointProperties webEndpointProperties) { + WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier, + EndpointMediaTypes endpointMediaTypes, WebEndpointProperties webEndpointProperties) { String basePath = webEndpointProperties.getBasePath(); boolean shouldRegisterLinks = shouldRegisterLinksMapping(environment, basePath); shouldRegisterLinksMapping(environment, basePath); - return new JerseyWebEndpointsResourcesRegistrar(resourceConfig.getIfAvailable(), webEndpointsSupplier, - servletEndpointsSupplier, endpointMediaTypes, basePath, shouldRegisterLinks); + return new JerseyWebEndpointsResourcesRegistrar(webEndpointsSupplier, servletEndpointsSupplier, + endpointMediaTypes, basePath, shouldRegisterLinks); } private boolean shouldRegisterLinksMapping(Environment environment, String basePath) { @@ -83,12 +81,9 @@ class JerseyWebEndpointManagementContextConfiguration { } /** - * Register endpoints with the {@link ResourceConfig}. The - * {@link ResourceConfigCustomizer} cannot be used because we don't want to apply + * Register endpoints with the {@link ResourceConfig} for the management context. */ - static class JerseyWebEndpointsResourcesRegistrar { - - private final ResourceConfig resourceConfig; + static class JerseyWebEndpointsResourcesRegistrar implements ManagementContextResourceConfigCustomizer { private final WebEndpointsSupplier webEndpointsSupplier; @@ -100,33 +95,29 @@ class JerseyWebEndpointManagementContextConfiguration { private final boolean shouldRegisterLinks; - JerseyWebEndpointsResourcesRegistrar(ResourceConfig resourceConfig, WebEndpointsSupplier webEndpointsSupplier, + JerseyWebEndpointsResourcesRegistrar(WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier, EndpointMediaTypes endpointMediaTypes, String basePath, boolean shouldRegisterLinks) { - super(); - this.resourceConfig = resourceConfig; this.webEndpointsSupplier = webEndpointsSupplier; this.servletEndpointsSupplier = servletEndpointsSupplier; this.mediaTypes = endpointMediaTypes; this.basePath = basePath; this.shouldRegisterLinks = shouldRegisterLinks; - register(); } - private void register() { - // We can't easily use @ConditionalOnBean because @AutoConfigureBefore is - // not an option for management contexts. Instead we manually check if - // the resource config bean exists - if (this.resourceConfig == null) { - return; - } + @Override + public void customize(ResourceConfig config) { + register(config); + } + + private void register(ResourceConfig config) { Collection webEndpoints = this.webEndpointsSupplier.getEndpoints(); Collection servletEndpoints = this.servletEndpointsSupplier.getEndpoints(); EndpointLinksResolver linksResolver = getLinksResolver(webEndpoints, servletEndpoints); EndpointMapping mapping = new EndpointMapping(this.basePath); - JerseyEndpointResourceFactory resourceFactory = new JerseyEndpointResourceFactory(); - register(resourceFactory.createEndpointResources(mapping, webEndpoints, this.mediaTypes, linksResolver, - this.shouldRegisterLinks)); + Collection endpointResources = new JerseyEndpointResourceFactory().createEndpointResources( + mapping, webEndpoints, this.mediaTypes, linksResolver, this.shouldRegisterLinks); + register(endpointResources, config); } private EndpointLinksResolver getLinksResolver(Collection webEndpoints, @@ -137,8 +128,8 @@ class JerseyWebEndpointManagementContextConfiguration { return new EndpointLinksResolver(endpoints, this.basePath); } - private void register(Collection resources) { - this.resourceConfig.registerResources(new HashSet<>(resources)); + private void register(Collection resources, ResourceConfig config) { + config.registerResources(new HashSet<>(resources)); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyChildManagementContextConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyChildManagementContextConfiguration.java index b2f925c31f6..360e9357717 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyChildManagementContextConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyChildManagementContextConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -18,6 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.web.jersey; import org.glassfish.jersey.server.ResourceConfig; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration; import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -47,4 +48,11 @@ public class JerseyChildManagementContextConfiguration { return () -> "/"; } + @Bean + ResourceConfig resourceConfig(ObjectProvider customizers) { + ResourceConfig resourceConfig = new ResourceConfig(); + customizers.orderedStream().forEach((customizer) -> customizer.customize(resourceConfig)); + return resourceConfig; + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementContextConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementContextConfiguration.java index 8f65f4fb7dd..57e7bf9835d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementContextConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementContextConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2021 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. @@ -39,9 +39,4 @@ class JerseyManagementContextConfiguration { jerseyApplicationPath.getUrlMapping()); } - @Bean - ResourceConfig resourceConfig() { - return new ResourceConfig(); - } - } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseySameManagementContextConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseySameManagementContextConfiguration.java index 60e039eab8f..9de0cc4019c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseySameManagementContextConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseySameManagementContextConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -18,6 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.web.jersey; import org.glassfish.jersey.server.ResourceConfig; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration; import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -25,10 +26,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.jersey.JerseyProperties; +import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer; import org.springframework.boot.autoconfigure.web.servlet.DefaultJerseyApplicationPath; import org.springframework.boot.autoconfigure.web.servlet.JerseyApplicationPath; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** @@ -39,18 +42,36 @@ import org.springframework.context.annotation.Import; * @since 2.1.0 */ @ManagementContextConfiguration(value = ManagementContextType.SAME, proxyBeanMethods = false) -@Import(JerseyManagementContextConfiguration.class) @EnableConfigurationProperties(JerseyProperties.class) -@ConditionalOnMissingBean(ResourceConfig.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnClass(ResourceConfig.class) @ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet") public class JerseySameManagementContextConfiguration { @Bean - @ConditionalOnMissingBean(JerseyApplicationPath.class) - public JerseyApplicationPath jerseyApplicationPath(JerseyProperties properties, ResourceConfig config) { - return new DefaultJerseyApplicationPath(properties.getApplicationPath(), config); + ResourceConfigCustomizer managementResourceConfigCustomizerAdapter( + ObjectProvider customizers) { + return (config) -> customizers.orderedStream().forEach((customizer) -> customizer.customize(config)); + } + + @Configuration(proxyBeanMethods = false) + @Import(JerseyManagementContextConfiguration.class) + @ConditionalOnMissingBean(ResourceConfig.class) + class JerseyInfrastructureConfiguration { + + @Bean + @ConditionalOnMissingBean(JerseyApplicationPath.class) + JerseyApplicationPath jerseyApplicationPath(JerseyProperties properties, ResourceConfig config) { + return new DefaultJerseyApplicationPath(properties.getApplicationPath(), config); + } + + @Bean + ResourceConfig resourceConfig(ObjectProvider resourceConfigCustomizers) { + ResourceConfig resourceConfig = new ResourceConfig(); + resourceConfigCustomizers.orderedStream().forEach((customizer) -> customizer.customize(resourceConfig)); + return resourceConfig; + } + } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/ManagementContextResourceConfigCustomizer.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/ManagementContextResourceConfigCustomizer.java new file mode 100644 index 00000000000..028815b1356 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/ManagementContextResourceConfigCustomizer.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2021 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.autoconfigure.web.jersey; + +import org.glassfish.jersey.server.ResourceConfig; + +/** + * Callback interface that can be implemented by beans wishing to customize Jersey's + * {@link ResourceConfig} in the management context before it is used. + * + * @author Andy Wilkinson + * @since 2.3.10 + */ +public interface ManagementContextResourceConfigCustomizer { + + /** + * Customize the resource config. + * @param config the {@link ResourceConfig} to customize + */ + void customize(ResourceConfig config); + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointIntegrationTests.java new file mode 100644 index 00000000000..ca6c9984ba6 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointIntegrationTests.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2021 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.autoconfigure.endpoint.web.jersey; + +import java.util.Set; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.model.Resource; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.web.jersey.JerseySameManagementContextConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration; +import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener; +import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; +import org.springframework.boot.logging.LogLevel; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.DispatcherServlet; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for web endpoints running on Jersey. + * + * @author Andy Wilkinson + */ +class JerseyWebEndpointIntegrationTests { + + @Test + void whenJerseyIsConfiguredToUseAFilterThenResourceRegistrationSucceeds() { + new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new) + .withConfiguration(AutoConfigurations.of(JerseySameManagementContextConfiguration.class, + JerseyAutoConfiguration.class, ServletWebServerFactoryAutoConfiguration.class, + EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class, + JerseyWebEndpointManagementContextConfiguration.class)) + .withUserConfiguration(ResourceConfigConfiguration.class) + .withClassLoader(new FilteredClassLoader(DispatcherServlet.class)) + .withInitializer(new ConditionEvaluationReportLoggingListener(LogLevel.INFO)) + .withPropertyValues("spring.jersey.type=filter", "server.port=0").run((context) -> { + assertThat(context).hasNotFailed(); + Set resources = context.getBean(ResourceConfig.class).getResources(); + assertThat(resources).hasSize(1); + Resource resource = resources.iterator().next(); + assertThat(resource.getPath()).isEqualTo("/actuator"); + }); + } + + @Configuration(proxyBeanMethods = false) + static class ResourceConfigConfiguration { + + @Bean + ResourceConfig resourceConfig() { + return new ResourceConfig(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyChildManagementContextConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyChildManagementContextConfigurationTests.java index 9d57fa5f6ed..d19975c9a82 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyChildManagementContextConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyChildManagementContextConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2021 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. @@ -27,8 +27,12 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.testsupport.classpath.ClassPathExclusions; import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; /** * Tests for {@link JerseyChildManagementContextConfiguration}. @@ -78,4 +82,25 @@ class JerseyChildManagementContextConfigurationTests { this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ResourceConfig.class)); } + @Test + void resourceConfigIsCustomizedWithResourceConfigCustomizerBean() { + this.contextRunner.withUserConfiguration(CustomizerConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(ResourceConfig.class); + ResourceConfig config = context.getBean(ResourceConfig.class); + ManagementContextResourceConfigCustomizer customizer = context + .getBean(ManagementContextResourceConfigCustomizer.class); + verify(customizer).customize(config); + }); + } + + @Configuration(proxyBeanMethods = false) + static class CustomizerConfiguration { + + @Bean + ManagementContextResourceConfigCustomizer resourceConfigCustomizer() { + return mock(ManagementContextResourceConfigCustomizer.class); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseySameManagementContextConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseySameManagementContextConfigurationTests.java index 1f3063045f1..e15bdbb46e6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseySameManagementContextConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseySameManagementContextConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2021 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. @@ -33,6 +33,7 @@ import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; /** * Tests for {@link JerseySameManagementContextConfiguration}. @@ -91,6 +92,17 @@ class JerseySameManagementContextConfigurationTests { }); } + @Test + void resourceConfigIsCustomizedWithResourceConfigCustomizerBean() { + this.contextRunner.withUserConfiguration(CustomizerConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(ResourceConfig.class); + ResourceConfig config = context.getBean(ResourceConfig.class); + ManagementContextResourceConfigCustomizer customizer = context + .getBean(ManagementContextResourceConfigCustomizer.class); + verify(customizer).customize(config); + }); + } + @Configuration(proxyBeanMethods = false) static class ConfigWithJerseyApplicationPath { @@ -111,4 +123,14 @@ class JerseySameManagementContextConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class CustomizerConfiguration { + + @Bean + ManagementContextResourceConfigCustomizer resourceConfigCustomizer() { + return mock(ManagementContextResourceConfigCustomizer.class); + } + + } + } diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/SampleJerseyApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/AbstractJerseyApplicationTests.java similarity index 90% rename from spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/SampleJerseyApplicationTests.java rename to spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/AbstractJerseyApplicationTests.java index 0771ee6bc87..2c783f936b3 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/SampleJerseyApplicationTests.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/AbstractJerseyApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2021 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. @@ -27,8 +27,8 @@ import org.springframework.http.ResponseEntity; import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -class SampleJerseyApplicationTests { +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "logging.level.root=debug") +abstract class AbstractJerseyApplicationTests { @Autowired private TestRestTemplate restTemplate; diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyManagementPortTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/AbstractJerseyManagementPortTests.java similarity index 72% rename from spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyManagementPortTests.java rename to spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/AbstractJerseyManagementPortTests.java index 9ed29086ddc..22f3ac5ea65 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyManagementPortTests.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/AbstractJerseyManagementPortTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2021 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. @@ -21,6 +21,7 @@ import javax.ws.rs.Path; import org.glassfish.jersey.server.ResourceConfig; import org.junit.jupiter.api.Test; +import smoketest.jersey.AbstractJerseyManagementPortTests.ResourceConfigConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort; @@ -30,18 +31,22 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import static org.assertj.core.api.Assertions.assertThat; /** - * Integration tests for separate management and main service ports. + * Base class for integration tests for Jersey using separate management and main service + * ports. * * @author Madhura Bhave */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "management.server.port=0") -class JerseyManagementPortTests { +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = { "management.server.port=0", "debug=true" }) +@Import(ResourceConfigConfiguration.class) +class AbstractJerseyManagementPortTests { @LocalServerPort private int port; @@ -67,6 +72,20 @@ class JerseyManagementPortTests { assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); } + @Test + void actuatorShouldBeAvailableOnManagementPort() { + ResponseEntity entity = this.testRestTemplate + .getForEntity("http://localhost:" + this.managementPort + "/actuator/health", String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); + } + + @Test + void actuatorShouldNotBeAvailableOnMainPort() { + ResponseEntity entity = this.testRestTemplate + .getForEntity("http://localhost:" + this.port + "/actuator/health", String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + } + @TestConfiguration static class ResourceConfigConfiguration { diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyFilterApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyFilterApplicationTests.java new file mode 100644 index 00000000000..957bfbf0620 --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyFilterApplicationTests.java @@ -0,0 +1,29 @@ +/* + * Copyright 2012-2021 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 smoketest.jersey; + +import org.springframework.test.context.TestPropertySource; + +/** + * Smoke tests for Jersey configured as a Filter. + * + * @author Andy Wilkinson + */ +@TestPropertySource(properties = "spring.jersey.type=filter") +class JerseyFilterApplicationTests extends AbstractJerseyApplicationTests { + +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyFilterManagementPortTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyFilterManagementPortTests.java new file mode 100644 index 00000000000..a8785637d2d --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyFilterManagementPortTests.java @@ -0,0 +1,30 @@ +/* + * Copyright 2012-2021 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 smoketest.jersey; + +import org.springframework.test.context.TestPropertySource; + +/** + * Integration tests for Jersey configured as a Servlet using separate management and main + * service ports. + * + * @author Andy Wilkinson + */ +@TestPropertySource(properties = "spring.jersey.type=filter") +public class JerseyFilterManagementPortTests extends AbstractJerseyManagementPortTests { + +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyServletApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyServletApplicationTests.java new file mode 100644 index 00000000000..fa51216869d --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyServletApplicationTests.java @@ -0,0 +1,26 @@ +/* + * Copyright 2012-2021 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 smoketest.jersey; + +/** + * Smoke tests for Jersey configured as a Servlet. + * + * @author Andy Wilkinson + */ +class JerseyServletApplicationTests extends AbstractJerseyApplicationTests { + +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyServletManagementPortTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyServletManagementPortTests.java new file mode 100644 index 00000000000..333454063d9 --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyServletManagementPortTests.java @@ -0,0 +1,27 @@ +/* + * Copyright 2012-2021 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 smoketest.jersey; + +/** + * Integration tests for Jersey configured as a Servlet using separate management and main + * service ports. + * + * @author Andy Wilkinson + */ +public class JerseyServletManagementPortTests extends AbstractJerseyManagementPortTests { + +}