2016-12-15 1 views
0

런타임시 Javassist 3.20.0-GA를 사용하여 사용자 정의 Java 에이전트를 통해 바이트 코드를 다시 작성하는 Java 8 프로젝트가 있습니다. 목표는 메소드를 인스트루먼트하여 원래의 본문이 print 문을 사용하여 try/finally 블록으로 래핑되도록하는 것입니다.Javassist를 사용하여 원래의 메서드 로직을 래핑하는 try/finally 로직을 삽입하십시오.

CtClass ctClass = ClassPool.getDefault().get("com.example.test.TimeService"); 

CtMethod ctMethod = ctClass.getDeclaredMethod("getCurrentTime"); 

ctMethod.insertBefore("System.out.println(\"Start\");"); 
ctMethod.insertAfter("System.out.println(\"Stop\");", true); 
:

public class TimeService { 

    public long getCurrentTime(){ 
     try { 
      System.out.println("Start"); 

      // BEGIN original code 
      long time = 0; 
      try { 
       time = System.currentTimeMillis(); 
      } 
      catch(Throwable t){ 
       time = -1; 
      } 

      System.out.println("The current time is "+time); 

      return time; 
      // END original code 
     } 
     finally { 
      System.out.println("Stop"); 
     } 
    } 
} 

먼저 나는 다음과 같은 코드를 시도 : 나는 (의견 없음) 출력 다음 수정 된 코드를 싶습니다

public class TimeService { 

    public long getCurrentTime(){ 

     long time = 0; 
     try { 
      time = System.currentTimeMillis(); 
     } 
     catch(Throwable t){ 
      time = -1; 
     } 

     System.out.println("The current time is "+time); 

     return time; 
    } 
} 

: 예를 들어,이 사소한 방법을 제공

이것은 기존의 try/catch/finally 블록을 사용하지 않고 간단한 void 메소드에서 잘 작동하는 것처럼 보였으 나, getCurrentTime() 메소드의 출력은 str 오류가없는 경우

public long getCurrentTime() { 
    boolean var10 = false; 

    long var10000; 
    long var5; 
    try { 
     var10 = true; 
     System.out.println("Start"); 
     long time = 0L; 

     try { 
      time = System.currentTimeMillis(); 
     } catch (Throwable var11) { 
      time = -1L; 
     } 

     System.out.println("The current time is " + time); 
     var10000 = time; 
     var10 = false; 
    } finally { 
     if(var10) { 
      var5 = 0L; 
      System.out.println("Stop"); 
     } 
    } 

    var5 = var10000; 
    System.out.println("Stop"); 
    return var5; 
} 

위의 코드는 "작동"하지만 에 System.currentTimeMillis 척 : 플랜지 및 에서 System.out.println ("정지") 문은 두 번반복()는 예외를 throw, 다음 var10는 thusly 히 에서 System.out.println ("정지") 문이 두 번실행됩니다를 거짓로 설정 될 않을 것입니다. 부울 플래그를 세이프 가드로 사용하면 여기서는 잘 작동하지 않으므로 메서드의 맨 처음과 끝에 간단히 try/finally를 삽입하는 것이 좋습니다. 많은 시도를 통해 출력물을 여러 번 "정지"

CtClass ctClass = ClassPool.getDefault().get("com.example.test.TimeService"); 

CtMethod ctMethod = ctClass.getDeclaredMethod("getCurrentTime"); 

ctMethod.instrument(new ExprEditor(){ 
    public void edit(MethodCall m) throws CannotCompileException { 
     String start = "{ System.out.println(\"Start\"); }"; 
     String stop = "{ System.out.println(\"Stop\"); }"; 

     m.replace("{ try {"+start+" $_ = $proceed($$); } finally { "+stop+" } }"); 
    } 
}); 

그러나 그것은 "시작"반복 왜곡 된 엉망으로 전환 :

다음 나는 인스트루먼트와 같은 직접 방법을 교체 시도/catch/finally 블록 (너무 지저분 해 여기에 붙여 넣기).

다음에 시도 할 내용이 확실하지 않거나 Javassist API의 잘못된 부분을 사용하고 있는지 잘 모르겠습니다. 그것은 매우 직설적이어야하고 단순한 void 메쏘드와 같이 보인다. 그러나 값이 반환 될 때, 특히 pre/try/catch/finally 블록과 결합하여 결과가 예측할 수 없게된다.

어떤 생각이나 해결 방법이 있습니까?

미리 감사드립니다.

답변

1

생성 된 getCurrentTime은 정확합니다. 예외가 throw 된 경우에만 if(var10) 문을 입력합니다. 그러나이 경우에는 코드 finally 아래에 절대 도달하지 않습니다. finally 예외를 포착하지 않습니다, 그냥 일부 코드를 실행하고 더 던졌습니다

생성 된 코드는 꽤 이상하지만 그것은 결국해야 할 일을합니다. 메시지 "Stop"은 정확히 한 번 인쇄됩니다.

+0

생성 된 코드를 다시 검사했는데 정확합니다. 생성 된 코드가 원본의 배수가 아니 었으면 좋겠다. (10 개 라인이 100 개 라인을 넘는 것을 본 적이있다.) 그렇다면 다시 _ 생성 된 것은 꽤 이상합니다. – user1661467

관련 문제