There are two ways to configure Spring MVC resources - via the spring.web.resources
configuration, and the deprecated spring.resources
configuration.
With spring-boot 2.4.0, there is a bug where if Devtools is enabled, spring.web.resources
is ignored and the deprecated configuration is read instead.
The WebMvcAutoConfiguration ostensibly only chooses the deprecated configuration if it's been customized, and falls back to the WebProperties Resources. However, one of Devtools' customizations (disabling spring.resources.chain.cache
) sets the "has been customized" flag and thus switches configurations out from under you.
I noticed this because static resources started 404'ing with Devtools enabled, but worked fine without. Switching to the deprecated configuration fixes the issue, but is clearly an undesirable solution.
This can be observed in the following test case. Note that Devtools turns itself off in tests and this can't be bypassed, but setting the spring.resources.chain.cache=false
simulates its modification.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = {
"spring.web.resources.static-locations=file:" + DevToolsWebResourceTest.tmpDir,
// uncomment the following line to simulate devtools' change and break static resource resolution
// "spring.resources.chain.cache=false"
}
)
class DevToolsWebResourceTest {
static final String tmpDir = "/tmp";
private static final String content = "Hello, world";
private static final String resource = "hello" + System.currentTimeMillis() + ".txt";
private static final Path path = Path.of(tmpDir, resource);
@BeforeAll
static void setUp() throws Exception {
Files.writeString(path, content);
}
@AfterAll
static void tearDown() throws Exception {
Files.delete(path);
}
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void staticResource() {
final String s = restTemplate
.getForObject("http://localhost:" + port + "/" + resource, String.class);
assertEquals(content, s);
}
}
Comment From: wilkinsona
I think this may be a duplicate of #24203.
Comment From: snicoll
I thought the same Andy but this test is failing for me with 2.4.1-SNAPSHOT
.
Comment From: snicoll
Courtesy of @wilkinsona for reminding me. With spring.web.resources.static-locations
and spring.web.resources.chain.cache
this test passes. You can't mix and match deprecated properties with the new namespace. So it looks like indeed this was fixed via #24203.
@chrisrhut please give your actual project a try with 2.4.1-SNAPSHOT
. If that still failing we can reopen but we'd need more details. Thanks!
Comment From: chrisrhut
Thank you very much for the quick response, @wilkinsona and @snicoll - I confirmed 2.4.1-SNAPSHOT
works in my application :pray:
Comment From: snicoll
Thank you very much for checking @chrisrhut.