i want to intercept the connect() method of java.net.HttpURLConnection. for that i am using below provided code. The provided code intercepts the connect method of the HttpURLConnection class in Java 8. However, when attempting to run the same code with Java 17, it results in an error provided below. please provide any solutions or suggestion.
CODE :
package com.bytebuddy.bytebuddydemo.test;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.loading.ClassInjector;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;
import java.io.File;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.util.Collections;
import java.util.concurrent.Callable;
public class Test {
public static void main(String[] args) throws Exception {
premain(null, ByteBuddyAgent.install());
HttpURLConnection urlConnection = (HttpURLConnection) new URL("http://www.google.com").openConnection();
System.out.println(urlConnection.getRequestMethod());
System.out.println(urlConnection.getResponseCode());
}
public static void premain(String arg, Instrumentation instrumentation) throws Exception {
File tempDirectory = Files.createTempDirectory("tmp").toFile();
ClassInjector.UsingInstrumentation
.of(tempDirectory, ClassInjector.UsingInstrumentation.Target.BOOTSTRAP, instrumentation)
.inject(Collections.singletonMap(new TypeDescription.ForLoadedType(MyInterceptor.class),
ClassFileLocator.ForClassLoader.read(MyInterceptor.class)));
new AgentBuilder.Default().ignore(ElementMatchers.nameStartsWith("net.bytebuddy."))
.with(new AgentBuilder.InjectionStrategy.UsingInstrumentation(instrumentation, tempDirectory))
.type(ElementMatchers.nameEndsWith(".HttpURLConnection"))
.transform((builder, typeDescription, classLoader, module) -> builder
.method(ElementMatchers.named("connect")).intercept(MethodDelegation.to(MyInterceptor.class)))
.installOn(instrumentation);
}
public static class MyInterceptor {
public static void intercept(@SuperCall Callable<?> zuper, @Origin Method method) throws Exception {
System.out.println("Intercepted!");
System.out.println("method :: !" + method);
zuper.call();
}
}
}
ERROR :
Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
Exception in thread "main" java.lang.ExceptionInInitializerError
at java.base/sun.net.www.protocol.http.Handler.openConnection(Handler.java:62)
at java.base/sun.net.www.protocol.http.Handler.openConnection(Handler.java:57)
at java.base/java.net.URL.openConnection(URL.java:1094)
at com.JavaAgent.Agent.Test.main(Test.java:26)
Caused by: java.lang.reflect.InvocationTargetException
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 java.base/sun.net.www.protocol.http.HttpURLConnection.(HttpURLConnection.java:435)
... 4 more
Caused by: java.lang.reflect.InvocationTargetException
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 net.bytebuddy.dynamic.Nexus.initialize(Nexus.java:143)
... 9 more
Caused by: java.lang.IllegalStateException: Cannot load injected class
at net.bytebuddy.dynamic.loading.ClassInjector$UsingInstrumentation.injectRaw(ClassInjector.java:2498)
at net.bytebuddy.dynamic.loading.ClassInjector$AbstractBase.inject(ClassInjector.java:118)
at net.bytebuddy.agent.builder.AgentBuilder$InitializationStrategy$SelfInjection$Dispatcher$InjectingInitializer.onLoad(AgentBuilder.java:3855)
... 14 more
Caused by: java.lang.ClassNotFoundException: sun/net/www/protocol/http/HttpURLConnection$auxiliary$vcxnSSGw
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:467)
at net.bytebuddy.dynamic.loading.ClassInjector$UsingInstrumentation.injectRaw(ClassInjector.java:2487)
... 16 more
When executing the provided code in Java 17, a compilation error occurs in the transform method, indicating that it requires five parameters. To resolve this, the missing parameter, which is protectionDomain, is added to the method signature, allowing successful compilation. However, at runtime, the program throws an exception.
Reproducing the answer from this GitHub Gist, so the question can be marked as accepted:
package net.bytebuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.loading.ClassInjector;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
import java.net.URL;
import java.util.Collections;
import java.util.concurrent.Callable;
import static net.bytebuddy.matcher.ElementMatchers.none;
/**
* Inspired by <a href="https://github.com/apache/skywalking">Apache SkyWalking</a>, specifically
* <a href="https://github.com/apache/skywalking/blob/bc64c6a12770031478d29e2f19004796584374c9/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java">
* this class</a>. Discussed in <a href="https://github.com/raphw/byte-buddy/issues/697">Byte Buddy issue #697</a>.
* <p>
* Successfully tested on JDKs 8 to 21. Should print:
* <pre>
* Intercepted!
* GET
* </pre>
*/
public class BootstrapAgent {
public static void main(String[] args) throws Exception {
premain(null, ByteBuddyAgent.install());
Object urlConnection = new URL("http://www.google.com").openConnection();
System.out.println(urlConnection.getClass().getMethod("getRequestMethod").invoke(urlConnection));
}
public static void premain(String arg, Instrumentation instrumentation) throws Exception {
ClassInjector.UsingUnsafe.Factory factory = ClassInjector.UsingUnsafe.Factory.resolve(instrumentation);
factory.make(null, null).injectRaw(
Collections.singletonMap(
MyInterceptor.class.getName(),
ClassFileLocator.ForClassLoader.read(MyInterceptor.class)
)
);
AgentBuilder agentBuilder = new AgentBuilder.Default();
agentBuilder = agentBuilder.with(new AgentBuilder.InjectionStrategy.UsingUnsafe.OfFactory(factory));
agentBuilder
.ignore(none())
.assureReadEdgeFromAndTo(instrumentation, Class.forName("java.net.HttpURLConnection"))
.assureReadEdgeFromAndTo(instrumentation, MyInterceptor.class)
.ignore(ElementMatchers.nameStartsWith("net.bytebuddy."))
.type(ElementMatchers.nameContains("HttpURLConnection"))
.transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
.method(ElementMatchers.named("getRequestMethod"))
.intercept(MethodDelegation.to(MyInterceptor.class))
)
.installOn(instrumentation);
}
public static class MyInterceptor {
public static String intercept(@SuperCall Callable<String> zuper) throws Exception {
System.out.println("Intercepted!");
return zuper.call();
}
}
}
Try it on JDoodle.