1

我使用自定义类加载器将 ASM 与 java 一起使用,但在 scala 中做同样的事情时遇到了麻烦。首选方法是什么?

AHelloScala.scala编译成两个类(HelloScala.class HelloScala$.class)。我需要欺骗两者的字节码吗?

我的代码似乎只填充了一个 , HelloScala$.class,但没有公共构造函数或方法。我可以使用 Reflection API 并使用 Constructor 来获取访问权限,但有两个问题:

  1. 通过忽略HelloScala.class,我是否错过了任何有价值的东西?
  2. 这是危险的还是臭的?

“正确”的方法可能是调用 public, static mainin 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$正在加载,为什么找不到呢?

谢谢!

4

2 回答 2

1

Scala 使用了很多技巧来将其语义映射到 JVM。因此,您会在字节码级别看到很多意想不到的事情。我认为您必须接受它并深入了解 scala 编译器如何使用 Java 结构。

一个类由它的名称和加载该类的类加载器(调用定义方法的类)来标识。你确定加载 HelloScala 的加载器实际上也加载了 HelloScala$ 吗?

于 2012-12-22T00:20:34.377 回答
0

这对我有用,调用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;
  }

}
于 2013-04-03T06:38:23.053 回答