Java ASM нужна помощь - PullRequest
       3

Java ASM нужна помощь

2 голосов
/ 31 января 2011

Я пишу простую программу с использованием 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.

Ответы [ 2 ]

10 голосов
/ 31 января 2011

Я не думаю, что ваша ошибка вызвана ASM. Похоже, вы просто неправильно назвали java. Вы должны назвать это так:

java Main

Полагаю, вы назвали это так:

java Main.class

Обновление

Есть три проблемы с вашим кодом.

Задача № 1

Конструктор ClassWriter принимает битовую маску параметров. Вы прошли это Opcodes.NULL. Хотя это может показаться правильным, на самом деле вы хотите передать его 0 (Opcodes.NULL означает что-то другое).

ClassWriter cw=new ClassWriter(0);

Задача № 2

Вы вызываете AALOAD в конструкторе вместо ALOAD. Инструкция AALOAD загружает элемент массива , тогда как 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
  );

Вы можете избавить себя от боли, воспользовавшись классом Type ASM:

mv.visitFieldInsn(
    Opcodes.GETSTATIC,
    "java/lang/System",
    "out",
    Type.getObjectType("java/io/PrintStream").getDescriptor()
  );
2 голосов
/ 22 августа 2011

Просто добавлю: по опыту я обнаружил, что ошибка недопустимой подписи обычно возникает из-за отсутствия точки с запятой в конце описания метода.

...