[英]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.