Creating Classes Dynamically

The first question you normally ask is why do we need to create classes dynamically. I have came across many situation where I have to modify the exisitng classes by adding some functionality.

Recently when I was working with Carbonado, I got a chance where I modified the exisitng class. Interesting part here is, Carbonado also uses the same opensource tool for creating classes dynamically.

This is the reason why i thought of sharing this information.

Before Carbondao I was using Berkeley DB Java Edition (another in-memory database) where we can store the data object directly into memory. Following is my data class.



public class Employee {
private String ID;
private String firstName;
private String lastName;
private String email;

public String getID() {
return ID;
}

public void setID(String id) {
ID = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
}



Using the API's provided by Berkeley DB, I was able to insert the object into my memory.

Later the requirements changed and I have to do the same using Carbonado.

But Carbonado need the presitence classes to be decorated using some annotations and with some extension. I did like modifying the exisitng class, instead I planned to modify the classes on fly.

For this I created a dummy class with Carbonado requirement. The dummy class looks like

@PrimaryKey("pkey")
public interface CarbonadoStore extends Storable {
String getPkey();
void setPkey(String pkey);
}


Later I modified my 'Employee' class such that it implements the CarbonadoStore interface so that it meet all the requirements of carbonado and ready for presitence.

The dynamic creation of class is done using 'cojen' open soure component.

Following is the code snippet which I used for modification.


public void save(String key, Object object)
{
Class store = createStorableInterface(object.getClass());
Storage storage;
storage = repository.storageFor(store);
Storable message = storage.prepare();
copyObjectToMessage(object, message); //Copy the data of objet to message class using reflection.
message.insert();
}


private Class createStorableInterface(Class objClz)
{
Class store = null;
ClassFile cf = ClassFile.readFrom(getClass().getResourceAsStream(
"CarbonadoStore.class"));
Method[] methods = objClz.getDeclaredMethods();
for (Method method : methods) {
cf.addMethod(Modifiers.PUBLIC_ABSTRACT, method.getName(),
TypeDesc.forClass(method.getReturnType()),
getParamTypes(method.getParameterTypes()));
}

ByteArrayOutputStream out = new ByteArrayOutputStream();

cf.writeTo(out);
CPClassLoader cloader = new CPClassLoader(objClz.getClassLoader());
store = cloader.define(
"com.demo.CarbonadoStore",
out.toByteArray());
return store;
}


private static final class CPClassLoader extends ClassLoader {

CPClassLoader(ClassLoader parent) {
super(parent);
}

CPClassLoader() {
super();
}

Class define(String name, byte[] b) {
Class clazz = defineClass(name, b, 0, b.length);
resolveClass(clazz);
return clazz;
}
}




On doing this now I can reuse the same Employee class for both BerkelyDB and Carbonado operations.