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\"" + ";"
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