Merge branch '2.1.x'

Closes gh-18239
pull/18244/head
Stephane Nicoll 5 years ago
commit 81ddebbc27

@ -22,8 +22,10 @@ import java.lang.reflect.Field;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map.Entry; 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;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind; 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;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceFolder; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceFolder;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.io.AbstractResource; import org.springframework.core.io.AbstractResource;
import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ProtocolResolver; import org.springframework.core.io.ProtocolResolver;
@ -67,7 +70,8 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
private final ClassLoaderFiles classLoaderFiles; private final ClassLoaderFiles classLoaderFiles;
ClassLoaderFilesResourcePatternResolver(ApplicationContext applicationContext, ClassLoaderFiles classLoaderFiles) { ClassLoaderFilesResourcePatternResolver(AbstractApplicationContext applicationContext,
ClassLoaderFiles classLoaderFiles) {
this.classLoaderFiles = classLoaderFiles; this.classLoaderFiles = classLoaderFiles;
this.patternResolverDelegate = getResourcePatternResolverFactory() this.patternResolverDelegate = getResourcePatternResolverFactory()
.getResourcePatternResolver(applicationContext, retrieveResourceLoader(applicationContext)); .getResourcePatternResolver(applicationContext, retrieveResourceLoader(applicationContext));
@ -195,28 +199,11 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
*/ */
private static class ResourcePatternResolverFactory { private static class ResourcePatternResolverFactory {
ResourcePatternResolver getResourcePatternResolver(ApplicationContext applicationContext, ResourcePatternResolver getResourcePatternResolver(AbstractApplicationContext applicationContext,
ResourceLoader resourceLoader) { ResourceLoader resourceLoader) {
if (resourceLoader == null) { ResourceLoader targetResourceLoader = (resourceLoader != null) ? resourceLoader
resourceLoader = new DefaultResourceLoader(); : new ApplicationContextResourceLoader(applicationContext::getProtocolResolvers);
copyProtocolResolvers(applicationContext, resourceLoader); return new PathMatchingResourcePatternResolver(targetResourceLoader);
}
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);
}
} }
} }
@ -228,21 +215,35 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
private static class WebResourcePatternResolverFactory extends ResourcePatternResolverFactory { private static class WebResourcePatternResolverFactory extends ResourcePatternResolverFactory {
@Override @Override
public ResourcePatternResolver getResourcePatternResolver(ApplicationContext applicationContext, public ResourcePatternResolver getResourcePatternResolver(AbstractApplicationContext applicationContext,
ResourceLoader resourceLoader) { ResourceLoader resourceLoader) {
if (applicationContext instanceof WebApplicationContext) { if (applicationContext instanceof WebApplicationContext) {
return getResourcePatternResolver((WebApplicationContext) applicationContext, resourceLoader); return getServletContextResourcePatternResolver(applicationContext, resourceLoader);
} }
return super.getResourcePatternResolver(applicationContext, resourceLoader); return super.getResourcePatternResolver(applicationContext, resourceLoader);
} }
private ResourcePatternResolver getResourcePatternResolver(WebApplicationContext applicationContext, private ResourcePatternResolver getServletContextResourcePatternResolver(
ResourceLoader resourceLoader) { AbstractApplicationContext applicationContext, ResourceLoader resourceLoader) {
if (resourceLoader == null) { ResourceLoader targetResourceLoader = (resourceLoader != null) ? resourceLoader
resourceLoader = new WebApplicationContextResourceLoader(applicationContext); : new WebApplicationContextResourceLoader(applicationContext::getProtocolResolvers,
copyProtocolResolvers(applicationContext, resourceLoader); (WebApplicationContext) applicationContext);
return new ServletContextResourcePatternResolver(targetResourceLoader);
} }
return new ServletContextResourcePatternResolver(resourceLoader);
}
private static class ApplicationContextResourceLoader extends DefaultResourceLoader {
private final Supplier<Collection<ProtocolResolver>> protocolResolvers;
ApplicationContextResourceLoader(Supplier<Collection<ProtocolResolver>> protocolResolvers) {
this.protocolResolvers = protocolResolvers;
}
@Override
public Collection<ProtocolResolver> getProtocolResolvers() {
return this.protocolResolvers.get();
} }
} }
@ -251,11 +252,13 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
* {@link ResourceLoader} that optionally supports {@link ServletContextResource * {@link ResourceLoader} that optionally supports {@link ServletContextResource
* ServletContextResources}. * ServletContextResources}.
*/ */
private static class WebApplicationContextResourceLoader extends DefaultResourceLoader { private static class WebApplicationContextResourceLoader extends ApplicationContextResourceLoader {
private final WebApplicationContext applicationContext; private final WebApplicationContext applicationContext;
WebApplicationContextResourceLoader(WebApplicationContext applicationContext) { WebApplicationContextResourceLoader(Supplier<Collection<ProtocolResolver>> protocolResolvers,
WebApplicationContext applicationContext) {
super(protocolResolvers);
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
} }

@ -127,6 +127,18 @@ class ClassLoaderFilesResourcePatternResolverTests {
verify(resolver).resolve(eq("foo:some-file.txt"), any(ResourceLoader.class)); verify(resolver).resolve(eq("foo:some-file.txt"), any(ResourceLoader.class));
} }
@Test
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 @Test
void customResourceLoaderIsUsedInWebApplication() { void customResourceLoaderIsUsedInWebApplication() {
GenericWebApplicationContext context = new GenericWebApplicationContext(new MockServletContext()); GenericWebApplicationContext context = new GenericWebApplicationContext(new MockServletContext());
@ -149,6 +161,18 @@ class ClassLoaderFilesResourcePatternResolverTests {
verify(resolver).resolve(eq("foo:some-file.txt"), any(ResourceLoader.class)); verify(resolver).resolve(eq("foo:some-file.txt"), any(ResourceLoader.class));
} }
@Test
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) { private ProtocolResolver mockProtocolResolver(String path, Resource resource) {
ProtocolResolver resolver = mock(ProtocolResolver.class); ProtocolResolver resolver = mock(ProtocolResolver.class);
given(resolver.resolve(eq(path), any(ResourceLoader.class))).willReturn(resource); given(resolver.resolve(eq(path), any(ResourceLoader.class))).willReturn(resource);

Loading…
Cancel
Save