From dc7c7ac22acbc4b39ab1da1f1be372cb7bf64ada Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 4 Sep 2022 16:45:02 +0200 Subject: [PATCH] Register runtime hint for @WebAppConfiguration's resource path This commit introduces automatic registration of a runtime hint for classpath resources configured via the `value` attribute in @WebAppConfiguration. Closes gh-29026 --- .../context/aot/TestContextAotGenerator.java | 22 +++++++++++++++++-- .../aot/TestContextAotGeneratorTests.java | 12 ++++++---- .../samples/web/WebSpringJupiterTests.java | 14 ++++++++++-- .../aot/samples/web/WebTestConfiguration.java | 13 ++++++++--- src/checkstyle/checkstyle-suppressions.xml | 1 + 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java index 15cef335058..0f0dc0d1914 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java @@ -42,6 +42,7 @@ import org.springframework.test.context.ContextLoader; import org.springframework.test.context.MergedContextConfiguration; import org.springframework.test.context.SmartContextLoader; import org.springframework.test.context.TestContextBootstrapper; +import org.springframework.test.context.web.WebMergedContextConfiguration; import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -60,6 +61,8 @@ import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX; */ public class TestContextAotGenerator { + private static final String SLASH = "/"; + private static final Log logger = LogFactory.getLog(TestContextAotGenerator.class); private final ApplicationContextAotGenerator aotGenerator = new ApplicationContextAotGenerator(); @@ -251,6 +254,21 @@ public class TestContextAotGenerator { // @TestPropertySource(locations = ... ) registerHintsForClasspathResources(mergedConfig.getPropertySourceLocations()); + + if (mergedConfig instanceof WebMergedContextConfiguration webMergedConfig) { + String resourceBasePath = webMergedConfig.getResourceBasePath(); + if (resourceBasePath.startsWith(CLASSPATH_URL_PREFIX)) { + String pattern = resourceBasePath.substring(CLASSPATH_URL_PREFIX.length()); + if (!pattern.startsWith(SLASH)) { + pattern = SLASH + pattern; + } + if (!pattern.endsWith(SLASH)) { + pattern += SLASH; + } + pattern += "*"; + this.runtimeHints.resources().registerPattern(pattern); + } + } } private void registerHintsForClasspathResources(String... locations) { @@ -258,8 +276,8 @@ public class TestContextAotGenerator { .filter(location -> location.startsWith(CLASSPATH_URL_PREFIX)) .map(location -> { location = location.substring(CLASSPATH_URL_PREFIX.length()); - if (!location.startsWith("/")) { - location = "/" + location; + if (!location.startsWith(SLASH)) { + location = SLASH + location; } return location; }) diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java b/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java index 7952d33b4a4..114aa62581d 100644 --- a/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java @@ -172,9 +172,13 @@ class TestContextAotGeneratorTests extends AbstractAotTests { assertThat(resource().forResource("/org/springframework/test/context/aot/samples/xml/test-config.xml")) .accepts(runtimeHints); - // @TestPropertySource(locations = ... ) + // @TestPropertySource(locations = ...) assertThat(resource().forResource("/org/springframework/test/context/aot/samples/basic/BasicSpringVintageTests.properties")) .accepts(runtimeHints); + + // @WebAppConfiguration(value = ...) + assertThat(resource().forResource("/META-INF/web-resources/resources/Spring.js")).accepts(runtimeHints); + assertThat(resource().forResource("/META-INF/web-resources/WEB-INF/views/home.jsp")).accepts(runtimeHints); } private static void assertReflectionRegistered(RuntimeHints runtimeHints, String type, MemberCategory memberCategory) { @@ -328,9 +332,9 @@ class TestContextAotGeneratorTests extends AbstractAotTests { "org/springframework/test/context/aot/samples/web/WebSpringJupiterTests__TestContext005_ApplicationContextInitializer.java", "org/springframework/test/context/aot/samples/web/WebSpringJupiterTests__TestContext005_BeanFactoryRegistrations.java", "org/springframework/test/context/aot/samples/web/WebTestConfiguration__TestContext005_BeanDefinitions.java", - "org/springframework/web/reactive/config/DelegatingWebFluxConfiguration__TestContext005_Autowiring.java", - "org/springframework/web/reactive/config/DelegatingWebFluxConfiguration__TestContext005_BeanDefinitions.java", - "org/springframework/web/reactive/config/WebFluxConfigurationSupport__TestContext005_BeanDefinitions.java", + "org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration__TestContext005_Autowiring.java", + "org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration__TestContext005_BeanDefinitions.java", + "org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport__TestContext005_BeanDefinitions.java", // XmlSpringJupiterTests "org/springframework/context/event/DefaultEventListenerFactory__TestContext006_BeanDefinitions.java", "org/springframework/context/event/EventListenerMethodProcessor__TestContext006_BeanDefinitions.java", diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/samples/web/WebSpringJupiterTests.java b/spring-test/src/test/java/org/springframework/test/context/aot/samples/web/WebSpringJupiterTests.java index fb46611987b..0db71791319 100644 --- a/spring-test/src/test/java/org/springframework/test/context/aot/samples/web/WebSpringJupiterTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/aot/samples/web/WebSpringJupiterTests.java @@ -24,6 +24,7 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.context.WebApplicationContext; import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -33,7 +34,7 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC * @author Sam Brannen * @since 6.0 */ -@SpringJUnitWebConfig(WebTestConfiguration.class) +@SpringJUnitWebConfig(classes = WebTestConfiguration.class, resourcePath = "classpath:META-INF/web-resources") @TestPropertySource(properties = "test.engine = jupiter") public class WebSpringJupiterTests { @@ -49,7 +50,7 @@ public class WebSpringJupiterTests { } @org.junit.jupiter.api.Test - void test(@Value("${test.engine}") String testEngine) throws Exception { + void controller(@Value("${test.engine}") String testEngine) throws Exception { assertThat(testEngine) .as("@Value").isEqualTo("jupiter"); assertThat(wac.getEnvironment().getProperty("test.engine")) @@ -59,4 +60,13 @@ public class WebSpringJupiterTests { .andExpectAll(status().isOk(), content().string("Hello, AOT!")); } + @org.junit.jupiter.api.Test + void resources() throws Exception { + this.mockMvc.perform(get("/resources/Spring.js")) + .andExpectAll( + content().contentType("application/javascript"), + content().string(containsString("Spring={};")) + ); + } + } diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/samples/web/WebTestConfiguration.java b/spring-test/src/test/java/org/springframework/test/context/aot/samples/web/WebTestConfiguration.java index d7256dc13c5..6502e3c541a 100644 --- a/spring-test/src/test/java/org/springframework/test/context/aot/samples/web/WebTestConfiguration.java +++ b/spring-test/src/test/java/org/springframework/test/context/aot/samples/web/WebTestConfiguration.java @@ -18,19 +18,26 @@ package org.springframework.test.context.aot.samples.web; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.reactive.config.EnableWebFlux; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @author Sam Brannen * @since 6.0 */ @Configuration(proxyBeanMethods = false) -@EnableWebFlux -class WebTestConfiguration { +@EnableWebMvc +class WebTestConfiguration implements WebMvcConfigurer { @Bean MessageController messageController() { return new MessageController(); } + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/resources/**").addResourceLocations("/resources/"); + } + } diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index 0d1abc60e80..d4bb6c256fa 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -88,6 +88,7 @@ +