This blog is subject the DISCLAIMER below.

Friday, December 21, 2007

Java Byte Code Instrumentation

Welcome people :)

If you have used reflection before, you probably have tasted the power and flexibility it can give you. Especially the setAccessible function that lets you access private methods and fields, and the newInstance function that lets you load classes at run-time.

Anyway, sometimes you need to change something in the code. Or at least want to get notified on some function call (related: Aspect Oriented Programming, terms: aspectj, aspectwerkz).

If you have the source, then it is not a problem to go and modify, and recompile. Some cases it will take a lot of modifications for example if you want to log all function calls (aspectj can help in that regard). But in other cases where you don't have the code or where you can't redeploy the modified package in other machines, for license restrictions or for deployment overhead you can't do that(aspectwerkz will help in this time).

Both aspectj and aspectwerkz provides facilities to modify the classes based on aspect oriented programming rules, which may may not be enough for your desired task. However, have you ever considered how these are implemented ?

They are implemented using byte code engineering techniques. aspectj uses BCEL, and aspectwerkz uses ASM. Those libraries are simple, they just provide abstraction above the byte level to the java methods and fields level.

The main problem is in the JVM. The JVM provides strong checks on the byte code, so for example, a constructor must call the direct super class constructor (I tried to bypass that myself and I got a Wrong Constructor Called exception !). The JVM's ugliest part, is that it doesn't support class reloading. (to be fair it is supported in the debug mode given that the class have the same schema; methods and fields). JDK 1.5 provides a way to reload classes dynamically (as often as you want) using JVMTI (JVM Tool Interface) java.lang.instrument (it can be used natively too) . However it doesn't support schema changes. So statically, or at load time (JVMTI supports that too, you don't have to write your own class loader for that), add, remove, and modify all the methods or fields you anticipate that you would need, even if you just add an empty method. Then at anytime later, you can define the exact body of the method. In case you only want to change the implementation, then no need for load time modifications. You can do it anytime. JVMTI is the successor for JVMPI and JVMDI (JVM profiling and debugging interface). Maybe I will write about JVMTI and native Java programming sometime later.

aspectj modifies the class file itself (build-time offline weaving), while aspectwerkz can do that, beside deployment-time online weaving (it also support run-time online weaving using JVMTI).

Example of using BCEL:
http://mohammad.nabil.h.googlepages.com/DefaultCtorNeutralizer.java
That example replaces the default constructor with a stub constructor that check on a boolean variable, if equal true, it won't call the default constructor, otherwise it will.

1 comment:

praneeth said...

excellent