Какую библиотеку Bytecode при контроле номеров строки?

StackOverflow https://stackoverflow.com/questions/5041877

Вопрос

Мне нужно создать новые классы (через генерацию кода байтов Java) из существующих классов. Я проанаю тело (выражения) методов класса. Выражения определит, какой код я буду генерировать.

Для меня это ImportAnd и для установки исходного файла для новых классов (так же, как базовый файл Java), а также контрольные номера строки (когда исключение брошено, что Stacktrace должен содержать номера строки базового файла Java). < / P >.

Пример: У меня есть файл baseclass.java . Компилятор генерирует BASECLASS. Class от этого. Я хотел бы проанализировать этот классный файл и генерировать коды байтов для GeneratedClassClass.class.Class . Когда в c выдают исключение, Stacktrace должен содержать «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:}
.

Мой вопрос: есть ли библиотеки, которые поддерживают это требование? Javassist, Asm или Bcel? Что использовать для этой цели? Подсказки, как это сделать или пример код будет особенно полезным.

<Сильные> Редактировать: Подсказки, какую библиотеку не использовать, потому что требование не может быть полнофинанжено, тоже будет полезным :).

Это было полезно?

Решение

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)

Другие советы

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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top