JDK-8200559: Offer a means for Java agents to define auxiliary classes

Rafael Winterhalter rafael.wth at gmail.com
Sun Oct 26 17:07:02 UTC 2025


Hello,

I wanted to ask if https://bugs.openjdk.org/browse/JDK-8200559 is still
considered. I did a recent inventory for where users of Byte Buddy still
use Unsafe after Java 21, and this is the only real remaining case.

For a recap of the past discussion, agents often need to:

   1.

   Inject classes to satisfy API contracts of added code. For example, one
   might need to invoke a method on an object that is provided to the method.
   If this method accepts a Runnable, the agents need to add a class that
   implements that method.
   2.

   Inject classes to make use of subtypes when a state needs to be
   transported from one instrumented method to another. For example, one might
   want to add a tracing id to an object that the first instrumented method
   returns. When the second instrumented method later receives this object,
   the instance can be cast to the subclass and the id can be read.
   3.

   Inject classes for communication between the instrumented methods and
   the agent, often into the bootstrap class loader. This as the agent is
   always loaded on the system class loader whereas instrumented classes might
   not be loaded within a hierarchy that includes that loader.


To define classes at runtime, one is today supposed to use
MethodHandle::defineClass. However, agents often run prior to a class being
loaded, and no handle is available. Mandy Chung suggested a patch where the
ClassFileTransformer would receive an alternate form of a MethodHandle in
an overloaded method, to overcome this limitation. I argued that this would
only solve (1), but not (2) and (3) and that the patch was ultimately
rejected. I suggested instead adding a method to the Instrumentation
interface: Instrumentation::defineClass(ClassLoader, byte[]). This would be
the simplest solution and allow for an easy adoption. However, no further
work was done on this issue.

As of today, I am aware of the following approaches used by agents:

   1.

   One can inject classes into the boot loader, where they are globally
   visible to all class loaders, using
   Instrumentation::appendToBootSearchPath. This does however not work when a
   class needs to be added to a known java.* package, and it thus normally
   requires adjusting module read edges, which is rather inconvenient. Also,
   it requires a JarFile instance for each injection, which can also be
   problematic with regards to using the local file system.
   2.

   One can retransform a known class prior to installing a
   ClassFileTransformer. In this known class one adds code that reads a local
   MethodHandle, and that then defines the auxiliary class. This code is then
   run before transforming the actual class.
   3.

   One can to some degree add methods to classes and use invokedynamic to
   create classes. This does not work with retransformation however.
   4.

   One can instrument class loaders to resolve classes from alternative
   locations, with the expectation of the bootstrap class loader.
   5.

   One can use Instrumentation::redefineModule for opening the base module
   to the agent. This allows using jdk.internal.misc.Unsafe::defineClass. This
   as sun.misc.Unsafe does no longer offer a defineClass method. This is the
   most common approach today as far as I am aware of it.


I was still hoping that adding Instrumentation::defineClass(ClassLoader,
byte[]) could be considered. Even better with a varargs argument to allow
defining multiple classes that might depend on each other. Alternatively,
one could add a method to Instrumentation that allows adding a resolver
Function<String, Optional<byte[]>> which any class loader would need to
query for alternative class files, something that could be wired into
java.lang.ClassLoader. I do however wonder if this would be too complicated.

I am happy to implement anything that helps with this and send a PR. I do
however think that this is mainly a specification task. Personally, I would
just hope to avoid using Unsafe altogether, but on this issue Byte Buddy
still cannot offer a solution using only the official API and therefore
allows users to emulate the suggested Instrumentation::defineClass via
jdk.internal.misc.Unsafe.

Thanks for your consideration and let me know if I can be of any help
implementing a solution.

Best regards, Rafael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20251026/79d20513/attachment.htm>


More information about the core-libs-dev mailing list