zondag 9 maart 2014

the power of javaassist

Introduction:

Just for fun I tried to weave a method into a class. I have been googling around to find the answers I needed to work wit javaassist. There where a lot of examples that drilled down to the same point and where not working. So i tried a bit and combined some of the stuff together.

The setting:

package org.injector.binding;

import org.injector.annotations.ComponentScan;

This pore litle guy has to say a lot but has no acces to the outside world.

public class CreateSetterStub {
private String greetingsGrashopper;

}

Luckely he has a good friend we are going to meet soon. Here we are going to call him:

public void test() {
                 // The one that needs help
Class class1 = CreateSetterStub.class;
               // Reaching out the helper.
CreateMemberSetter createMemberSetter = new CreateMemberSetter();
createMemberSetter.createSetter("greetingsGrashopper", class1.getName());
try {
CreateSetterStub createSetterStub = (CreateSetterStub)class1.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

       // The friend that is going to help
Class createSetter(String memberName,  String className) {

//The standard classpool as ued by javaassist
                ClassPool pool = ClassPool.getDefault();
// The stanndard classtype as used by javaassist
                CtClass cc = null;
//Here we teached the poor litle creature to speak.
                Class clazz = null;
try {
       Typing the speachless into the javaassist type.
               cc = pool.get(className);
         //pruning itself is a good thing: To reduce memory consumption, pruning discards                                           unnecessary attributes. But if you dont stop, you get errormessages about it. Your flow
             stops.
             cc.stopPruning(true);
             //Creating a method to speak to the outside world.
            CtMethod m2 = CtNewMethod.make("public String getText(){return \"hello world\"" + ";"
               + "}" , cc);
              //adding the method to the class. 
            cc.addMethod(m2);
           create a copy of the original class otherwise you get errors about the same class on the
              claspath.
              cc.replaceClassName(className, className + 2);
              //Type it back to the normal Java Pojo kind a type.
           clazz = cc.toClass();
              // print out the desired message. 
System.out.println( clazz.getDeclaredMethod("getText", null).invoke(clazz.newInstance(),null));
              //Still a load of exception handling todo :).
} catch (NotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CannotCompileException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}  catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return clazz;

Conclusion:

Dealing with javaassist is actually amazingly simple. It has a lot of power. In that perspective, it is wise to use it when needed not for convinience. As allways with power comes responsibility :).

Have fun. 

Geen opmerkingen:

Een reactie posten