2017-11-12 30 views
2

모든 호출을 기록하려고합니다. 반환 된 객체 및 예외은 도구 코드의 정상적인 작동과 함께 반복하지 않고 ByteBuddy (v1.7.9) Java 에이전트를 사용하여 메소드 및 생성자에 Throw됩니다.ByteBuddy 에이전트를 사용하여 생성자가 던진 예외를 처리하는 방법은 무엇입니까?

에이전트의 나의 현재 인스턴스 내가 프로그램을 실행할 때

new AgentBuilder.Default() 
       .with(AgentBuilder.Listener.StreamWriting.toSystemOut()) 
       .type((typeDescription, classLoader, module, classBeingRedefined, protectionDomain) -> 
        matcher.matchesIncoming(typeDescription.getTypeName())) 
       .transform((builder, typeDescription, classLoader, javaModule) -> builder 
         .visit(Advice.to(CustomAdvicer.class).on(ElementMatchers.any()))) 
       .installOn(inst); 

나는 간단한 "advicer"로 시작하는 한

public class CustomAdvicer { 
    @Advice.OnMethodEnter 
    public static void enter(@Advice.Origin String origin) { 
     System.out.println("Entering " + origin); 
    } 

    @Advice.OnMethodExit(onThrowable = Throwable.class) 
    public static void exit(
     @Advice.Return(typing = Assigner.Typing.DYNAMIC) @RuntimeType Object value, 
     @Advice.Origin String origin, 
     @Advice.Thrown Throwable thrown) { 
     System.out.println("Exiting " + origin); 
    } 
} 

그러나 내가 bytebuddy에서 예외가있다 :

[Byte Buddy] ERROR some.pack.Thrower [[email protected], null, loaded=false] 
java.lang.IllegalStateException: Cannot catch exception during constructor call for public some.pack.Thrower() throws java.lang.Exception 
    at net.bytebuddy.asm.Advice.doWrap(Advice.java:515) 
    at net.bytebuddy.asm.Advice.wrap(Advice.java:470) 
    at net.bytebuddy.asm.AsmVisitorWrapper$ForDeclaredMethods$Entry.wrap(AsmVisitorWrapper.java:481) 
    at net.bytebuddy.asm.AsmVisitorWrapper$ForDeclaredMethods$DispatchingVisitor.visitMethod(AsmVisitorWrapper.java:562) 
    at net.bytebuddy.jar.asm.ClassVisitor.visitMethod(ClassVisitor.java:327) 
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining$RedefinitionClassVisitor.visitMethod(TypeWriter.java:3801) 
    at net.bytebuddy.jar.asm.ClassReader.readMethod(ClassReader.java:1020) 
    at net.bytebuddy.jar.asm.ClassReader.accept(ClassReader.java:698) 
    at net.bytebuddy.jar.asm.ClassReader.accept(ClassReader.java:500) 
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining.create(TypeWriter.java:2941) 
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1633) 
    at net.bytebuddy.dynamic.scaffold.inline.RebaseDynamicTypeBuilder.make(RebaseDynamicTypeBuilder.java:200) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$Transformation$Simple$Resolution.apply(AgentBuilder.java:8905) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:9306) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:9269) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1300(AgentBuilder.java:9047) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9625) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9575) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:9194) 
    at sun.instrument.TransformerManager.transform(Unknown Source) 
    at sun.instrument.InstrumentationImpl.transform(Unknown Source) 
    at java.lang.ClassLoader.defineClass1(Native Method) 
    at java.lang.ClassLoader.defineClass(Unknown Source) 
    at java.security.SecureClassLoader.defineClass(Unknown Source) 
    at java.net.URLClassLoader.defineClass(Unknown Source) 
    at java.net.URLClassLoader.access$100(Unknown Source) 
    at java.net.URLClassLoader$1.run(Unknown Source) 
    at java.net.URLClassLoader$1.run(Unknown Source) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.net.URLClassLoader.findClass(Unknown Source) 
    at java.lang.ClassLoader.loadClass(Unknown Source) 
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) 
    at java.lang.ClassLoader.loadClass(Unknown Source) 
    at Main.main(Main.java:23) 

그래서 EXCE를 기록하려면 어떻게해야합니까? 생성자 내부에 던져진 코드는 원래 코드를 간섭해서는 안된다는 것을 명심해야합니까?

package some.pack; 

public class Thrower { 
    public Thrower() throws Exception { 
    throw new Exception("By courtesy of thrower! ;)"); 
    } 

}

답변

1

문제는 생성자의 호출이다 암시 첫 번째 명령어를 가지고 있다는 것입니다 : 그런데

는 방사기 클래스는 내가이 사건을 테스트하기 위해 쓴 바보 클래스 다른 또는 슈퍼 생성자. 당신이 시도-catch 블록에서 전체 호출을 래핑하고 싶었다면

public class Thrower { 
    public Thrower() throws Exception { 
    super(); 
    throw new Exception("By courtesy of thrower! ;)"); 
    } 
} 

이이 얻을 것이다 : 당신의 Thrower 클래스는 정말 다음과 같습니다

public class Thrower { 
    public Thrower() throws Exception { 
    try { 
     super(); 
     throw new Exception("By courtesy of thrower! ;)"); 
    } catch (Exception e) { 
     ... 
    } 
    } 
} 

을하지만이 JVM에서 불법이다 따라서 Byte Buddy는이를 허용하지 않습니다. 슈퍼 생성자 호출을 제외하는 좋은 방법은 없습니다. 첫 번째 호출은 Java 언어 규칙이지만 바이트 코드는 더 많은 임의의 조합을 허용하기 때문입니다. 어떤 언어가 어떤 언어인지 알 수 없기 때문에, Byte Buddy는 어떤 트릭도 시도하지 않고 단순히 허용하지 않습니다.

+0

생성자가 던진 예외 로깅이라는 목표를 달성 할 수있는 다른 방법이 있습니까? – jmmurillo

+0

관련 질문 [여기] (https://stackoverflow.com/questions/47265835/can-i-instrument-outgoing-method-constructor-calls-with-bytebuddy)을 만들었습니다. 빠른 답변 주셔서 감사합니다. – jmmurillo

+1

사실, 예외 처리기가 정상적으로 완료하려고하지 않는 한, 바이트 코드에서 * 합법적입니다 (Java 프로그래밍 언어는 아님). 예외 처리기가 정상적으로 완료하려고하지 않는 한 즉, 예외를 재발행하거나, 다른 예외를 던지거나, 무한 루프. – Holger