domenica 13 gennaio 2013

Class generation with Javassist

With this post you will see how it's easy to create at runtime a class with javassist.
We will go to create a simple javaBean that extends an interface.
The interface is defined at development time as follows:
public interface IBean {

   public String getField();

   public void setField(String field);

}

Now we will create the Bean class at runtime that extends the IBean interface:
public class Generate {
   // If a program is running on a web application server such as JBoss and Tomcat,
   // the ClassPool object may not be able to find user classes.
   // In that case, an additional class path must be registered to the ClassPool.
   static{
      // ClassPool initialization
      ClassPool.getDefault().insertClassPath(new ClassClassPath(IBean.class));
   }

   public static IBean bean(){

      ClassPool cp = ClassPool.getDefault();

      // creation of the class
      CtClass Bean = cp.makeClass("Bean");
      
      // addition of the interface
      Bean.addInterface(cp.get(IBean.class.getName()));

      // creation of an empty constructor
      CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, Bean);

      // its body
      ctConstructor.setBody(";");

      // addition of the constructor
      Bean.addConstructor(ctConstructor);

      // addition of the String field
      Bean.addField(new CtField(cp.get(String.class.getName()), "field", Bean));

      // creation of getField method
      CtMethod getField = CtNewMethod.make("public String getField(){ return field; }",Bean);

      // add method to CtClass
      Bean.addMethod(getField); 

      // creation of setField method
      CtMethod setField = CtNewMethod.make("public void setField(String field){ this.field = field; }",Bean);

      // add method to CtClass
      Bean.addMethod(setField); 

      return (IBean) Bean.toClass().newInstance();

   }
}

In this mode we can create an instance of IBean dynamically, using the IBean interface at development time:
IBean bean = Generate.bean();
bean.setField("example");
assertEqual("example",bean.getField());

The exceptions aren't handled to increase the readability.
This technique is used in the development of JMapper Framework: http://code.google.com/p/jmapper-framework/ You can download the source.jar or checkout the code from svn.

Nessun commento:

Posta un commento