简体   繁体   English

ByteBuddy - Static 方法和字段无法从 Advice 访问

[英]ByteBuddy - Static methods & fields not accessible from Advice

This code is applying an ByteBuddy Advice to the FileInputStream constructor.此代码将 ByteBuddy Advice应用于FileInputStream构造函数。 The onEnter method is actually called but it cannot access static methods and fields.确实调用了onEnter方法,但无法访问static方法和字段。

How can I make accessible static methods and static fields from the onEnter method?如何从onEnter方法访问static 方法static 字段

package com.example.javaagent.instrumentation;

import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.util.*;
import java.util.logging.Logger;

import static java.util.logging.Level.FINE;
import static net.bytebuddy.matcher.ElementMatchers.*;


public class FileInputStreamConstructorInstrumentationTests2 {

    @Test
    public void testByteBuddyfileInputStreamConstructor() {
        ByteBuddyAgent.install();

        AgentBuilder.Identified.Extendable extendableAgentBuilder = new AgentBuilder.Default()
                .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
                .with(AgentBuilder.RedefinitionStrategy.Listener.StreamWriting.toSystemError())
                .with(AgentBuilder.Listener.StreamWriting.toSystemError().withTransformationsOnly())
                .with(AgentBuilder.InstallationListener.StreamWriting.toSystemError())
                .ignore(none())
                .type(named("java.io.FileInputStream"))
                .transform(new AgentBuilder.Transformer.ForAdvice());

        extendableAgentBuilder = extendableAgentBuilder.transform(
                new AgentBuilder.Transformer.ForAdvice()
                        .include(Thread.currentThread().getContextClassLoader())
                        .advice(
                                isConstructor().and(takesArguments(1)).and(takesArgument(0, String.class)),
                                this.getClass().getName() + "$FileInputStreamCtorString"));

        extendableAgentBuilder.installOnByteBuddyAgent();

        String filename = "example.txt";
        createFile(filename);
        try {
            FileInputStream inputStream = new FileInputStream(filename);
            int data = inputStream.read();
            while (data != -1) {
                System.out.print((char) data);
                data = inputStream.read();
            }
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        deleteFile(filename);
    }

    public static class FileInputStreamCtorString {
        public static boolean iveBeenHere = false;

        @Advice.OnMethodEnter(suppress = Throwable.class)
        public static void onEnter(@Advice.Argument(0) String name) {
            System.out.println("FileInputStreamCtorString: entered with param "+ name);
            System.out.println("FileInputStreamCtorString: second log line");
            try{
                JustPrint.sayHello();
            }catch (Throwable e){
                System.out.println("FileInputStreamCtorString: inside catch: " + e.getMessage());
                e.printStackTrace();
            }
            System.out.println("FileInputStreamCtorString: after calling static method");
            try {
                iveBeenHere = true;
            } catch (Throwable e) {
                System.out.println("FileInputStreamCtorString: inside catch: " + e.getMessage());
                e.printStackTrace();
            }
            System.out.println("FileInputStreamCtorString: after setting static field");
        }
    }

    public static class JustPrint{
        public static void sayHello(){
            System.out.println("Did I say 'hello'?");
        }
    }

    private static void deleteFile(String filename) {
        File file = new File(filename);
        // Check if the file exists
        if (file.exists()) {
            // If the file exists, delete it
            if (file.delete()) {
                System.out.println("File deleted successfully");
            } else {
                System.out.println("Failed to delete file");
            }
        } else {
            System.out.println("File does not exist");
        }
    }

    private static void createFile(String filename) {
        File file = new File(filename);
        // Check if the file already exists
        if (!file.exists()) {
            // If the file does not exist, create a new file
            try {
                file.createNewFile();
                System.out.println("File created successfully");
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("File already exists");
        }
    }
}

Running the test above, I get the following output:运行上面的测试,我得到以下 output:

[Byte Buddy] BEFORE_INSTALL net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$ByteBuddy$ModuleSupport@3af17be2 on sun.instrument.InstrumentationImpl@f9879ac
[Byte Buddy] REDEFINE BATCH #0 [1 of 1 type(s)]
[Byte Buddy] TRANSFORM java.io.FileInputStream [null, module java.base, Thread[Test worker,5,main], loaded=true]
[Byte Buddy] REDEFINE COMPLETE 1 batch(es) containing 1 types [0 failed batch(es)]
[Byte Buddy] INSTALL net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$ByteBuddy$ModuleSupport@3af17be2 on sun.instrument.InstrumentationImpl@f9879ac
File created successfully
FileInputStreamCtorString: entered with param example.txt
FileInputStreamCtorString: second log line
FileInputStreamCtorString: inside catchcom/example/javaagent/instrumentation/FileInputStreamConstructorInstrumentationTests2$JustPrint

java.lang.NoClassDefFoundError: com/example/javaagent/instrumentation/FileInputStreamConstructorInstrumentationTests2$JustPrint
    at java.base/java.io.FileInputStream.<init>(FileInputStream.java:111)
    at com.example.javaagent.instrumentation.FileInputStreamConstructorInstrumentationTests2.testByteBuddyfileInputStreamConstructor(FileInputStreamConstructorInstrumentationTests2.java:49)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    ....................
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

FileInputStreamCtorString: after calling static method
FileInputStreamCtorString: inside catchcom/example/javaagent/instrumentation/FileInputStreamConstructorInstrumentationTests2$FileInputStreamCtorString

java.lang.NoClassDefFoundError: com/example/javaagent/instrumentation/FileInputStreamConstructorInstrumentationTests2$FileInputStreamCtorString
    at java.base/java.io.FileInputStream.<init>(FileInputStream.java:111)
    at com.example.javaagent.instrumentation.FileInputStreamConstructorInstrumentationTests2.testByteBuddyfileInputStreamConstructor(FileInputStreamConstructorInstrumentationTests2.java:49)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    ...................
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

FileInputStreamCtorString: after setting static field
File deleted successfully

Advice is inlined by Byte Buddy, as if the code was part of the targeted method.建议由 Byte Buddy 内联,就好像代码是目标方法的一部分一样。 That is unless if you set the delegate property to true.除非您将delegate属性设置为 true。 This will however take its ability to access private members of the instrumented class.然而,这将需要它访问已检测的 class 的私有成员的能力。

If you need utilities, you need to add them to the instrumented codes class loader and make them public.如果您需要实用程序,则需要将它们添加到检测代码 class 加载程序中并公开它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM