diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/ClassFinder.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/ClassFinder.java index 9dccb291fb6..b8ec0ddc741 100644 --- a/hbase-common/src/test/java/org/apache/hadoop/hbase/ClassFinder.java +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/ClassFinder.java @@ -49,6 +49,7 @@ public class ClassFinder { private FileNameFilter fileNameFilter; private ClassFilter classFilter; private FileFilter fileFilter; + private ClassLoader classLoader; public interface ResourcePathFilter { boolean isCandidatePath(String resourcePath, boolean isJar); @@ -114,16 +115,27 @@ public class ClassFinder { } } - public ClassFinder() { - this(null, null, null); + // To control which classloader to use while trying to find jars/classes + public ClassFinder(ClassLoader classLoader) { + this(null, null, null, classLoader); } - public ClassFinder(ResourcePathFilter resourcePathFilter, - FileNameFilter fileNameFilter, ClassFilter classFilter) { + public ClassFinder() { + this(ClassLoader.getSystemClassLoader()); + } + + public ClassFinder(ResourcePathFilter resourcePathFilter, FileNameFilter fileNameFilter, + ClassFilter classFilter) { + this(resourcePathFilter, fileNameFilter, classFilter, ClassLoader.getSystemClassLoader()); + } + + public ClassFinder(ResourcePathFilter resourcePathFilter, FileNameFilter fileNameFilter, + ClassFilter classFilter, ClassLoader classLoader) { this.resourcePathFilter = resourcePathFilter; this.classFilter = classFilter; this.fileNameFilter = fileNameFilter; this.fileFilter = new FileFilterWithName(fileNameFilter); + this.classLoader = classLoader; } /** @@ -147,7 +159,7 @@ public class ClassFinder { final String path = packageName.replace('.', '/'); final Pattern jarResourceRe = Pattern.compile("^file:(.+\\.jar)!/" + path + "$"); - Enumeration resources = ClassLoader.getSystemClassLoader().getResources(path); + Enumeration resources = this.classLoader.getResources(path); List dirs = new ArrayList<>(); List jars = new ArrayList<>(); @@ -270,7 +282,7 @@ public class ClassFinder { private Class makeClass(String className, boolean proceedOnExceptions) throws ClassNotFoundException, LinkageError { try { - Class c = Class.forName(className, false, this.getClass().getClassLoader()); + Class c = Class.forName(className, false, classLoader); boolean isCandidateClass = null == classFilter || classFilter.isCandidateClass(c); return isCandidateClass ? c : null; } catch (NoClassDefFoundError|ClassNotFoundException classNotFoundEx) { diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/TestClassFinder.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/TestClassFinder.java index 0b17359eb1f..21a092b0665 100644 --- a/hbase-common/src/test/java/org/apache/hadoop/hbase/TestClassFinder.java +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/TestClassFinder.java @@ -27,7 +27,6 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; -import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.HashSet; @@ -73,6 +72,8 @@ public class TestClassFinder { private static String basePath = null; + private static CustomClassloader classLoader; + @BeforeClass public static void createTestDir() throws IOException { basePath = testUtil.getDataTestDir(TestClassFinder.class.getSimpleName()).toString(); @@ -86,6 +87,8 @@ public class TestClassFinder { } assertTrue(testDir.mkdirs()); LOG.info("Using new, clean directory=" + testDir); + + classLoader = new CustomClassloader(new URL[0], ClassLoader.getSystemClassLoader()); } @AfterClass @@ -102,7 +105,7 @@ public class TestClassFinder { packageAndLoadJar(c1, c3); packageAndLoadJar(c2); - ClassFinder allClassesFinder = new ClassFinder(); + ClassFinder allClassesFinder = new ClassFinder(classLoader); Set> allClasses = allClassesFinder.findClasses( makePackageName("", counter), false); assertEquals(3, allClasses.size()); @@ -116,7 +119,7 @@ public class TestClassFinder { packageAndLoadJar(c1, c2); packageAndLoadJar(c1); - ClassFinder allClassesFinder = new ClassFinder(); + ClassFinder allClassesFinder = new ClassFinder(classLoader); Set> allClasses = allClassesFinder.findClasses( makePackageName("", counter), false); assertEquals(2, allClasses.size()); @@ -134,7 +137,7 @@ public class TestClassFinder { packageAndLoadJar(c1, c2); packageAndLoadJar(c3); - ClassFinder allClassesFinder = new ClassFinder(); + ClassFinder allClassesFinder = new ClassFinder(classLoader); Set> nestedClasses = allClassesFinder.findClasses( makePackageName(NESTED, counter), false); assertEquals(2, nestedClasses.size()); @@ -156,7 +159,7 @@ public class TestClassFinder { return !fileName.startsWith(PREFIX); } }; - ClassFinder incClassesFinder = new ClassFinder(null, notExcNameFilter, null); + ClassFinder incClassesFinder = new ClassFinder(null, notExcNameFilter, null, classLoader); Set> incClasses = incClassesFinder.findClasses( makePackageName("", counter), false); assertEquals(1, incClasses.size()); @@ -176,7 +179,7 @@ public class TestClassFinder { return !c.getSimpleName().startsWith(PREFIX); } }; - ClassFinder incClassesFinder = new ClassFinder(null, null, notExcClassFilter); + ClassFinder incClassesFinder = new ClassFinder(null, null, notExcClassFilter, classLoader); Set> incClasses = incClassesFinder.findClasses( makePackageName("", counter), false); assertEquals(1, incClasses.size()); @@ -215,7 +218,7 @@ public class TestClassFinder { return !isJar || !resourcePath.equals(excludedJarResource); } }; - ClassFinder incClassesFinder = new ClassFinder(notExcJarFilter, null, null); + ClassFinder incClassesFinder = new ClassFinder(notExcJarFilter, null, null, classLoader); Set> incClasses = incClassesFinder.findClasses( makePackageName("", counter), false); assertEquals(1, incClasses.size()); @@ -231,7 +234,7 @@ public class TestClassFinder { final String classNamePrefix = name.getMethodName(); String pkgNameSuffix = name.getMethodName(); LOG.info("Created jar " + createAndLoadJar(pkgNameSuffix, classNamePrefix, counter)); - ClassFinder allClassesFinder = new ClassFinder(); + ClassFinder allClassesFinder = new ClassFinder(classLoader); String pkgName = makePackageName(pkgNameSuffix, counter); Set> allClasses = allClassesFinder.findClasses(pkgName, false); assertTrue("Classes in " + pkgName, allClasses.size() > 0); @@ -262,10 +265,10 @@ public class TestClassFinder { } }; String pkgName = makePackageName(pkgNameSuffix, counter); - ClassFinder allClassesFinder = new ClassFinder(); + ClassFinder allClassesFinder = new ClassFinder(classLoader); Set> allClasses = allClassesFinder.findClasses(pkgName, false); assertTrue("Classes in " + pkgName, allClasses.size() > 0); - ClassFinder notThisClassFinder = new ClassFinder(null, notThisFilter, null); + ClassFinder notThisClassFinder = new ClassFinder(null, notThisFilter, null, classLoader); Set> notAllClasses = notThisClassFinder.findClasses(pkgName, false); assertFalse(contains(notAllClasses, classNameToFilterOut)); assertEquals(allClasses.size() - 1, notAllClasses.size()); @@ -287,10 +290,10 @@ public class TestClassFinder { } }; String pkgName = makePackageName(pkgNameSuffix, counter); - ClassFinder allClassesFinder = new ClassFinder(); + ClassFinder allClassesFinder = new ClassFinder(classLoader); Set> allClasses = allClassesFinder.findClasses(pkgName, false); assertTrue("Classes in " + pkgName, allClasses.size() > 0); - ClassFinder notThisClassFinder = new ClassFinder(null, null, notThisFilter); + ClassFinder notThisClassFinder = new ClassFinder(null, null, notThisFilter, classLoader); Set> notAllClasses = notThisClassFinder.findClasses(pkgName, false); assertFalse(contains(notAllClasses, clazz.getSimpleName())); assertEquals(allClasses.size() - 1, notAllClasses.size()); @@ -307,7 +310,7 @@ public class TestClassFinder { } }; String thisPackage = this.getClass().getPackage().getName(); - ClassFinder notThisClassFinder = new ClassFinder(notExcJarFilter, null, null); + ClassFinder notThisClassFinder = new ClassFinder(notExcJarFilter, null, null, classLoader); Set> notAllClasses = notThisClassFinder.findClasses(thisPackage, false); assertFalse(notAllClasses.contains(this.getClass())); } @@ -316,7 +319,7 @@ public class TestClassFinder { public void testClassFinderDefaultsToOwnPackage() throws Exception { // Correct handling of nested packages is tested elsewhere, so here we just assume // pkgClasses is the correct answer that we don't have to check. - ClassFinder allClassesFinder = new ClassFinder(); + ClassFinder allClassesFinder = new ClassFinder(classLoader); Set> pkgClasses = allClassesFinder.findClasses( ClassFinder.class.getPackage().getName(), false); Set> defaultClasses = allClassesFinder.findClasses(false); @@ -334,8 +337,8 @@ public class TestClassFinder { private static Class makeClass(String nestedPkgSuffix, String className, long counter) throws ClassNotFoundException { - return Class.forName( - makePackageName(nestedPkgSuffix, counter) + "." + className + counter); + String name = makePackageName(nestedPkgSuffix, counter) + "." + className + counter; + return Class.forName(name, true, classLoader); } private static String makePackageName(String nestedSuffix, long counter) { @@ -415,11 +418,19 @@ public class TestClassFinder { // Add the file to classpath. File jarFile = new File(path); assertTrue(jarFile.exists()); - URLClassLoader urlClassLoader = (URLClassLoader)ClassLoader.getSystemClassLoader(); - Method method = URLClassLoader.class - .getDeclaredMethod("addURL", new Class[] { URL.class }); - method.setAccessible(true); - method.invoke(urlClassLoader, new Object[] { jarFile.toURI().toURL() }); + classLoader.addURL(jarFile.toURI().toURL()); return jarFile.getAbsolutePath(); } + + // Java 11 workaround - Custom class loader to expose addUrl method of URLClassLoader + private static class CustomClassloader extends URLClassLoader { + + public CustomClassloader(URL[] urls, ClassLoader parentLoader) { + super(urls, parentLoader); + } + + public void addURL(URL url) { + super.addURL(url); + } + } }