【问题标题】:Java ASM help needJava ASM 帮助需要
【发布时间】:2011-01-31 17:08:25
【问题描述】:

我使用Java ASM编写了一个简单的程序来生成通过编译以下类生成的字节码。

public class Main {
    public static void main(String[] args) {
        System.out.println("Test");
    }
}

我为这个类生成字节码的代码如下。

public class CodeGenerator {

    public void generateClass()
    {
        ClassWriter cw=new ClassWriter(Opcodes.NULL);
        FieldVisitor fv;
        MethodVisitor mv;
        cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "Main", null, "java/lang/Object", null);
        mv=cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitVarInsn(Opcodes.AALOAD, 0);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
        mv=cw.visitMethod(Opcodes.ACC_PUBLIC+ Opcodes.ACC_STATIC, "Main", "([Ljava/lang/String;)V", null, null);
        mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream");
        mv.visitLdcInsn("Test");
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();
        cw.visitEnd();
        this.WriteClass(cw);
    }
    public void WriteClass(ClassWriter cw){
        FileOutputStream fos;
        try{
            fos = new FileOutputStream("E:\\Acadamic\\Final year project\\ASM\\Main.class");
            fos.write(cw.toByteArray());
            fos.close();
        }
        catch (IOException ex){
            Logger.getLogger(CodeGenerator.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

这编译成功,当我尝试运行它时,它给出了以下错误。

Exception in thread "main" java.lang.NoClassDefFoundError: main/class
Caused by: java.lang.ClassNotFoundException: main.class
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: main.class.  Program will exit.

谁能帮我避免这个错误。如果有人能解释错误的原因以及如何避免它,请帮助我。

谢谢。

跟进:

当我像 java Main 一样运行它时,会出现以下错误。

Exception in thread "main" java.lang.ClassFormatError: Field "out" in class Main
 has illegal signature "Ljava/io/PrintStream"
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClassCond(Unknown Source)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        at java.security.SecureClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.access$000(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: Main.  Program will exit.
 

【问题讨论】:

    标签: java java-bytecode-asm


    【解决方案1】:

    我认为您的错误不是由 ASM 引起的。看起来您只是错误地调用了java。你应该这样称呼它:

    java 主要

    我猜你是这样称呼它的:

    java Main.class

    更新

    您的代码存在三个问题。

    问题 #1

    ClassWriter 构造函数接受选项的位掩码。你通过了Opcodes.NULL。虽然这可能看起来正确,但您实际上想传递它0Opcodes.NULL 意味着不同的东西)。

    ClassWriter cw=new ClassWriter(0);
    

    问题 #2

    您在构造函数中调用AALOAD 而不是ALOADAALOAD 指令加载一个数组元素,而ALOAD 加载一个局部变量

    mv.visitVarInsn(Opcodes.ALOAD, 0);
    

    问题 #3

    在您的Main 方法中,您忘记了Ljava/io/PrintStream 后面的分号:

    mv.visitFieldInsn(
        Opcodes.GETSTATIC,
        "java/lang/System",
        "out",
        "Ljava/io/PrintStream;" // Notice the semicolon
      );
    

    您可以利用 ASM 的 Type 类为自己节省一些痛苦:

    mv.visitFieldInsn(
        Opcodes.GETSTATIC,
        "java/lang/System",
        "out",
        Type.getObjectType("java/io/PrintStream").getDescriptor()
      );
    

    【讨论】:

    • 感谢您的回复。当我像 java Main 一样运行它时,它会出现另一个错误。我在这里提到过
    【解决方案2】:

    补充一下,根据经验,我发现非法签名错误通常是由于方法描述末尾缺少分号造成的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-09
      • 1970-01-01
      • 2015-11-14
      相关资源
      最近更新 更多