2017-06-25 6 views
0

私はのFileInputStream /のFileOutputStreamコンストラクタを傍受することのJavaエージェントを作成しようとしています:バイトバディAdvice.OnMethodExit:コンストラクタの再変換

import java.io.*; 
import java.lang.instrument.Instrumentation; 
import java.util.Arrays; 
import java.util.List; 
import java.util.jar.JarEntry; 
import java.util.jar.JarFile; 
import java.util.jar.JarOutputStream; 
import net.bytebuddy.agent.builder.AgentBuilder; 
import net.bytebuddy.agent.builder.AgentBuilder.InitializationStrategy; 
import net.bytebuddy.agent.builder.AgentBuilder.Listener; 
import net.bytebuddy.agent.builder.AgentBuilder.RedefinitionStrategy; 
import net.bytebuddy.agent.builder.AgentBuilder.TypeStrategy; 
import net.bytebuddy.asm.Advice; 
import static net.bytebuddy.dynamic.ClassFileLocator.CLASS_FILE_EXTENSION; 
import static net.bytebuddy.matcher.ElementMatchers.*; 
import net.bytebuddy.matcher.StringMatcher; 

public class Agent { 

    private static final List<Class<?>> BOOTSTRAP_CLASSES = Arrays.asList(
     Interceptor.class 
    ); 

    private Agent() { 
    } 

    public static void premain(String arg, Instrumentation instrumentation) { 
     injectBootstrapClasses(instrumentation); 
     new AgentBuilder.Default() 
      .with(RedefinitionStrategy.RETRANSFORMATION) 
      .with(InitializationStrategy.NoOp.INSTANCE) 
      .with(TypeStrategy.Default.REDEFINE) 
      .ignore(new AgentBuilder.RawMatcher.ForElementMatchers(nameStartsWith("net.bytebuddy.").or(isSynthetic()), any(), any())) 
      .with(new Listener.Filtering(
       new StringMatcher("java.io.FileInputStream", StringMatcher.Mode.EQUALS_FULLY) 
        .or(new StringMatcher("java.io.FileOutputStream", StringMatcher.Mode.EQUALS_FULLY)), 
       Listener.StreamWriting.toSystemOut())) 
      .type(named("java.io.FileInputStream").or(named("java.io.FileOutputStream"))) 
      .transform((builder, type, classLoader, module) -> 
       builder 
        .constructor(any()) 
        .intercept(Advice.to(Interceptor.class)) 
      ) 
      .installOn(instrumentation); 
    } 

    private static void injectBootstrapClasses(Instrumentation instrumentation) { 
     try { 
      File jarFile = File.createTempFile(Agent.class.getSimpleName(), ".jar"); 
      jarFile.deleteOnExit(); 
      try (JarOutputStream jarOutputStream = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(jarFile)))) { 
       for (Class<?> bootstrapClass : BOOTSTRAP_CLASSES) { 
        String klassPath = classFileFullname(bootstrapClass); 
        jarOutputStream.putNextEntry(new JarEntry(klassPath)); 
        jarOutputStream.write(readFully(bootstrapClass.getClassLoader().getResourceAsStream(klassPath))); 
       } 
      } 
      instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(jarFile)); 
     } catch (IOException exception) { 
      throw new IllegalStateException("Cannot write jar file to disk", exception); 
     } 
    } 

    private static String classFileFullname(Class<?> bootstrapClass) { 
     return bootstrapClass.getName().replace('.', '/') + CLASS_FILE_EXTENSION; 
    } 

    private static byte[] readFully(InputStream input) throws IOException { 
     byte[] buffer = new byte[8192]; 
     try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { 
      int bytesRead; 
      while ((bytesRead = input.read(buffer)) != -1) { 
       output.write(buffer, 0, bytesRead); 
      } 
      return output.toByteArray(); 
     } 
    } 

    public static class Interceptor{ 
     @Advice.OnMethodExit 
     public static void intercept() { 
      System.out.println("Exit constructor"); 
     } 
    } 

} 

上記のコードを印刷:

java.lang.IllegalStateException: Cannot call super (or default) method for public java.io.FileOutputStream(java.lang.String) throws java.io.FileNotFoundException 
    at net.bytebuddy.implementation.SuperMethodCall$Appender.apply(SuperMethodCall.java:97) 
    at net.bytebuddy.asm.Advice$Appender$EmulatingMethodVisitor.resolve(Advice.java:7812) 
    at net.bytebuddy.asm.Advice$Appender.apply(Advice.java:7765) 
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:620) 
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:609) 
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining$RedefinitionClassVisitor$CodePreservingMethodVisitor.visitCode(TypeWriter.java:3969) 
    at net.bytebuddy.jar.asm.ClassReader.b(Unknown Source) 
    at net.bytebuddy.jar.asm.ClassReader.accept(Unknown Source) 
    at net.bytebuddy.jar.asm.ClassReader.accept(Unknown Source) 
    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.RedefinitionDynamicTypeBuilder.make(RedefinitionDynamicTypeBuilder.java:171) 
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:2676) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$Transformation$Simple$Resolution.apply(AgentBuilder.java:8902) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:9303) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:9266) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1300(AgentBuilder.java:9044) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9622) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9572) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:9191) 
    at sun.instrument.TransformerManager.transform(TransformerManager.java:188) 
    at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428) 
    at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method) 
    at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144) 
    at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy$Collector$ForRetransformation.doApply(AgentBuilder.java:6213) 
    at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy$Collector.apply(AgentBuilder.java:6071) 
    at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy.apply(AgentBuilder.java:4252) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default.installOn(AgentBuilder.java:8258) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$Delegator.installOn(AgentBuilder.java:9957) 
    at com.github.soldierkam.agent.Agent.premain(Agent.java:46) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386) 
    at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401) 

これを解決する方法問題? ByteBuddyが存在しないOutputStream(String)コンストラクタを呼び出そうとしているようです。私はByte Buddy 1.7.1とJVM 1.8.0_131を使用しています。

答えて

0

既存のコンストラクタを拡張するために訪問者としてAdviceコンポーネントを使用する必要があります。現在、新しいメソッドを実装しています。

これは動作するはずです:

builder.visit(Advice.to(Interceptor.class).on(isConstructor())); 
関連する問題