Reputation: 31
First time class is created successfully but next time when there is change in class (like add some variables) It throws an error. Below is my code.
ClassPool pool = ClassPool.getDefault();
CtClass cc=null;
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if (contextClassLoader != null)
{
pool.insertClassPath(new LoaderClassPath(contextClassLoader));
}
try{
cc = pool.makeClass(className);
cc.defrost();
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()));
}
cc.addConstructor(generateConstructor(cc,properties,className));
CtConstructor defaultCons=new CtConstructor(NO_ARGS, cc);
defaultCons.setBody(";");
cc.addConstructor(defaultCons);
return cc.toClass();
}catch(Exception e){
cc = pool.get(className);
cc.detach();
cc = pool.makeClass(className);
cc.defrost();
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()));
}
cc.addConstructor(generateConstructor(cc,properties,className));
CtConstructor defaultCons=new CtConstructor(NO_ARGS, cc);
defaultCons.setBody(";");
cc.addConstructor(defaultCons);
return **cc.toClass();** // getting error at this line
}
Upvotes: 2
Views: 4990
Reputation: 44032
You need to write a Java agent and attach it dynamically to transform a class after it was already loaded. A Java agent defines a method named agentmain
which takes an instance of Instrumentation
as its second argument. With such a Java agent, the changes you are allowed to apply are however limited to changing the body of a method, you cannot add members (fields or methods) or change the signature of existing ones.
You call Instrumentation::redefineClass
to apply a redefinition.
You can find articles on how to change loaded code on several places online.
Upvotes: 4
Reputation: 140447
Simple answer: you can't (easily).
The point is: when the class is already loaded then the JVM has already information about that class. The "default" classloader simply does not allow you to replace that definition with a new one.
If you want to dynamically exchange class definitions, you have to turn to the advanced topic of writing your own classloader that allows for such things. See here as starting point.
Upvotes: 1