Domanda

Ho bisogno di generare nuove classi (tramite generazione di codice byte Java) da lezioni esistenti. Analizzerò il corpo (espressioni) dei metodi di una classe. Le espressioni determinano quale codice genererò.

per me è importato e impostare il file sorgente per le nuove classi (come come file Java Base) e il controllo dei numeri della riga (quando viene lanciata un'eccezione che la stacktrana deve contenere i numeri di linea del file Java di base). < / P >.

Esempio: Ho il file baseclass.java . Il compilatore genera un baseclass.class da questo. Mi piacerebbe analizzare questo file di classe e generare i codici Byte per generatedclass.class . Quando AT C viene lanciata un'eccezione, la stacktrace dovrebbe contenere "Baseclass.java Line 3".

BaseClass.java
1: class BaseClass {
2:    void method() {
3:        call();
4:    }
5:}

GeneratesClaas.class
a: class GeneratedClass {
b:    void generatedMethod() {
c:        generatedCall();
d:    }
e:}
.

La mia domanda: ci sono librerie che supportano questo requisito? Javassist, ASM o BCEL? Cosa usare per questo scopo? Suggerimenti Come farlo o il codice di esempio sarebbe particolarmente utile.

Modifica: Suggerisce quale biblioteca non utilizzare perché il requisito non può essere pieno di fullfiled sarebbe utile anche :).

È stato utile?

Soluzione

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)

Altri suggerimenti

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top