4

Currently I'm trying to modify method bodies residing in classes already loaded by the JVM. I'm aware of the JVM actually not allowing to change the definition of classes that have already been loaded. But my researches brought me to implementations like JRebel or Java Instrumentation API, both using an agent-based approach. I know how to do it right before a class is loaded o behalf of Javassist. But considering e.g. JRebel in an EJB environment where class definitions are loaded on application startup, shouldn't bytecode modification be possible on JVM-loaded classes?

lospejos
  • 1,976
  • 3
  • 19
  • 35
pklndnst
  • 726
  • 2
  • 10
  • 27

2 Answers2

9

Well, you learned that the Instrumentation API exists and it offers redefinition of classes as an operation. So then it is time to rethink you initial premise of “the JVM actually not allowing to change the definition of classes that have already been loaded”.

You should note that

  • as the links show, the Instrumentation API is part of the standard API
  • the support of redefinition of classes is, however, optional. You may ask whether the current JVM supports this feature
  • it might be limited to not support every class; you may ask whether it’s possible for a particular class
  • Even if it is supported, the changes may be limited, to cite the documentation:

    The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance. These restrictions maybe be lifted in future versions.

  • at the time you perform the redefinition, there might be threads executing code of methods of these classes; these executions will complete using the old code then

So the Instrumentation is merely useful for debugging and profiling, etc.

But other frameworks, like EJB containers, offering class reloading in production code, usually resort to creating new ClassLoaders which create different versions of the classes which then are entirely independent to the older versions.

In a Java runtime environment, the identity of a class consists of a pair of <ClassLoader, Qualified Name> rather than just a qualified name…

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Thank you Holger. So what I know now is that redefine a class by changing a method body (which completely satisfies my needs) is still possible. So the docs say that an Instrumentation object can be obtained as a parameter when a Java agent gets started. Is it allowed to store a reference to this object and call method on it later from my running application when I want to redefine an arbitrary class? – pklndnst Apr 27 '15 at 12:12
  • 1
    It works and there is no additional constraint about this usage pattern, you just have to be aware that you are using a feature that might not be supported by every JVM. At the end of [this answer](http://stackoverflow.com/a/19912148/2711488) is an example code of an application that (re-)launches itself as a Java-Agent while already running to get hands on the Instrumentation API. – Holger Apr 27 '15 at 12:30
3

I wasn't aware that you can use the instrumentation API to redefine classes (see @Holger's answer). However, as he notes, there are some significant limitations on that approach. Furthermore, the javadoc says:

"This method is intended for use in instrumentation, as described in the class specification."

Using it to materially change the semantics of a class is ... all sorts of bad from the perspective of the Java type system.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216