I am trying to add a non-existing method to a Java bean, compile it and use the newly added method in Drools rules. Via a custom class loader.
I am using CompilerUtils to bind newly modified class to the custom ClassLoader
as follows:
ClassLoader loader = new ClassLoader(){};
String className = "com.example.Transaction";
String path = "file:D:/workspace/Transaction.class.tmp"; // a tmp file that contains source for Java bean
try {
URL transactionUrl = new URL(path);
URLConnection connection = transactionUrl.openConnection();
InputStream input = connection.getInputStream();
String transactionClass = new String(StreamUtils.copyToByteArray(input), StandardCharsets.UTF_8);
System.out.println(transactionClass);
String javaCode = "\npublic int test() {\n" +
" return 3;\n" +
" }\n" +
"}";
String updatedClassString = transactionClass.substring(0, transactionClass.length() - 1).concat(javaCode);
Class<?> classB = CompilerUtils.CACHED_COMPILER.loadFromJava(loader, className, updatedClassString); // This is where the loader is made aware of the newly compiled class
return loader;
} catch (IOException | ClassNotFoundException exception) {
e.printStackTrace();
}
return null;
And this is where I give access to drools my classloader
final KieServices kServices = KieServices.Factory.get();
final KieFileSystem kFileSystem = kServices.newKieFileSystem();
final KieModuleModel kModuleModel = KieRulePopulator.kieModuleModel();
if (kModuleModel != null) kFileSystem.writeKModuleXML(kModuleModel.toXML());
kServices
.newKieBuilder(kFileSystem, classLoader)
.buildAll();
}
KieContainer container = kServices.newKieContainer(kServices
.getRepository()
.getDefaultReleaseId(), classLoader);
This is how I fire rules
final KieBaseConfiguration configuration = KieServices.Factory.get().newKieBaseConfiguration();
final KieSession kSession = container
.getKieContainer()
.newKieBase(configuration)
.newKieSession();
Transaction someTransaction = new Transaction();
kSession.insert(transaction);
kSession.fireAllRules();
And this is my rule
rule "Rule_31F6DE769554404B89D4E3B7B5979CA1"
dialect "java"
no-loop true
when
tr : Transaction( test == 3 )
then
System.out.println("deneme");
end
I have load Transaction class from containers classloader and it worked.
final KieSession kSession = container
.getKieContainer()
.newKieBase(configuration)
.newKieSession();
Class<?> classA = container.getKieContainer().getClassLoader().loadClass("com.example.Transaction");
Object transaction = classA.getDeclaredConstructor().newInstance();
kSession.insert(transaction);
kSession.fireAllRules();