diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/server/ChildManagementContextInitializerAotTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/server/ChildManagementContextInitializerAotTests.java index eab060c3872..306a8710498 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/server/ChildManagementContextInitializerAotTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/server/ChildManagementContextInitializerAotTests.java @@ -16,12 +16,8 @@ package org.springframework.boot.actuate.autoconfigure.web.server; -import java.net.URL; import java.util.function.Consumer; -import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -36,6 +32,7 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext; import org.springframework.context.ApplicationContextInitializer; @@ -44,7 +41,6 @@ import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.test.tools.CompileWithForkedClassLoader; import org.springframework.core.test.tools.TestCompiler; import org.springframework.javapoet.ClassName; -import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -55,15 +51,9 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Phillip Webb */ @ExtendWith(OutputCaptureExtension.class) +@DirtiesUrlFactories class ChildManagementContextInitializerAotTests { - @BeforeEach - @AfterEach - void reset() { - ReflectionTestUtils.setField(TomcatURLStreamHandlerFactory.class, "instance", null); - ReflectionTestUtils.setField(URL.class, "factory", null); - } - @Test @CompileWithForkedClassLoader @SuppressWarnings("unchecked") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/DirtiesUrlFactories.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/DirtiesUrlFactories.java new file mode 100644 index 00000000000..deb5b59e761 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/DirtiesUrlFactories.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2022 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.testsupport.web.servlet; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Indicates that a test pollutes URL factories. + * + * @author Phillip Webb + * @since 2.6.14 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Documented +@ExtendWith(DirtiesUrlFactoriesExtension.class) +public @interface DirtiesUrlFactories { + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/DirtiesUrlFactoriesExtension.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/DirtiesUrlFactoriesExtension.java new file mode 100644 index 00000000000..db2e102e284 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/DirtiesUrlFactoriesExtension.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2022 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.testsupport.web.servlet; + +import java.net.URL; + +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.util.ClassUtils; + +/** + * JUnit extension used by {@link DirtiesUrlFactories @DirtiesUrlFactories}. + * + * @author Phillip Webb + */ +class DirtiesUrlFactoriesExtension implements BeforeEachCallback, AfterEachCallback { + + private static final String TOMCAT_URL_STREAM_HANDLER_FACTORY = "org.apache.catalina.webresources.TomcatURLStreamHandlerFactory"; + + @Override + public void afterEach(ExtensionContext context) throws Exception { + reset(); + } + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + reset(); + } + + private void reset() { + ClassLoader classLoader = getClass().getClassLoader(); + if (ClassUtils.isPresent(TOMCAT_URL_STREAM_HANDLER_FACTORY, classLoader)) { + Class factoryClass = ClassUtils.resolveClassName(TOMCAT_URL_STREAM_HANDLER_FACTORY, classLoader); + ReflectionTestUtils.setField(factoryClass, "instance", null); + } + ReflectionTestUtils.setField(URL.class, "factory", null); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java index ad8a9a25381..f1d7716fcae 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java @@ -18,7 +18,6 @@ package org.springframework.boot.web.embedded.tomcat; import java.io.IOException; import java.io.InputStream; -import java.net.URL; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -28,7 +27,6 @@ import java.util.Set; import org.apache.catalina.LifecycleState; import org.apache.catalina.connector.Connector; import org.apache.catalina.startup.Tomcat; -import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory; import org.apache.tomcat.util.net.SSLHostConfig; import org.apache.tomcat.util.net.SSLHostConfigCertificate; import org.junit.jupiter.api.AfterEach; @@ -38,12 +36,12 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.testsupport.system.CapturedOutput; import org.springframework.boot.testsupport.system.OutputCaptureExtension; +import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.web.server.Ssl; import org.springframework.boot.web.server.SslStoreProvider; import org.springframework.boot.web.server.WebServerException; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; -import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -58,6 +56,7 @@ import static org.mockito.Mockito.mock; * @author Scott Frederick */ @ExtendWith(OutputCaptureExtension.class) +@DirtiesUrlFactories class SslConnectorCustomizerTests { private Tomcat tomcat; @@ -75,8 +74,6 @@ class SslConnectorCustomizerTests { @AfterEach void stop() throws Exception { System.clearProperty("javax.net.ssl.trustStorePassword"); - ReflectionTestUtils.setField(TomcatURLStreamHandlerFactory.class, "instance", null); - ReflectionTestUtils.setField(URL.class, "factory", null); this.tomcat.stop(); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java index bdfeefa6911..0e8b5c6a6e1 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java @@ -78,7 +78,6 @@ import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; -import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory; import org.apache.hc.client5.http.classic.HttpClient; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.entity.InputStreamFactory; @@ -116,6 +115,7 @@ import org.springframework.boot.system.ApplicationHome; import org.springframework.boot.system.ApplicationTemp; import org.springframework.boot.testsupport.system.CapturedOutput; import org.springframework.boot.testsupport.system.OutputCaptureExtension; +import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.testsupport.web.servlet.ExampleFilter; import org.springframework.boot.testsupport.web.servlet.ExampleServlet; import org.springframework.boot.web.server.Compression; @@ -144,7 +144,6 @@ import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.util.ClassUtils; import org.springframework.util.FileCopyUtils; import org.springframework.util.StreamUtils; @@ -172,6 +171,7 @@ import static org.mockito.Mockito.mock; * @author Scott Frederick */ @ExtendWith(OutputCaptureExtension.class) +@DirtiesUrlFactories public abstract class AbstractServletWebServerFactoryTests { @TempDir @@ -194,20 +194,6 @@ public abstract class AbstractServletWebServerFactoryTests { // Ignore } } - if (ClassUtils.isPresent("org.apache.catalina.webresources.TomcatURLStreamHandlerFactory", - getClass().getClassLoader())) { - ReflectionTestUtils.setField(TomcatURLStreamHandlerFactory.class, "instance", null); - } - ReflectionTestUtils.setField(URL.class, "factory", null); - } - - @AfterEach - void clearUrlStreamHandlerFactory() { - if (ClassUtils.isPresent("org.apache.catalina.webresources.TomcatURLStreamHandlerFactory", - getClass().getClassLoader())) { - ReflectionTestUtils.setField(TomcatURLStreamHandlerFactory.class, "instance", null); - ReflectionTestUtils.setField(URL.class, "factory", null); - } } @Test