net.javaforge.blog - How to create Java POJOs dynamically at runtime with Javassist

Install this theme
How to create Java POJOs dynamically at runtime with Javassist

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!
PRINT THIS POST WORDS: Notes: 2 View comments 9/20/12 — 10:09am Short URL: https://tmblr.co/ZwTERuTkDEb7 Filed under: #java #bytecode #generation #pojo #javassist
 
  1. nreoj11 liked this
  2. javaforge posted this
View the discussion thread
Blog comments powered by Disqus

AltStyle によって変換されたページ (->オリジナル) /