Frage

Ich muss neue Klassen (über Generierung von Java-Byte-Code) aus vorhandenen Klassen generieren. Ich werde den Körper (Ausdrücke) der Methoden einer Klasse analysieren. Die Ausdrücke bestimmen, welchen Code ich generieren werde.

Für mich ist es importieren, die Quelldatei für die neuen Klassen einzustellen (gleiche als Basis-Java-Datei) sowie die Steuerung von Zeilennummern (wenn eine Ausnahme ausgelöst wird, sollte das Stacktrace Zeilennummern der Basis-Java-Datei enthalten). < / p>

Beispiel: Ich habe die Datei baseclass.java . Der Compiler generiert ein basenclass.class davon. Ich möchte diese Klassendatei analysieren und die Byte-Codes für eine generierteclass.class generieren. Wenn bei c eine Ausnahme ausgelöst wird, sollte das Stacktrace "basenclass.java line 3" enthalten. generasacodicetagpre.

Meine Frage: Gibt es Bibliotheken, die diese Anforderung unterstützen? JavaSt, Asm oder Bler? Was für diesen Zweck verwenden? Hinweise, wie es tut, oder Beispielcode wäre besonders hilfreich.

edit: Tipps, welche Bibliothek nicht verwendet wird, da die Anforderung nicht fulliliert werden kann, wäre auch hilfreich :).

War es hilfreich?

Lösung

With asm, you can use the methods visitSource and visitLineNumber to create this debugging information in the generated class.

Edit: Here is a minimal example:

import java.io.File;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import java.io.FileOutputStream;
import java.io.IOException;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.util.CheckClassAdapter;
import static org.objectweb.asm.Opcodes.*;

public class App {
    public static void main(String[] args) throws IOException {
        ClassWriter cw = new ClassWriter(0);
        CheckClassAdapter ca = new CheckClassAdapter(cw);
        ca.visit(V1_5, ACC_PUBLIC + ACC_SUPER, "test/Test", null, "java/lang/Object", null);
        ca.visitSource("this/file/does/not/exist.txt", null); // Not sure what the second parameter does
        MethodVisitor mv = ca.visitMethod(ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);

        mv.visitCode();
        Label label = new Label();
        mv.visitLabel(label);
        mv.visitLineNumber(123, label);
        mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "()V");
        mv.visitInsn(ATHROW);
        mv.visitInsn(RETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();

        ca.visitEnd();

        File target = new File("target/classes/test/");
        target.mkdirs();
        FileOutputStream out = new FileOutputStream(new File(target, "Test.class"));
        out.write(cw.toByteArray());
        out.close();
    }
}

Running this generates a class containing a main method that throws a RuntimeException just to see the line number in the stack trace. First lets see what a disassembler makes of this:

$ javap -classpath target/classes/ -c -l test.Test
Compiled from "this.file.does.not.exist.txt"
public class test.Test extends java.lang.Object{
public static void main(java.lang.String[]);
  Code:
   0:   new #9; //class java/lang/RuntimeException
   3:   dup
   4:   invokespecial   #13; //Method java/lang/RuntimeException."<init>":()V
   7:   athrow
   8:   return

  LineNumberTable: 
   line 123: 0
}

So this class was compiled from a txt file that does not exist :), the LineNumberTable says that the bytecode starting at offset 0 corresponds to line 123 of this imaginary file. Running this file shows that this file and linenumber is also contained in the stack trace:

$ java -cp target/classes/ test.Test
Exception in thread "main" java.lang.RuntimeException
        at test.Test.main(this/file/does/not/exist.txt:123)

Andere Tipps

BCEL has classes LineNumber and LineNumberTable that represent the line number information in a classfile. By the looks of it, you can create and set the table for some class that you are code generating. Presumably, the information gets written out to the class file.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top