Vol*_*ker 13 java unit-testing classloader
我最近在Java中乱用ClassLoaders,试图测试使用动态加载类(使用Class.forName(String name))和自定义的代码ClassLoader.
我有自己的自定义ClassLoader设置,应该可配置为ClassNotFoundException在尝试加载给定的类时抛出.
public class CustomTestClassLoader extends ClassLoader {
private static String[] notAllowed = new String[]{};
public static void setNotAllowed(String... nonAllowedClassNames) {
notAllowed = nonAllowedClassNames;
}
public static String[] getNotAllowed() {
return notAllowed;
}
public CustomTestClassLoader(ClassLoader parent){super(parent);}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
for (String s : notAllowed) {
if (name.equals(s)) {
throw new ClassNotFoundException("Loading this class is not allowed for testing purposes.");
}
}
if(name.startsWith("java") || name.startsWith("sun") || getClass().getName().equals(name)) {
return getParent().loadClass(name);
}
Class<?> gotOne = super.findLoadedClass(name);
if (gotOne != null) {
return gotOne;
}
Class<?> c;
InputStream in = getParent().getResourceAsStream(name.replace('.', '/')+".class");
if (in == null) {
throw new ClassNotFoundException("Couldn't locate the classfile: "+name);
}
try {
byte[] classData = readBytes(in);
c = defineClass(name, classData, 0, classData.length);
} catch(IOException e) {
throw new ClassNotFoundException("Couldn't read the class data.", e);
} finally {
try {
in.close();
} catch (IOException e) {/* not much we can do at this point */}
}
if (resolve) {
resolveClass(c);
}
return c;
}
private byte[] readBytes(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[4194304];
int read = in.read(buffer);
while (read != -1) {
out.write(buffer, 0, read);
read = in.read(buffer);
}
out.close();
return out.toByteArray();
}
}
Run Code Online (Sandbox Code Playgroud)
我正在使用-Djava.system.class.loader=com.classloadertest.test.CustomTestClassLoader此设置classloader为默认值ClassLoader.我希望ClassNotFoundException通过禁止使用某些类名来强制执行CustomTestClassLoader.setNotAllowed(String...).但是,它只适用于ClassLoader.loadClass,而不适用于Class.forName:
public void test() {
ClassLoader loader = this.getClass().getClassLoader();
CustomTestClassLoader custom = (CustomTestClassLoader)loader;
CustomTestClassLoader.setNotAllowed(NAME);
for (String s : custom.getNotAllowed())
System.out.println("notAllowed: "+s);
try {
System.out.println(Class.forName(NAME));
} catch (ClassNotFoundException e) {
System.out.println("forName(String) failed");
}
try {
System.out.println(Class.forName(NAME,false,custom));
} catch (ClassNotFoundException e) {
System.out.println("forName(String,boolean,ClassLoader) failed");
}
try {
System.out.println(custom.loadClass(NAME));
} catch (ClassNotFoundException e) {
System.out.println("ClassLoader.loadClass failed");
}
}
Run Code Online (Sandbox Code Playgroud)
现在我预计所有三个try块都会失败,因为文档Class.forName说它使用ClassLoader了调用者(在这个测试中应该是自定义/加载器).但是,只有最终的try块失败.这是我得到的输出:
notAllowed: com.classloadertest.test.Test
class com.classloadertest.test.Test
class com.classloadertest.test.Test
ClassLoader.loadClass failed
Run Code Online (Sandbox Code Playgroud)
是否Class.forName真的使用classloader?如果是这样,哪种方法?它似乎是使用本机调用,所以我不知道它在幕后做了什么.
当然,如果有人知道测试Class.forName()呼叫的任何其他方式,也会非常感激.
Class.forName()使用调用它的类的类加载器(例如,在您的情况下是包含该test()方法的类)。因此,如果您在不同的环境中运行它,就会导致问题。
更新该类加载器将用于Class.forName()加载您的Test类。这可能是解决方案:它可能是 Eclipse 定义的类加载器,它可以访问您的类,因此它将加载它。尽管它的父(或根)类加载器有明确的规则来禁止加载该类。
我仍然建议为此实例化创建一个包装类。您应该使用您的 加载该类CustomTestClassLoader,然后您可以Class.forName()在该类中使用。
| 归档时间: |
|
| 查看次数: |
2064 次 |
| 最近记录: |