HBASE-22458: TestClassFinder fails when run on JDK11

Signed-off-by: Sean Busbey <busbey@apache.org>
This commit is contained in:
Sakthi 2019-06-04 17:14:47 -07:00 committed by Sean Busbey
parent c2cf06d0bf
commit 0445186f1a
2 changed files with 50 additions and 27 deletions

View File

@ -49,6 +49,7 @@ public class ClassFinder {
private FileNameFilter fileNameFilter; private FileNameFilter fileNameFilter;
private ClassFilter classFilter; private ClassFilter classFilter;
private FileFilter fileFilter; private FileFilter fileFilter;
private ClassLoader classLoader;
public interface ResourcePathFilter { public interface ResourcePathFilter {
boolean isCandidatePath(String resourcePath, boolean isJar); boolean isCandidatePath(String resourcePath, boolean isJar);
@ -114,16 +115,27 @@ public class ClassFinder {
} }
} }
public ClassFinder() { // To control which classloader to use while trying to find jars/classes
this(null, null, null); public ClassFinder(ClassLoader classLoader) {
this(null, null, null, classLoader);
} }
public ClassFinder(ResourcePathFilter resourcePathFilter, public ClassFinder() {
FileNameFilter fileNameFilter, ClassFilter classFilter) { 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.resourcePathFilter = resourcePathFilter;
this.classFilter = classFilter; this.classFilter = classFilter;
this.fileNameFilter = fileNameFilter; this.fileNameFilter = fileNameFilter;
this.fileFilter = new FileFilterWithName(fileNameFilter); this.fileFilter = new FileFilterWithName(fileNameFilter);
this.classLoader = classLoader;
} }
/** /**
@ -147,7 +159,7 @@ public class ClassFinder {
final String path = packageName.replace('.', '/'); final String path = packageName.replace('.', '/');
final Pattern jarResourceRe = Pattern.compile("^file:(.+\\.jar)!/" + path + "$"); final Pattern jarResourceRe = Pattern.compile("^file:(.+\\.jar)!/" + path + "$");
Enumeration<URL> resources = ClassLoader.getSystemClassLoader().getResources(path); Enumeration<URL> resources = this.classLoader.getResources(path);
List<File> dirs = new ArrayList<>(); List<File> dirs = new ArrayList<>();
List<String> jars = new ArrayList<>(); List<String> jars = new ArrayList<>();
@ -270,7 +282,7 @@ public class ClassFinder {
private Class<?> makeClass(String className, boolean proceedOnExceptions) private Class<?> makeClass(String className, boolean proceedOnExceptions)
throws ClassNotFoundException, LinkageError { throws ClassNotFoundException, LinkageError {
try { try {
Class<?> c = Class.forName(className, false, this.getClass().getClassLoader()); Class<?> c = Class.forName(className, false, classLoader);
boolean isCandidateClass = null == classFilter || classFilter.isCandidateClass(c); boolean isCandidateClass = null == classFilter || classFilter.isCandidateClass(c);
return isCandidateClass ? c : null; return isCandidateClass ? c : null;
} catch (NoClassDefFoundError|ClassNotFoundException classNotFoundEx) { } catch (NoClassDefFoundError|ClassNotFoundException classNotFoundEx) {

View File

@ -27,7 +27,6 @@ import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.util.HashSet; import java.util.HashSet;
@ -73,6 +72,8 @@ public class TestClassFinder {
private static String basePath = null; private static String basePath = null;
private static CustomClassloader classLoader;
@BeforeClass @BeforeClass
public static void createTestDir() throws IOException { public static void createTestDir() throws IOException {
basePath = testUtil.getDataTestDir(TestClassFinder.class.getSimpleName()).toString(); basePath = testUtil.getDataTestDir(TestClassFinder.class.getSimpleName()).toString();
@ -86,6 +87,8 @@ public class TestClassFinder {
} }
assertTrue(testDir.mkdirs()); assertTrue(testDir.mkdirs());
LOG.info("Using new, clean directory=" + testDir); LOG.info("Using new, clean directory=" + testDir);
classLoader = new CustomClassloader(new URL[0], ClassLoader.getSystemClassLoader());
} }
@AfterClass @AfterClass
@ -102,7 +105,7 @@ public class TestClassFinder {
packageAndLoadJar(c1, c3); packageAndLoadJar(c1, c3);
packageAndLoadJar(c2); packageAndLoadJar(c2);
ClassFinder allClassesFinder = new ClassFinder(); ClassFinder allClassesFinder = new ClassFinder(classLoader);
Set<Class<?>> allClasses = allClassesFinder.findClasses( Set<Class<?>> allClasses = allClassesFinder.findClasses(
makePackageName("", counter), false); makePackageName("", counter), false);
assertEquals(3, allClasses.size()); assertEquals(3, allClasses.size());
@ -116,7 +119,7 @@ public class TestClassFinder {
packageAndLoadJar(c1, c2); packageAndLoadJar(c1, c2);
packageAndLoadJar(c1); packageAndLoadJar(c1);
ClassFinder allClassesFinder = new ClassFinder(); ClassFinder allClassesFinder = new ClassFinder(classLoader);
Set<Class<?>> allClasses = allClassesFinder.findClasses( Set<Class<?>> allClasses = allClassesFinder.findClasses(
makePackageName("", counter), false); makePackageName("", counter), false);
assertEquals(2, allClasses.size()); assertEquals(2, allClasses.size());
@ -134,7 +137,7 @@ public class TestClassFinder {
packageAndLoadJar(c1, c2); packageAndLoadJar(c1, c2);
packageAndLoadJar(c3); packageAndLoadJar(c3);
ClassFinder allClassesFinder = new ClassFinder(); ClassFinder allClassesFinder = new ClassFinder(classLoader);
Set<Class<?>> nestedClasses = allClassesFinder.findClasses( Set<Class<?>> nestedClasses = allClassesFinder.findClasses(
makePackageName(NESTED, counter), false); makePackageName(NESTED, counter), false);
assertEquals(2, nestedClasses.size()); assertEquals(2, nestedClasses.size());
@ -156,7 +159,7 @@ public class TestClassFinder {
return !fileName.startsWith(PREFIX); return !fileName.startsWith(PREFIX);
} }
}; };
ClassFinder incClassesFinder = new ClassFinder(null, notExcNameFilter, null); ClassFinder incClassesFinder = new ClassFinder(null, notExcNameFilter, null, classLoader);
Set<Class<?>> incClasses = incClassesFinder.findClasses( Set<Class<?>> incClasses = incClassesFinder.findClasses(
makePackageName("", counter), false); makePackageName("", counter), false);
assertEquals(1, incClasses.size()); assertEquals(1, incClasses.size());
@ -176,7 +179,7 @@ public class TestClassFinder {
return !c.getSimpleName().startsWith(PREFIX); return !c.getSimpleName().startsWith(PREFIX);
} }
}; };
ClassFinder incClassesFinder = new ClassFinder(null, null, notExcClassFilter); ClassFinder incClassesFinder = new ClassFinder(null, null, notExcClassFilter, classLoader);
Set<Class<?>> incClasses = incClassesFinder.findClasses( Set<Class<?>> incClasses = incClassesFinder.findClasses(
makePackageName("", counter), false); makePackageName("", counter), false);
assertEquals(1, incClasses.size()); assertEquals(1, incClasses.size());
@ -215,7 +218,7 @@ public class TestClassFinder {
return !isJar || !resourcePath.equals(excludedJarResource); return !isJar || !resourcePath.equals(excludedJarResource);
} }
}; };
ClassFinder incClassesFinder = new ClassFinder(notExcJarFilter, null, null); ClassFinder incClassesFinder = new ClassFinder(notExcJarFilter, null, null, classLoader);
Set<Class<?>> incClasses = incClassesFinder.findClasses( Set<Class<?>> incClasses = incClassesFinder.findClasses(
makePackageName("", counter), false); makePackageName("", counter), false);
assertEquals(1, incClasses.size()); assertEquals(1, incClasses.size());
@ -231,7 +234,7 @@ public class TestClassFinder {
final String classNamePrefix = name.getMethodName(); final String classNamePrefix = name.getMethodName();
String pkgNameSuffix = name.getMethodName(); String pkgNameSuffix = name.getMethodName();
LOG.info("Created jar " + createAndLoadJar(pkgNameSuffix, classNamePrefix, counter)); LOG.info("Created jar " + createAndLoadJar(pkgNameSuffix, classNamePrefix, counter));
ClassFinder allClassesFinder = new ClassFinder(); ClassFinder allClassesFinder = new ClassFinder(classLoader);
String pkgName = makePackageName(pkgNameSuffix, counter); String pkgName = makePackageName(pkgNameSuffix, counter);
Set<Class<?>> allClasses = allClassesFinder.findClasses(pkgName, false); Set<Class<?>> allClasses = allClassesFinder.findClasses(pkgName, false);
assertTrue("Classes in " + pkgName, allClasses.size() > 0); assertTrue("Classes in " + pkgName, allClasses.size() > 0);
@ -262,10 +265,10 @@ public class TestClassFinder {
} }
}; };
String pkgName = makePackageName(pkgNameSuffix, counter); String pkgName = makePackageName(pkgNameSuffix, counter);
ClassFinder allClassesFinder = new ClassFinder(); ClassFinder allClassesFinder = new ClassFinder(classLoader);
Set<Class<?>> allClasses = allClassesFinder.findClasses(pkgName, false); Set<Class<?>> allClasses = allClassesFinder.findClasses(pkgName, false);
assertTrue("Classes in " + pkgName, allClasses.size() > 0); assertTrue("Classes in " + pkgName, allClasses.size() > 0);
ClassFinder notThisClassFinder = new ClassFinder(null, notThisFilter, null); ClassFinder notThisClassFinder = new ClassFinder(null, notThisFilter, null, classLoader);
Set<Class<?>> notAllClasses = notThisClassFinder.findClasses(pkgName, false); Set<Class<?>> notAllClasses = notThisClassFinder.findClasses(pkgName, false);
assertFalse(contains(notAllClasses, classNameToFilterOut)); assertFalse(contains(notAllClasses, classNameToFilterOut));
assertEquals(allClasses.size() - 1, notAllClasses.size()); assertEquals(allClasses.size() - 1, notAllClasses.size());
@ -287,10 +290,10 @@ public class TestClassFinder {
} }
}; };
String pkgName = makePackageName(pkgNameSuffix, counter); String pkgName = makePackageName(pkgNameSuffix, counter);
ClassFinder allClassesFinder = new ClassFinder(); ClassFinder allClassesFinder = new ClassFinder(classLoader);
Set<Class<?>> allClasses = allClassesFinder.findClasses(pkgName, false); Set<Class<?>> allClasses = allClassesFinder.findClasses(pkgName, false);
assertTrue("Classes in " + pkgName, allClasses.size() > 0); assertTrue("Classes in " + pkgName, allClasses.size() > 0);
ClassFinder notThisClassFinder = new ClassFinder(null, null, notThisFilter); ClassFinder notThisClassFinder = new ClassFinder(null, null, notThisFilter, classLoader);
Set<Class<?>> notAllClasses = notThisClassFinder.findClasses(pkgName, false); Set<Class<?>> notAllClasses = notThisClassFinder.findClasses(pkgName, false);
assertFalse(contains(notAllClasses, clazz.getSimpleName())); assertFalse(contains(notAllClasses, clazz.getSimpleName()));
assertEquals(allClasses.size() - 1, notAllClasses.size()); assertEquals(allClasses.size() - 1, notAllClasses.size());
@ -307,7 +310,7 @@ public class TestClassFinder {
} }
}; };
String thisPackage = this.getClass().getPackage().getName(); String thisPackage = this.getClass().getPackage().getName();
ClassFinder notThisClassFinder = new ClassFinder(notExcJarFilter, null, null); ClassFinder notThisClassFinder = new ClassFinder(notExcJarFilter, null, null, classLoader);
Set<Class<?>> notAllClasses = notThisClassFinder.findClasses(thisPackage, false); Set<Class<?>> notAllClasses = notThisClassFinder.findClasses(thisPackage, false);
assertFalse(notAllClasses.contains(this.getClass())); assertFalse(notAllClasses.contains(this.getClass()));
} }
@ -316,7 +319,7 @@ public class TestClassFinder {
public void testClassFinderDefaultsToOwnPackage() throws Exception { public void testClassFinderDefaultsToOwnPackage() throws Exception {
// Correct handling of nested packages is tested elsewhere, so here we just assume // 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. // pkgClasses is the correct answer that we don't have to check.
ClassFinder allClassesFinder = new ClassFinder(); ClassFinder allClassesFinder = new ClassFinder(classLoader);
Set<Class<?>> pkgClasses = allClassesFinder.findClasses( Set<Class<?>> pkgClasses = allClassesFinder.findClasses(
ClassFinder.class.getPackage().getName(), false); ClassFinder.class.getPackage().getName(), false);
Set<Class<?>> defaultClasses = allClassesFinder.findClasses(false); Set<Class<?>> defaultClasses = allClassesFinder.findClasses(false);
@ -334,8 +337,8 @@ public class TestClassFinder {
private static Class<?> makeClass(String nestedPkgSuffix, private static Class<?> makeClass(String nestedPkgSuffix,
String className, long counter) throws ClassNotFoundException { String className, long counter) throws ClassNotFoundException {
return Class.forName( String name = makePackageName(nestedPkgSuffix, counter) + "." + className + counter;
makePackageName(nestedPkgSuffix, counter) + "." + className + counter); return Class.forName(name, true, classLoader);
} }
private static String makePackageName(String nestedSuffix, long counter) { private static String makePackageName(String nestedSuffix, long counter) {
@ -415,11 +418,19 @@ public class TestClassFinder {
// Add the file to classpath. // Add the file to classpath.
File jarFile = new File(path); File jarFile = new File(path);
assertTrue(jarFile.exists()); assertTrue(jarFile.exists());
URLClassLoader urlClassLoader = (URLClassLoader)ClassLoader.getSystemClassLoader(); classLoader.addURL(jarFile.toURI().toURL());
Method method = URLClassLoader.class
.getDeclaredMethod("addURL", new Class[] { URL.class });
method.setAccessible(true);
method.invoke(urlClassLoader, new Object[] { jarFile.toURI().toURL() });
return jarFile.getAbsolutePath(); 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);
}
}
} }