Java 控制行号时使用哪个字节码库?

Java 控制行号时使用哪个字节码库?,java,assembly,bytecode-manipulation,bcel,Java,Assembly,Bytecode Manipulation,Bcel,我需要从现有类生成新类(通过生成java字节码)。我将分析类的方法体(表达式)。表达式将决定我将生成什么代码 对我来说,为新类设置源文件(与基本java文件相同)以及控制行号(当抛出异常时,stacktrace应该包含基本java文件的行号)非常重要 例如: 我有一个文件BaseClass.java。编译器由此生成一个BaseClass.class。我想分析这个类文件并为GeneratedClass.class生成字节码。在c中引发异常时,stacktrace应该包含“BaseClass.jav

我需要从现有类生成新类(通过生成java字节码)。我将分析类的方法体(表达式)。表达式将决定我将生成什么代码

对我来说,为新类设置源文件(与基本java文件相同)以及控制行号(当抛出异常时,stacktrace应该包含基本java文件的行号)非常重要

例如: 我有一个文件BaseClass.java。编译器由此生成一个BaseClass.class。我想分析这个类文件并为GeneratedClass.class生成字节码。在c中引发异常时,stacktrace应该包含“BaseClass.java第3行”

我的问题:是否有支持此要求的库?Javassist、ASM还是BCEL?为此目的使用什么?提示如何做或示例代码将特别有用

编辑:
提示由于需求无法完全归档而不使用的库也会很有用:)。

BCEL有类LineNumber和LineNumber Table,它们表示类文件中的行号信息。从外观上看,您可以为正在生成代码的某个类创建和设置表。信息可能会写入类文件。

使用,您可以使用这些方法并在生成的类中创建此调试信息

编辑:以下是一个简单的示例:

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();
    }
}

大多数反编译器可以在原始代码行所在的代码中打印输出(作为注释)。您可以解析此代码并重新排列代码。您可能会发现,反编译代码的顺序可能不一样,因为它不完全相同。反编译程序不是我想要的。我需要这些信息在运行时生成新的字节码。
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();
    }
}
$ 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
}
$ java -cp target/classes/ test.Test
Exception in thread "main" java.lang.RuntimeException
        at test.Test.main(this/file/does/not/exist.txt:123)