Jakarta’s BCEL vs. ObjectWeb’s ASM Java “yield return” code published
Jul 20

In order to implement the Yielder feature, it was not enough to understand what I want to do and implement it using a bytecode manipulation framework – I also had to hook into the JVM to manipulate any Yielder implementation at runtime.

At first I thought of having a Factory design pattern, where Yielder implementations would be passed to it and, using a specialized ClassLoader, I could create a new class which is a copy of the original one with the difference in the yieldNextCore method.

This would look something like:


class YielderClassLoader extends ClassLoader {
  public findClass(String name)
      throws ClassNotFoundException {
    String originalName = getOriginalName(name);
    if (classIsYielder(originalName)) {
      byte[] b = Trasnformer.transform(originalName);
    }
  }
}

class YielderFactory {
  private YielderClassLoader = ...;
  public static Yielder createYielder(Class yielderClass)
      throws Exception {
    String newName = getNewName(yielderClass.getName());
    Class generated = yielderClassLoader.loadClass(newName);
    return generated.newInstance();
  }
}

The yielder would be implemented using some concrete class, passed to the factory where it would be loaded normally and passed into the bytecode manipulation framework to create a new class with a new name. This turned out to be a bad idea, for several reasons.

First, it was a mess changing the constants pool in the class. Even with ASM dealing with most of the work, there were still a few gotchas there. Second, and most importantly, it prevented from using the more intuitive anonymous class. In fact, it forced all Yielder subclasses to have a default constructor, which forced them to have an init method to accept all external data (such as the predicate and collection, in previous post’s example).

I was looking for something more elegant. That’s when I noticed the Instrumentation feature, new in Java 5.

The idea is that a user can write an agent which will apply some rules over loaded classes. The reason behind it was to add hooks for AOP, profiling and debugging frameworks, making them more elegant. I’ve decided to use the same hook. I can’t say I’m fully pleased with the decision – this feature was not meant to be used for these kind of manipulations. However, there really isn’t a good place for these sort of manipulations as Java doesn’t really (and for a good reason) allow for language feature changes or additions.

Using the agent also had the added benefit of not needing to create a second class: instead, the original class was just manipulated and any call to new MyYielder would invoke the agent’s transformation. The transformation was added using the premain method, marked in the JAR’s manifest file using the Premain-Class attribute:


public static void premain(String arg, Instrumentation inst) {
  inst.addTransformer(new ClassFileTransformer() {
    public byte[] transform(ClassLoader loader,
        String className,
        Class< ?> classBeingRedefined,
        ProtectionDomain protectionDomain,
        byte[] classfileBuffer)
          throws IllegalClassFormatException {
      return Transformer.transform(classfileBuffer);
    }
}

Now, in order to use the yielder, it needs to be in the classpath like everything else but a flag needs to be passed to the JVM in order to let it know that the JAR contains an agent, using the -javaagent:yielder.jar flag. So far, this seems like a clean and elegant solution. Comments are, as always, welcome.

  • Share/Bookmark

Leave a Reply

Chaotic Java is Digg proof thanks to caching by WP Super Cache