Skip to content

Commit 98b2b5f

Browse files
nosanphilwebb
authored andcommitted
Improve ApplicationResourceLoader preferFileResolution support
Update `ApplicationResourceLoader` so that the `preferFileResolution` flag now also supports `FilteredReactiveWebContextResource`. See gh-44535 Signed-off-by: Dmytro Nosan <[email protected]>
1 parent 80632bd commit 98b2b5f

File tree

2 files changed

+66
-19
lines changed

2 files changed

+66
-19
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/io/ApplicationResourceLoader.java

+45-19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -132,8 +132,8 @@ public static ResourceLoader get(ResourceLoader resourceLoader) {
132132
* class loader at the time this call is made.
133133
* @param resourceLoader the delegate resource loader
134134
* @param preferFileResolution if file based resolution is preferred over
135-
* {@code ServletContextResource} or {@link ClassPathResource} when no resource prefix
136-
* is provided.
135+
* {@code ServletContextResource}, {@code FilteredReactiveWebContextResource} or
136+
* {@link ClassPathResource} when no resource prefix is provided.
137137
* @return a {@link ResourceLoader} instance
138138
* @since 3.4.1
139139
*/
@@ -212,28 +212,31 @@ private static class ProtocolResolvingResourceLoader implements ResourceLoader {
212212

213213
private static final String SERVLET_CONTEXT_RESOURCE_CLASS_NAME = "org.springframework.web.context.support.ServletContextResource";
214214

215+
private static final String FILTERED_REACTIVE_WEB_CONTEXT_RESOURCE_CLASS_NAME = "org.springframework.boot.web.reactive.context.FilteredReactiveWebContextResource";
216+
215217
private final ResourceLoader resourceLoader;
216218

217219
private final List<ProtocolResolver> protocolResolvers;
218220

219221
private final boolean preferFileResolution;
220222

221-
private Class<?> servletContextResourceClass;
223+
private final Class<?> servletContextResourceClass;
224+
225+
private final Class<?> filteredReactiveWebContextResourceClass;
222226

223227
ProtocolResolvingResourceLoader(ResourceLoader resourceLoader, List<ProtocolResolver> protocolResolvers,
224228
boolean preferFileResolution) {
225229
this.resourceLoader = resourceLoader;
226230
this.protocolResolvers = protocolResolvers;
227231
this.preferFileResolution = preferFileResolution;
228-
this.servletContextResourceClass = resolveServletContextResourceClass(
229-
resourceLoader.getClass().getClassLoader());
232+
this.servletContextResourceClass = resolveServletContextResourceClass(resourceLoader);
233+
this.filteredReactiveWebContextResourceClass = resolveFilteredReactiveWebContextResourceClass(
234+
resourceLoader);
230235
}
231236

232-
private static Class<?> resolveServletContextResourceClass(ClassLoader classLoader) {
233-
if (!ClassUtils.isPresent(SERVLET_CONTEXT_RESOURCE_CLASS_NAME, classLoader)) {
234-
return null;
235-
}
236-
return ClassUtils.resolveClassName(SERVLET_CONTEXT_RESOURCE_CLASS_NAME, classLoader);
237+
@Override
238+
public ClassLoader getClassLoader() {
239+
return this.resourceLoader.getClassLoader();
237240
}
238241

239242
@Override
@@ -247,24 +250,47 @@ public Resource getResource(String location) {
247250
}
248251
}
249252
Resource resource = this.resourceLoader.getResource(location);
250-
if (this.preferFileResolution
251-
&& (isClassPathResourceByPath(location, resource) || isServletResource(resource))) {
252-
resource = new ApplicationResource(location);
253+
if (shouldUseFileResolution(location, resource)) {
254+
return new ApplicationResource(location);
253255
}
254256
return resource;
255257
}
256258

259+
private boolean shouldUseFileResolution(String location, Resource resource) {
260+
if (!this.preferFileResolution) {
261+
return false;
262+
}
263+
return isClassPathResourceByPath(location, resource) || isServletContextResource(resource)
264+
|| isFilteredReactiveWebContextResource(resource);
265+
}
266+
257267
private boolean isClassPathResourceByPath(String location, Resource resource) {
258268
return (resource instanceof ClassPathResource) && !location.startsWith(CLASSPATH_URL_PREFIX);
259269
}
260270

261-
private boolean isServletResource(Resource resource) {
262-
return this.servletContextResourceClass != null && this.servletContextResourceClass.isInstance(resource);
271+
private boolean isServletContextResource(Resource resource) {
272+
return (this.servletContextResourceClass != null) && this.servletContextResourceClass.isInstance(resource);
263273
}
264274

265-
@Override
266-
public ClassLoader getClassLoader() {
267-
return this.resourceLoader.getClassLoader();
275+
private boolean isFilteredReactiveWebContextResource(Resource resource) {
276+
return (this.filteredReactiveWebContextResourceClass != null)
277+
&& this.filteredReactiveWebContextResourceClass.isInstance(resource);
278+
}
279+
280+
private static Class<?> resolveServletContextResourceClass(ResourceLoader resourceLoader) {
281+
return resolveClassName(SERVLET_CONTEXT_RESOURCE_CLASS_NAME, resourceLoader.getClass().getClassLoader());
282+
}
283+
284+
private static Class<?> resolveFilteredReactiveWebContextResourceClass(ResourceLoader resourceLoader) {
285+
return resolveClassName(FILTERED_REACTIVE_WEB_CONTEXT_RESOURCE_CLASS_NAME,
286+
resourceLoader.getClass().getClassLoader());
287+
}
288+
289+
private static Class<?> resolveClassName(String clazz, ClassLoader classLoader) {
290+
if (!ClassUtils.isPresent(clazz, classLoader)) {
291+
return null;
292+
}
293+
return ClassUtils.resolveClassName(clazz, classLoader);
268294
}
269295

270296
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/io/ApplicationResourceLoaderTests.java

+21
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import org.springframework.boot.testsupport.classpath.resources.ResourcePath;
3131
import org.springframework.boot.testsupport.classpath.resources.WithResource;
32+
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
3233
import org.springframework.core.io.ByteArrayResource;
3334
import org.springframework.core.io.ClassPathResource;
3435
import org.springframework.core.io.DefaultResourceLoader;
@@ -37,6 +38,7 @@
3738
import org.springframework.core.io.ResourceLoader;
3839
import org.springframework.core.io.support.SpringFactoriesLoader;
3940
import org.springframework.mock.web.MockServletContext;
41+
import org.springframework.util.ClassUtils;
4042
import org.springframework.web.context.support.ServletContextResource;
4143
import org.springframework.web.context.support.ServletContextResourceLoader;
4244

@@ -209,6 +211,25 @@ void getResourceWithPreferFileResolutionWhenPathWithServletContextResource() thr
209211
assertThat(regularLoader.getResource("src/main/resources/a-file")).isInstanceOf(ServletContextResource.class);
210212
}
211213

214+
@Test
215+
void getResourceWhenFilteredReactiveWebContextResourceWithPreferFileResolution() throws Exception {
216+
ResourceLoader resourceLoader = ApplicationResourceLoader
217+
.get(new AnnotationConfigReactiveWebApplicationContext(), true);
218+
Resource resource = resourceLoader.getResource("src/main/resources/a-file");
219+
assertThat(resource).isInstanceOf(FileSystemResource.class);
220+
assertThat(resource.getFile().getAbsoluteFile())
221+
.isEqualTo(new File("src/main/resources/a-file").getAbsoluteFile());
222+
}
223+
224+
@Test
225+
void getResourceWhenFilteredReactiveWebContextResource() {
226+
ResourceLoader resourceLoader = ApplicationResourceLoader
227+
.get(new AnnotationConfigReactiveWebApplicationContext(), false);
228+
Resource resource = resourceLoader.getResource("src/main/resources/a-file");
229+
assertThat(resource).isInstanceOf(ClassUtils.resolveClassName(
230+
"org.springframework.boot.web.reactive.context.FilteredReactiveWebContextResource", null));
231+
}
232+
212233
@Test
213234
void getClassLoaderReturnsDelegateClassLoader() {
214235
ClassLoader classLoader = new TestClassLoader(this::useTestProtocolResolversFactories);

0 commit comments

Comments
 (0)