我使用自定义类加载器将ASM与java一起使用,但我在scala中遇到同样的问题。什么是首选方法?
HelloScala.scala
编译为两个类(HelloScala.class
和 HelloScala$.class
)。我是否需要欺骗两者的字节码?
我的代码似乎只填充了一个HelloScala$.class
,但没有公共构造函数或方法。我可以使用Reflection API并使用Constructor来获取访问权限,但有两个问题:
HelloScala.class
,我错过了什么有价值的东西吗?“正确”的方式可能是调用main
中的公开HelloScala
,但我收到此错误:
[Loaded HelloScala from __JVM_DefineClass__]
[Loaded scala.ScalaObject from file:/home/julianpeeters/asm-scala-example/lib/scala-library-2.9.1.jar]
[Loaded HelloScala$ from __JVM_DefineClass__]
[Loaded sun.reflect.NativeMethodAccessorImpl from /usr/lib/jvm/java-6-openjdk/jre/lib/rt.jar]
[Loaded sun.reflect.DelegatingMethodAccessorImpl from /usr/lib/jvm/java-6-openjdk/jre/lib/rt.jar]
[Loaded java.lang.reflect.InvocationTargetException from /usr/lib/jvm/java-6-openjdk/jre/lib/rt.jar]
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at HelloScalaDump.main(HelloScalaDump.java:41)
Caused by: java.lang.NoClassDefFoundError: HelloScala$
at HelloScala.main(Unknown Source)
... 5 more
Caused by: java.lang.ClassNotFoundException: HelloScala$
at java.lang.ClassLoader.findClass(ClassLoader.java:373)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
... 6 more
似乎HelloScala$
正在加载,为什么不能找到它?
谢谢!
答案 0 :(得分:1)
Scala使用了很多技巧将它的语义映射到JVM。因此,您会在字节码级别看到很多意想不到的事情。我认为你必须接受它并深入研究scala编译器如何使用Java Structures。
一个类由它的名称和加载类的类加载器(调用define方法的类)标识。你确定加载HelloScala的加载器实际上也加载了HelloScala $吗?
答案 1 :(得分:0)
这对我有用,在每个类''dump'文件中调用dump()
方法来加载具有上下文的ClassLoader而不是自定义类加载器的类(因此欺骗类可以访问与类相同的类路径)项目的其余部分):
import java.lang.reflect.*;
public class DumpLoader {
public static void main(String[] args) throws Exception {
Class<?> c$ = loadClass("HelloScala$", HelloScala$Dump.dump()); //First load the "anonymous" class
Class<?> c = loadClass("HelloScala", HelloScalaDump.dump()); //Then load the "real" class
try {
Method mainMethod = c.getMethod("main", String[].class); //Get the main method of the "real" class
mainMethod.invoke(null, (Object) new String[]{}); //and invoke it to run the spoofed program
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
private static Class loadClass(String className, byte[] b) {
//override classDefine (as it is protected) and define the class.
Class<?> clazz = null;
try {
// ClassLoader loader = ClassLoader.getSystemClassLoader();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?> cls = Class.forName("java.lang.ClassLoader");
Method method = cls.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class, int.class });
// protected method invocaton
method.setAccessible(true);
try {
Object[] args = new Object[] { className, b, new Integer(0), new Integer(b.length)};
clazz = (Class) method.invoke(loader, args);
} finally {
method.setAccessible(false);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
return clazz;
}
}