Question

J'ai besoin de générer de nouvelles classes (via la génération de code d'octet Java) des classes existantes. Je vais analyser le corps (expressions) des méthodes d'une classe. Les expressions détermineront quel code je vais générer.

Pour moi, c'est importé pour définir le fichier source des nouvelles classes (identique au fichier Java de base) ainsi que le contrôle des numéros de ligne (lorsqu'une exception est lancée, la stacktrace doit contenir des numéros de ligne du fichier Java de base). < / p>

exemple: J'ai le fichier basoclass.java . Le compilateur génère un basoclass.class à partir de ceci. J'aimerais analyser ce fichier de classe et générer les codes d'octets pour un générationdclass.class . Lorsque chez C une exception est lancée, la stacktrace doit contenir "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:}

Ma question: Y a-t-il des bibliothèques qui soutiennent cette exigence? Javassist, ASM ou BCEL? Que utiliser à cet effet? Conseils Comment le faire ou l'exemple de code serait particulièrement utile.

edit: Conseils Quelle bibliothèque à ne pas utiliser car l'exigence ne peut pas être complète serait utile, aussi :).

Était-ce utile?

La solution

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)

Autres conseils

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top