From d3ca1a7b0e4c624267ef1b0c5a1c8400ac4ed2fa Mon Sep 17 00:00:00 2001 From: Roy Jacobs Date: Wed, 10 Oct 2018 16:46:01 +0200 Subject: [PATCH] Allow ClassPathResources to be filtered by FilteredClassLoader See gh-14774 --- .../test/context/FilteredClassLoader.java | 56 ++++++++++++++++++- .../context/FilteredClassLoaderTests.java | 26 +++++++++ .../FilteredClassLoaderTestResource.txt | 1 + 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 spring-boot-project/spring-boot-test/src/test/resources/org/springframework/boot/test/context/FilteredClassLoaderTestResource.txt diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/FilteredClassLoader.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/FilteredClassLoader.java index d222aa5cda7..ce12d524e5b 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/FilteredClassLoader.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/FilteredClassLoader.java @@ -20,12 +20,15 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.function.Predicate; +import org.springframework.core.io.ClassPathResource; + /** - * Test {@link URLClassLoader} that can filter the classes it can load. + * Test {@link URLClassLoader} that can filter the classes and resources it can load. * * @author Andy Wilkinson * @author Stephane Nicoll * @author Phillip Webb + * @author Roy Jacobs * @since 2.0.0 */ public class FilteredClassLoader extends URLClassLoader { @@ -48,10 +51,19 @@ public class FilteredClassLoader extends URLClassLoader { this(PackageFilter.of(hiddenPackages)); } + /** + * Create a {@link FilteredClassLoader} that hides resources from the given packages. + * @param hiddenResources the resources to hide + */ + public FilteredClassLoader(ClassPathResource... hiddenResources) { + this(ClassPathResourceFilter.of(hiddenResources)); + } + /** * Create a {@link FilteredClassLoader} that filters based on the given predicate. - * @param filters a set of filters to determine when a class name should be hidden. A - * {@link Predicate#test(Object) result} of {@code true} indicates a filtered class. + * @param filters a set of filters to determine when a class name or resource should + * be hidden. A {@link Predicate#test(Object) result} of {@code true} indicates a + * filtered class or resource. */ @SafeVarargs public FilteredClassLoader(Predicate... filters) { @@ -70,6 +82,16 @@ public class FilteredClassLoader extends URLClassLoader { return super.loadClass(name, resolve); } + @Override + public URL getResource(String name) { + for (Predicate filter : this.filters) { + if (filter.test(name)) { + return null; + } + } + return super.getResource(name); + } + /** * Filter to restrict the classes that can be loaded. */ @@ -124,4 +146,32 @@ public class FilteredClassLoader extends URLClassLoader { } + /** + * Filter to restrict the resources that can be loaded. + */ + public static final class ClassPathResourceFilter implements Predicate { + + private final ClassPathResource[] hiddenResources; + + private ClassPathResourceFilter(ClassPathResource[] hiddenResources) { + this.hiddenResources = hiddenResources; + } + + @Override + public boolean test(String resourceName) { + for (ClassPathResource hiddenResource : this.hiddenResources) { + if (hiddenResource.getFilename() != null + && resourceName.equals(hiddenResource.getPath())) { + return true; + } + } + return false; + } + + public static ClassPathResourceFilter of(ClassPathResource... hiddenResources) { + return new ClassPathResourceFilter(hiddenResources); + } + + } + } diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/FilteredClassLoaderTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/FilteredClassLoaderTests.java index 1422f1e3a40..6034e75e4f7 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/FilteredClassLoaderTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/FilteredClassLoaderTests.java @@ -16,8 +16,12 @@ package org.springframework.boot.test.context; +import java.net.URL; + import org.junit.Test; +import org.springframework.core.io.ClassPathResource; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -25,9 +29,13 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; * Tests for {@link FilteredClassLoader}. * * @author Phillip Webb + * @author Roy Jacobs */ public class FilteredClassLoaderTests { + private static ClassPathResource TEST_RESOURCE = new ClassPathResource( + "org/springframework/boot/test/context/FilteredClassLoaderTestResource.txt"); + @Test public void loadClassWhenFilteredOnPackageShouldThrowClassNotFound() throws Exception { @@ -55,4 +63,22 @@ public class FilteredClassLoaderTests { classLoader.close(); } + @Test + public void loadResourceWhenFilteredOnResourceShouldReturnNotFound() + throws Exception { + try (FilteredClassLoader classLoader = new FilteredClassLoader(TEST_RESOURCE)) { + final URL loaded = classLoader.getResource(TEST_RESOURCE.getPath()); + assertThat(loaded).isNull(); + } + } + + @Test + public void loadResourceWhenNotFilteredShouldLoadResource() throws Exception { + try (FilteredClassLoader classLoader = new FilteredClassLoader( + (resourceName) -> false)) { + final URL loaded = classLoader.getResource(TEST_RESOURCE.getPath()); + assertThat(loaded).isNotNull(); + } + } + } diff --git a/spring-boot-project/spring-boot-test/src/test/resources/org/springframework/boot/test/context/FilteredClassLoaderTestResource.txt b/spring-boot-project/spring-boot-test/src/test/resources/org/springframework/boot/test/context/FilteredClassLoaderTestResource.txt new file mode 100644 index 00000000000..5c1b88e1a7e --- /dev/null +++ b/spring-boot-project/spring-boot-test/src/test/resources/org/springframework/boot/test/context/FilteredClassLoaderTestResource.txt @@ -0,0 +1 @@ +Used by FilteredClassLoaderTests.java \ No newline at end of file