This code is applying an ByteBuddy Advice
to the FileInputStream
constructor. The onEnter
method is actually called but it cannot access static methods and fields.
How can I make accessible static methods and static fields from the onEnter
method?
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:
[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. That is unless if you set the delegate
property to true. This will however take its ability to access private members of the instrumented class.
If you need utilities, you need to add them to the instrumented codes class loader and make them public.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.