diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml
index 4247b8a93a..29791145aa 100644
--- a/spring-boot-project/spring-boot-dependencies/pom.xml
+++ b/spring-boot-project/spring-boot-dependencies/pom.xml
@@ -165,7 +165,7 @@
1.23
7.7.2
- 5.1.9.RELEASE
+ 5.1.10.BUILD-SNAPSHOT
2.1.8.RELEASE
4.1.2.RELEASE
2.0.6.RELEASE
diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolver.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolver.java
index d915ac01eb..5cceb7bc60 100644
--- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolver.java
+++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolver.java
@@ -22,8 +22,10 @@ import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
+import java.util.function.Supplier;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;
@@ -31,6 +33,7 @@ import org.springframework.boot.devtools.restart.classloader.ClassLoaderFileURLS
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceFolder;
import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.io.AbstractResource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ProtocolResolver;
@@ -67,7 +70,8 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
private final ClassLoaderFiles classLoaderFiles;
- ClassLoaderFilesResourcePatternResolver(ApplicationContext applicationContext, ClassLoaderFiles classLoaderFiles) {
+ ClassLoaderFilesResourcePatternResolver(AbstractApplicationContext applicationContext,
+ ClassLoaderFiles classLoaderFiles) {
this.classLoaderFiles = classLoaderFiles;
this.patternResolverDelegate = getResourcePatternResolverFactory()
.getResourcePatternResolver(applicationContext, retrieveResourceLoader(applicationContext));
@@ -195,28 +199,11 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
*/
private static class ResourcePatternResolverFactory {
- public ResourcePatternResolver getResourcePatternResolver(ApplicationContext applicationContext,
+ public ResourcePatternResolver getResourcePatternResolver(AbstractApplicationContext applicationContext,
ResourceLoader resourceLoader) {
- if (resourceLoader == null) {
- resourceLoader = new DefaultResourceLoader();
- copyProtocolResolvers(applicationContext, resourceLoader);
- }
- return new PathMatchingResourcePatternResolver(resourceLoader);
- }
-
- protected final void copyProtocolResolvers(ApplicationContext applicationContext,
- ResourceLoader resourceLoader) {
- if (applicationContext instanceof DefaultResourceLoader
- && resourceLoader instanceof DefaultResourceLoader) {
- copyProtocolResolvers((DefaultResourceLoader) applicationContext,
- (DefaultResourceLoader) resourceLoader);
- }
- }
-
- protected final void copyProtocolResolvers(DefaultResourceLoader source, DefaultResourceLoader destination) {
- for (ProtocolResolver resolver : source.getProtocolResolvers()) {
- destination.addProtocolResolver(resolver);
- }
+ ResourceLoader targetResourceLoader = (resourceLoader != null) ? resourceLoader
+ : new ApplicationContextResourceLoader(applicationContext::getProtocolResolvers);
+ return new PathMatchingResourcePatternResolver(targetResourceLoader);
}
}
@@ -228,22 +215,35 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
private static class WebResourcePatternResolverFactory extends ResourcePatternResolverFactory {
@Override
- public ResourcePatternResolver getResourcePatternResolver(ApplicationContext applicationContext,
+ public ResourcePatternResolver getResourcePatternResolver(AbstractApplicationContext applicationContext,
ResourceLoader resourceLoader) {
if (applicationContext instanceof WebApplicationContext) {
- return getResourcePatternResolver((WebApplicationContext) applicationContext, resourceLoader);
+ return getServletContextResourcePatternResolver(applicationContext, resourceLoader);
}
return super.getResourcePatternResolver(applicationContext, resourceLoader);
}
- private ResourcePatternResolver getResourcePatternResolver(WebApplicationContext applicationContext,
- ResourceLoader resourceLoader) {
- if (resourceLoader == null) {
- resourceLoader = new WebApplicationContextResourceLoader(applicationContext);
- copyProtocolResolvers(applicationContext, resourceLoader);
- }
- return new ServletContextResourcePatternResolver(resourceLoader);
+ private ResourcePatternResolver getServletContextResourcePatternResolver(
+ AbstractApplicationContext applicationContext, ResourceLoader resourceLoader) {
+ ResourceLoader targetResourceLoader = (resourceLoader != null) ? resourceLoader
+ : new WebApplicationContextResourceLoader(applicationContext::getProtocolResolvers,
+ (WebApplicationContext) applicationContext);
+ return new ServletContextResourcePatternResolver(targetResourceLoader);
+ }
+ }
+
+ private static class ApplicationContextResourceLoader extends DefaultResourceLoader {
+
+ private final Supplier> protocolResolvers;
+
+ ApplicationContextResourceLoader(Supplier> protocolResolvers) {
+ this.protocolResolvers = protocolResolvers;
+ }
+
+ @Override
+ public Collection getProtocolResolvers() {
+ return this.protocolResolvers.get();
}
}
@@ -252,11 +252,13 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
* {@link ResourceLoader} that optionally supports {@link ServletContextResource
* ServletContextResources}.
*/
- private static class WebApplicationContextResourceLoader extends DefaultResourceLoader {
+ private static class WebApplicationContextResourceLoader extends ApplicationContextResourceLoader {
private final WebApplicationContext applicationContext;
- WebApplicationContextResourceLoader(WebApplicationContext applicationContext) {
+ WebApplicationContextResourceLoader(Supplier> protocolResolvers,
+ WebApplicationContext applicationContext) {
+ super(protocolResolvers);
this.applicationContext = applicationContext;
}
diff --git a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolverTests.java b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolverTests.java
index 7cdfcedc5f..a2a9156330 100644
--- a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolverTests.java
+++ b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolverTests.java
@@ -134,6 +134,18 @@ public class ClassLoaderFilesResourcePatternResolverTests {
verify(resolver).resolve(eq("foo:some-file.txt"), any(ResourceLoader.class));
}
+ @Test
+ public void customProtocolResolverRegisteredAfterCreationIsUsedInNonWebApplication() {
+ GenericApplicationContext context = new GenericApplicationContext();
+ Resource resource = mock(Resource.class);
+ this.resolver = new ClassLoaderFilesResourcePatternResolver(context, this.files);
+ ProtocolResolver resolver = mockProtocolResolver("foo:some-file.txt", resource);
+ context.addProtocolResolver(resolver);
+ Resource actual = this.resolver.getResource("foo:some-file.txt");
+ assertThat(actual).isSameAs(resource);
+ verify(resolver).resolve(eq("foo:some-file.txt"), any(ResourceLoader.class));
+ }
+
@Test
public void customResourceLoaderIsUsedInWebApplication() {
GenericWebApplicationContext context = new GenericWebApplicationContext(new MockServletContext());
@@ -156,6 +168,18 @@ public class ClassLoaderFilesResourcePatternResolverTests {
verify(resolver).resolve(eq("foo:some-file.txt"), any(ResourceLoader.class));
}
+ @Test
+ public void customProtocolResolverRegisteredAfterCreationIsUsedInWebApplication() {
+ GenericWebApplicationContext context = new GenericWebApplicationContext(new MockServletContext());
+ Resource resource = mock(Resource.class);
+ this.resolver = new ClassLoaderFilesResourcePatternResolver(context, this.files);
+ ProtocolResolver resolver = mockProtocolResolver("foo:some-file.txt", resource);
+ context.addProtocolResolver(resolver);
+ Resource actual = this.resolver.getResource("foo:some-file.txt");
+ assertThat(actual).isSameAs(resource);
+ verify(resolver).resolve(eq("foo:some-file.txt"), any(ResourceLoader.class));
+ }
+
private ProtocolResolver mockProtocolResolver(String path, Resource resource) {
ProtocolResolver resolver = mock(ProtocolResolver.class);
given(resolver.resolve(eq(path), any(ResourceLoader.class))).willReturn(resource);