I know it's not a good demand. But I need to do that now.
I need to replace the method of Class.getResourceAsStream(String)
But ClassLoader.preDefineClass(String , ProtectionDomain)
checks whether the class name of the full name starts with java.
, and if so, throws an exception and is not allowed to load.
Is there a way to bypass runtime security checks instead of compile time?
Update
The real requirement is that many older projects need to migrate to new environments, because some of these projects may be out of date and some of them may not be able to find the source code. I am required to simulate the old environment in a new environment so that these ancient projects can continue to function.
Upadte (GhostCat)
I tried the way which you given.
ClassLoader Class
public class ClassLoaderTest extends ClassLoader {
@Override
public InputStream getResourceAsStream(String name) {
System.out.println("getResourceAsStream " + name);
return new ByteArrayInputStream(new byte[]{1, 3, 5, 7, 9});
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
System.out.println("Load class " + name);
String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
InputStream is = getClass().getResourceAsStream(fileName);
if (is == null) {
return super.loadClass(name);
}
byte[] b = new byte[0];
try {
b = new byte[is.available()];
is.read(b);
} catch (IOException e) {
e.printStackTrace();
}
return defineClass(name, b, 0, b.length);
}
}
Invoke Class
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
ClassLoaderTest classLoaderTest = new ClassLoaderTest();
Class clazz = Class.forName("com.Client", true, classLoaderTest);
Object client = clazz.newInstance();
Method method = clazz.getDeclaredMethod("method");
method.invoke(client);
}
Client Class
public class Client {
public void method() {
System.out.println(this.getClass().getResourceAsStream("aaa"));
System.out.println(Class.class.getResourceAsStream("bbb"));
System.out.println("".getClass().getResourceAsStream("ccc"));
}
}
It really works with this.getClass().getResourceAsStream(String)
, but Class.class.getResourceAsStream(String)
/ "".getClass().getResourceAsStream(String)
. Because I cannot load class using my custom ClassLoader which
name start with java.