Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding code to a Java class w/ Instrumentation: ASM or BCEL?

I am writing a game engine/library in which I have an event dispatcher class which dispatches events by calling listener methods of "registered" event handler classes. One can register an event handler/listener with the event dispatcher by calling the appropriate dispatcher method.

This obviously leads to some boilerplate code for registering every event handler(and also other aspects of my engine have similar bolierplate code), so I was wondering - how about just using Instrumentation to add in all of the necessary code during loading of the event handler class, so that no explicit registration with the event dispatcher is necessary while coding - the call to the dispatcher's register method is added in automatically when the program is run.

It is my understanding that in order to use Instrumentation one should use some bytecode modifier API. I know of two - ASM and BCEL. Which one should I use? Obviously, this is a somewhat simple task I am trying to do, so I want the one which is easier to learn and better documented.

EDIT: Here is a specific example.

Original event handler class:

@Handler //indicates this this class should be transformed
public class MouseEventHandler implements EventHandler<MouseEvent>
{
    //hidden default constructor
    public void handleEvent(MouseEvent event)
    { ... }
}

After transformation:

@Handler
public class MouseEventHandler implements EventHandler<MouseEvent>
{
    public MouseEventHandler()
    {
        //add this line of code to default constructor
        Game.getEventDispatcher().addEventHandler(this);
    }
    public void handleEvent(MouseEvent event)
    { ... }
}
like image 938
user1299784 Avatar asked Apr 18 '12 07:04

user1299784


People also ask

What does ASM stand for in Java?

ASM simply stands for ASMifier tool.

How do you use ASM?

How do I start using ASM? If you want to use ASM to generate classes from scratch, write a Java source file that is representative of the classes you want to generate, compile it(*), and then run the ASMifier on the compiled class to see the Java source code that generates this class with ASM.

What is instrumentation in Java?

Instrumentation is the addition of byte-codes to methods for the purpose of gathering data to be utilized by tools. Since the changes are purely additive, these tools do not modify application state or behavior.

What is ASM library?

The ASM library is a project of the OW2 consortium. It provides a simple API for decomposing, modifying, and recomposing binary Java classes (i.e. bytecode). The project was originally conceived and developed by Eric Bruneton.


2 Answers

Java bytecode libraries:

  • ASM is fast and actively developed.
  • BCEL is comparatively slow.
  • Javassist is probably easiest to get started with if you're not familiar with Java bytecode.
  • cglib builds on top of ASM, providing some higher level abstractions.
  • Byte Buddy generates classes via a DSL. Actively maintained and seeing increasing usage.

I would however consider other options before jumping into bytecode manipulation.

like image 79
henry Avatar answered Nov 11 '22 09:11

henry


Adding the logic to a few classes might be boring, but unless you've thoushands of handlers, that's the way I would go. Keep it simple.

That said,

Game.registerHandler( this );

would be more object-oriented.

An alternative to adding the logic in each class is to introduce a factory that is responsible to instantiate the handlers.

HandlerFactory.createMouseHandler();

And method createMouseHandler contains something like

Handler mh = new MousheHandler();
registerHandler(mh);
return mh;

If you don't want either of these options, I would consider either an aspect framework (maybe AspectJ) or a container for Invertion of Control (maybe Spring IoC). Aspects allow you to annotate your source, and "weave" code at the selected places. An IoC container allows you to control the lifecycle of object (e.g. instantiation). Both use bytecode instrumentation behind the scene.

But if you want to do the instrumentation yourself, I can only compare Javassist and ASM that I used personally.

ASM is low-level, and operates really at the level of java bytecode. You must be familiar with it. The framework is very well designed, the manual is excellent, and it is a great library. One one side it can be complicate to replace patterns of bytecode, because it requires a so-called "stateful" transformation. One the other side, you have full control over the bytecode.

Javassist is more high-level. You do not operate at the raw level of bytecode, a slight higher level, e.g. fields read/write, message send, constructors. Also, it allows you to specify changes using regular java syntax, that is then compiled by the framework. The API is a bit confused, because the project grew over the years. There is documentation about the framework, but not so well centralized as with ASM.

like image 44
ewernli Avatar answered Nov 11 '22 08:11

ewernli