My purpose is to dynamically inject new attributes + getter setter methods to a class definition at runtime. Currently I have a method to regenerate the code with newly added attributes which then will compile the generated code.
Initially I'll have a template for each class at compile time. Upon running the project, the template class is loaded to runtime. I have written some code to dynamically generate java code and compile it. When I load the newly created class using the below code, I am not able to access injected methods. I think I am not able to overwrite existing runtime definition. I went through a lot of blogs but still couldn't understand why. Please help.
I am accessing the newly added methods in DROOLS and its not referenced in any other class which can raise issues during compilation. Rules of the rule engine with new attributes are updated at runtime and so I need to adapt my code accordingly. Below is the ClassLoader code. This code doesn't throw any exception but fails to solve my purpose. Not sure if coding is right.
public static boolean loadClass2RunTime() {
try {
File folder = new File("target");
File dir = new File(folder, "com/itap/template");
File[] classFiles = dir.listFiles();
URL[] url = new URL[] { folder.toURI().toURL() };
int i = 0;
for (File classFile : classFiles) {
if (classFile.getName().matches(".*\\.class")) {
System.out.println(classFile.getName().substring(0,
classFile.getName().lastIndexOf(".")));
ClassLoader loader = URLClassLoader
.newInstance(new URL[] { folder.toURI().toURL() });
Class cls = loader.loadClass("com.itap.template."
+ classFile.getName().substring(0,
classFile.getName().lastIndexOf(".")));
ClassLoader temp = cls.getClassLoader();
}
}
return true;
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
URLClassLoader
can be useful when you need to load newly generated classes at runtime. Unfortunately, you will not be able to reload the definition of a already loaded class (i.e. reload a class) using URLCLassLoader
.
When I load the newly created class using the below code, I am not able to access injected methods. I think I am not able to overwrite existing runtime definition.
URLClassLoader
will check if the specified class has been already loaded. If found it simply returns the instance pointing to loaded class. Thus you will not be able to overwrite existing runtime definition.
Solution: A standard approach to support dynamic class reloading in Java, one should read the byte information of the class (from its .class file) and write a custom class loader to load a class using this byte information.
Points to remember while using custom ClassLoader:
The steps followed by the class loader when loading classes are:
When you implement a class loader that is capable of reloading classes you will need to deviate a bit from this sequence. The class reloading request should not be delegated to the parent class loader.
Here are sample link which can help you develop your custom class loader in Java.
http://www.javablogging.com/java-classloader-2-write-your-own-classloader/
http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html
Edited after your comment:
I think the statement InputStream stream = getClass().getClassLoader().getResourceAsStream(name); of loadClassData function in the example is not picking up the latest version of the class.
You are right, it is not picking up the latest version of the class simply because it is using existing ClassLoader
to get the stream (which points to the old version of your class).
You can rather use,
FileInputStream stream = new FileInputStream("Path to your class file");
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = stream.read();
while(data != -1){
buffer.write(data);
data = stream.read();
}
stream.close();
byte[] classData = buffer.toByteArray();
to read the byte information for the class and try to load it using your version of ClassLoader
(custom ClassLoader).