Create simple POJO classes (bytecode) at runtime (dynamically)

Creating a simple POJO with getters and setters is easy if you use CGLib:

public static Class<?> createBeanClass(
    /* fully qualified class name */
    final String className,
    /* bean properties, name -> type */
    final Map<String, Class<?>> properties){

    final BeanGenerator beanGenerator = new BeanGenerator();

    /* use our own hard coded class name instead of a real naming policy */
    beanGenerator.setNamingPolicy(new NamingPolicy(){
        @Override public String getClassName(final String prefix,
            final String source, final Object key, final Predicate names){
            return className;
        }});
    BeanGenerator.addProperties(beanGenerator, properties);
    return (Class<?>) beanGenerator.createClass();
}

Test code:

public static void main(final String[] args) throws Exception{
    final Map<String, Class<?>> properties =
        new HashMap<String, Class<?>>();
    properties.put("foo", Integer.class);
    properties.put("bar", String.class);
    properties.put("baz", int[].class);

    final Class<?> beanClass =
        createBeanClass("some.ClassName", properties);
    System.out.println(beanClass);
    for(final Method method : beanClass.getDeclaredMethods()){
        System.out.println(method);
    }

}

Output:

class some.ClassName
public int[] some.ClassName.getBaz()
public void some.ClassName.setBaz(int[])
public java.lang.Integer some.ClassName.getFoo()
public void some.ClassName.setFoo(java.lang.Integer)
public java.lang.String some.ClassName.getBar()
public void some.ClassName.setBar(java.lang.String)

But the problem is: you have no way of coding against these methods, as they don't exist at compile time, so I don't know what good this will do you.


Well This may also given a try. But I need to understand this if anyone can explain.

UPDATE :

Imagine your application have to create Java POJO instances dynamically at runtime from some external configuration. This task can be easily done using one of the bytecode manipualtion library. This post demonstrates how this can be done using Javassist library.

Assume we have following configuration for the properties our dynamically created POJO should contain:

Map<String, Class<?>> props = new HashMap<String, Class<?>>();
props.put("foo", Integer.class);
props.put("bar", String.class);

Let’s write a PojoGenerator, that dynamically generates a Class object for the given class name and a map, containing required properties:

import java.io.Serializable;
import java.util.Map;
import java.util.Map.Entry;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.NotFoundException;

public class PojoGenerator {

public static Class generate(String className, Map<String, Class<?>>  properties) throws NotFoundException,
        CannotCompileException {

    ClassPool pool = ClassPool.getDefault();
    CtClass cc = pool.makeClass(className);

    // add this to define a super class to extend
    // cc.setSuperclass(resolveCtClass(MySuperClass.class));

    // add this to define an interface to implement
    cc.addInterface(resolveCtClass(Serializable.class));

    for (Entry<String, Class<?>> entry : properties.entrySet()) {

        cc.addField(new CtField(resolveCtClass(entry.getValue()), entry.getKey(), cc));

        // add getter
        cc.addMethod(generateGetter(cc, entry.getKey(), entry.getValue()));

        // add setter
        cc.addMethod(generateSetter(cc, entry.getKey(), entry.getValue()));
    }

    return cc.toClass();
}

private static CtMethod generateGetter(CtClass declaringClass, String fieldName, Class fieldClass)
        throws CannotCompileException {

    String getterName = "get" + fieldName.substring(0, 1).toUpperCase()
            + fieldName.substring(1);

    StringBuffer sb = new StringBuffer();
    sb.append("public ").append(fieldClass.getName()).append(" ")
            .append(getterName).append("(){").append("return this.")
            .append(fieldName).append(";").append("}");
    return CtMethod.make(sb.toString(), declaringClass);
}

private static CtMethod generateSetter(CtClass declaringClass, String fieldName, Class fieldClass)
        throws CannotCompileException {

    String setterName = "set" + fieldName.substring(0, 1).toUpperCase()
            + fieldName.substring(1);

    StringBuffer sb = new StringBuffer();
    sb.append("public void ").append(setterName).append("(")
            .append(fieldClass.getName()).append(" ").append(fieldName)
            .append(")").append("{").append("this.").append(fieldName)
            .append("=").append(fieldName).append(";").append("}");
    return CtMethod.make(sb.toString(), declaringClass);
}

private static CtClass resolveCtClass(Class clazz) throws NotFoundException {
    ClassPool pool = ClassPool.getDefault();
    return pool.get(clazz.getName());
}
}

That’s it!

Using PojoGenerator is quite simple. Let’s generate some POJO, output via reflection all its methods, set and then get some property:

public static void main(String[] args) throws Exception {

Map<String, Class<?>> props = new HashMap<String, Class<?>>();
props.put("foo", Integer.class);
props.put("bar", String.class);

Class<?> clazz = PojoGenerator.generate(
        "net.javaforge.blog.javassist.Pojo$Generated", props);

Object obj = clazz.newInstance();

System.out.println("Clazz: " + clazz);
System.out.println("Object: " + obj);
System.out.println("Serializable? " + (obj instanceof Serializable));

for (final Method method : clazz.getDeclaredMethods()) {
    System.out.println(method);
}

// set property "bar"
clazz.getMethod("setBar", String.class).invoke(obj, "Hello World!");

// get property "bar"
String result = (String) clazz.getMethod("getBar").invoke(obj);
System.out.println("Value for bar: " + result);

}

Executing above will result in the following console output:

Clazz: class net.javaforge.blog.javassist.Pojo$Generated
Object: net.javaforge.blog.javassist.Pojo$Generated@55571e
Serializable? true
public void     net.javaforge.blog.javassist.Pojo$Generated.setBar(java.lang.String)
public java.lang.String     net.javaforge.blog.javassist.Pojo$Generated.getBar()
public java.lang.Integer     net.javaforge.blog.javassist.Pojo$Generated.getFoo()
public void     net.javaforge.blog.javassist.Pojo$Generated.setFoo(java.lang.Integer)
Value for bar: Hello World!