Alternative ways of toString() generation with AnnoJ

October 15, 2009

In  the post “Using the @ToString annotation” you saw how easy it is to use @ToString. In this post I’ll show you how you can generate toString() methods in classes without using MainMethodBootstrap

The annoj.annotation.transformers package contains classes that are responsible for transforming class bytecode. Currently there’s one for toString() generation and onew for logging. In order to be able to instrument classes you have to instantiate TransformingClassLoader with a list of ClassTransformer objects and use that instance for loading the classes you want to modify. For example:

     List tl = Collections.singletonList(new ToStringCreator());
     TransformingClassLoader loader = new TransformingClassLoader(tl);
     loader.loadClass("Person");

This classloader modifies the classes if it finds the appropriate annotations. It’s important that the classloader should only be used in a so called bootstrap class which loads this classloader and then loads the classes with it.


How does AnnoJ work?

October 14, 2009

As you might guess AnnoJ modifies the bytecode of your classes. When TransformingClassLoader (the custom classloader used by AnnoJ) is asked to load a class it checks if its methods/fields or the entire class is annotated with @Loggable, @ToString or @Exclude. After that it tries to transform the bytecode of the class according to the annotations. If you use MainMethodBootstrap to start your application all classes are loaded with TransformingClassLoader.

AnnoJ uses javassist for bytecode modification. With this library it’s fairly easy to accomplish the neccessary transformations. For example the code below adds a logging method call to the beggining of the methods of a class called className:

     ClassPool pool = ClassPool.getDefault();
     CtClass ct = pool.get(className);
     CtMethod[] methods = ct.getDeclaredMethods();

     for (CtMethod method : methods) {
          method.insertBefore("{System.out.println(\"invoked: " + method.getName() + "(\" +  java.util.Arrays.asList($args) +\")\");}");
     }

     ct.toClass();

As you can see you don't have to bother yourself with the byecode - it can be modified at Java level. For more information consult the javassist documentation.


Why is AnnoJ useful?

October 14, 2009

Consider an application full of generated classes (by wsimport, for example). When many methods accepts this generated types as parameters logging/debugging is mere pain. If a method is called and you need to see the internal state of the paraeter object you have to work hard – unless you have an efficient tool for the job.

With @ToString annotation AnnoJ is able to generate toString() methods so you only have to print the parameters the object will show you its internal state.

Or think about logging. Sometimes it’s important to log when a method is called. How does AnnoJ help you? By using @Loggable annotation it can implement this kind (and many other kinds in the future) of logging.

.


Introducing AnnoJ

October 14, 2009

AnnoJ is a small library containing tools for developers. With Annoj you can avoid writing boilerplate code in some cases. The current version of AnnoJ has to features:

  • automated generation of logging code
  • automated generation of toString() methods

As you can see, both features facilitate logging.

In AnnoJ everything is implemented with annotations. You can download the library from the sourceforge project page. To read the API documentation visit this link.


Follow

Get every new post delivered to your Inbox.