1

カスタムクラスローダーを使用してJavaでASMを使用しましたが、scalaで同じことを行うのに問題があります。推奨されるアプローチは何ですか?

Aは2つのクラス(およびHelloScala.scala)にコンパイルされます。両方のバイトコードをスプーフィングする必要がありますか?HelloScala.class HelloScala$.class

私のコードは1つだけに詰め込まれているように見えますがHelloScala$.class、パブリックコンストラクターやメソッドはありません。Reflection APIを使用し、コンストラクターを使用してアクセスを取得できますが、2つの問題があります。

  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構造をどのように使用するかを詳しく調べる必要があると思います。

クラスは、その名前と、クラスをロードしたクラスローダー(defineメソッドを呼び出したクラス)によって識別されます。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 に答える