문제

기존 클래스에서 (Java 바이트 코드 생성을 통해) 새 클래스를 생성해야 합니다.클래스 메소드의 본문(표현식)을 분석하겠습니다.표현식에 따라 생성할 코드가 결정됩니다.

나에게는 새 클래스에 대한 소스 파일(기본 Java 파일과 동일)을 설정하고 줄 번호를 제어하는 ​​것(예외가 발생하면 스택 추적에 기본 Java 파일의 줄 번호가 포함되어야 함)이 중요합니다.

예:파일이 있어요 BaseClass.java.컴파일러는 BaseClass.class 이것으로부터.이 클래스 파일을 분석하고 생성된Class.class.언제 예외가 발생하면 스택 추적에 "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?이 목적으로 무엇을 사용해야합니까?수행 방법에 대한 힌트나 예제 코드가 특히 도움이 될 것입니다.

편집하다:요구 사항을 충족할 수 없기 때문에 사용하지 말아야 할 라이브러리를 힌트하는 것도 도움이 될 것입니다 :).

도움이 되었습니까?

해결책

와 함께 asm, 당신은 방법을 사용할 수 있습니다 방문소스 그리고 방문라인번호 생성된 클래스에 이 디버깅 정보를 생성합니다.

편집하다: 다음은 최소한의 예입니다.

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

이를 실행하면 스택 추적의 줄 번호를 보기 위해 RuntimeException을 발생시키는 기본 메서드가 포함된 클래스가 생성됩니다.먼저 디스어셈블러가 무엇을 하는지 살펴보겠습니다.

$ 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
}

따라서 이 클래스는 존재하지 않는 txt 파일에서 컴파일되었습니다. :) LineNumberTable은 오프셋 0에서 시작하는 바이트코드가 이 가상 파일의 라인 123에 해당한다고 말합니다.이 파일을 실행하면 이 파일과 줄 번호가 스택 추적에도 포함되어 있음을 알 수 있습니다.

$ 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에는 클래스 파일의 줄 번호 정보를 나타내는 LineNumber 및 LineNumberTable 클래스가 있습니다.보기에 따르면 코드를 생성하는 일부 클래스에 대한 테이블을 만들고 설정할 수 있습니다.아마도 정보는 클래스 파일에 기록될 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top