Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I modify a java.lang class on the fly?

I'm looking for a way to add fields to an Thread on the fly by rewriting the byte code and reloading the class, not sure if it is at all possible. Any pointers welcome. I found some info on modifying and loading a class, and I know JRebel can seamlessly hot swap your code but not sure if the same approach/tools apply here.

The motivation here is exploring a theoretically better alternative to thread local objects. Should the method work I should be able to replace thread local with an annotation and the result should outperform current JDK implementation.

PS: Please save me the "root of all evil speech"

Clarifying use case:

Imagine I have a class with a ThreadLocal:


class A {
   ThreadLocal&ltCounter&gt counter;
   ...
   counter.get().inc()
}

I'd like to replace that with an annotation:


class A {
   @ThreadLocal
   Counter counter;
   ...
   counter.inc()
}

But instead of the above code getting generated I'd like to mutate Thread such that Thread will now have an Acounter field and the actual code will be:


class A {
   // Nothing here, field is now in Thread
   ...
   Thread.currentThread().Acounter.inc()
}
like image 545
Nitsan Wakart Avatar asked Jun 07 '13 14:06

Nitsan Wakart


People also ask

How do you reload a class in Java?

Once a Java class has been loaded by a class loader, it's immutable and will last as long as the class loader itself. The identity is the class name and class loader identity, so to reload an application, you'll need to create a new class loader which in turn will load the latest version of the app classes.

What is ClassLoader in Java with example?

The Java ClassLoader is a part of the Java Runtime Environment that dynamically loads Java classes into the Java Virtual Machine. The Java run time system does not need to know about files and file systems because of classloaders. Java classes aren't loaded into memory all at once, but when required by an application.


1 Answers

At present it is impossible to redefine a class at runtime such that the redefinition will result in new methods or fields. This is due to the complexity involved in scanning the heap for all existing instances and transforming them + their references + potential Unsafe field offset base updaters (like AtomicFieldUpdater).

This limitation may be lifted as part of the JEP-159 but as discussed on the concurrency-interest mailing group this is a big impact change so may never happen at all.

Using Javaassist/similar will allow the transformation of a class to a new class with new methods/fields. This class can be loaded by a ClassLoader and used at runtime, but it's definition will not replace existing instances. So it will not be possible to use this method combined with an agent to redefine the class as an instrumentation redefinition is limited such that: "The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields ..." see here.

So for now, NO.

like image 128
Nitsan Wakart Avatar answered Oct 13 '22 00:10

Nitsan Wakart