Я пишу простую утилиту, которая читает XML-файлы, преобразует их узлы в POJO, загружает их в WM Drools и, наконец, применяет некоторые правила для них. Вы можете найти весь проект на моем GitHub profile. К сожалению, несмотря на все мои усилия, я не мог заставить Drools «понравиться» любому экземпляру классов, которые были скомпилированы во время выполнения. Я видел, что у многих людей также были проблемы с ClassLoader, поэтому я подозреваю, что это может быть его ошибка ... Я подготовил Минимальный рабочий пример, который вы можете попробовать, который доступен на GitHub и ниже. Для этого требуется несколько других небольших файлов (MemoryFileManager
, MemoryJavaClassObject
и MemoryJavaFileObject
), которые доступны только на GitHub для краткости. Для правильной работы этот пример требует, чтобы ваша JVM была JDK> = 6, и что у вас есть tools.jar
или classes.jar
на вашем classpath
. Примером может служить следующее:Совместное использование ClassLoader с Drools 5.6.0, чтобы разрешить компиляцию классов в памяти во время выполнения
public class Example {
/**
* @param args
*/
public static void main(String[] args) {
// Setting the strings that we are going to use...
String name = "Person";
String content = "public class " + name + " {\n";
content += " private String name;\n";
content += " public Person() {\n";
content += " }\n";
content += " public Person(String name) {\n";
content += " this.name = name;\n";
content += " }\n";
content += " public String getName() {\n";
content += " return name;\n";
content += " }\n";
content += " public void setName(String name) {\n";
content += " this.name = name;\n";
content += " }\n";
content += " @Override\n";
content += " public String toString() {\n";
content += " return \"Hello, \" + name + \"!\";\n";
content += " }\n";
content += "}\n";
String value = "HAL";
String rules = "rule \"Alive\"\n";
rules += "when\n";
rules += "then\n";
rules += " System.out.println(\"I'm alive!\")\n";
rules += "end\n";
rules += "\n";
rules += "rule \"Print\"\n";
rules += "when\n";
rules += " $o: Object()\n";
rules += "then\n";
rules += " System.out.println(\"DRL> \" + $o.toString())\n";
rules += "end\n";
// Compiling the given class in memory
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavaFileManager manager = new MemoryFileManager(compiler.getStandardFileManager(null, null, null));
ClassLoader classLoader = manager.getClassLoader(null);
List<JavaFileObject> files = new ArrayList<JavaFileObject>();
files.add(new MemoryJavaFileObject(name, content));
compiler.getTask(null, manager, null, null, null, files).call();
try {
// Instantiate and set the new class
Class<?> person = classLoader.loadClass(name);
Method method = person.getMethod("setName", String.class);
Object instance = person.newInstance();
method.invoke(instance, value);
System.out.println(instance);
System.out.println("We get a salutation, so Person is now a compiled class in memory loaded by the given ClassLoader.");
// Use the same instance in Drools (by means of the shared ClassLoader)
KnowledgeBuilderConfiguration config1 = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(null, classLoader);
KnowledgeBuilder builder = KnowledgeBuilderFactory.newKnowledgeBuilder(config1);
builder.add(ResourceFactory.newByteArrayResource(rules.getBytes()), ResourceType.DRL);
if (builder.hasErrors()) {
for (KnowledgeBuilderError error : builder.getErrors())
System.out.println(error.toString());
System.exit(-1);
}
KnowledgeBaseConfiguration config2 = KnowledgeBaseFactory.newKnowledgeBaseConfiguration(null, classLoader);
KnowledgeBase base = KnowledgeBaseFactory.newKnowledgeBase(config2);
base.addKnowledgePackages(builder.getKnowledgePackages());
StatefulKnowledgeSession session = base.newStatefulKnowledgeSession();
session.insert(instance);
session.fireAllRules();
} catch (ClassNotFoundException e) {
System.out.println("Class not found!");
} catch (IllegalAccessException e) {
System.out.println("Illegal access!");
} catch (InstantiationException e) {
System.out.println("Instantiation!");
} catch (NoSuchMethodException e) {
System.out.println("No such method!");
} catch (InvocationTargetException e) {
System.out.println("Invocation target!");
}
System.out.println("Done.");
}
}
Если я запускаю пример, я получаю следующий результат:
Hello, HAL!
We get a salutation, so Person is now a compiled class in memory loaded by the given ClassLoader.
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Exception in thread "main" java.lang.NoClassDefFoundError: Object (wrong name: Person)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at bragaglia.skimmer.core.MemoryFileManager$1.findClass(MemoryFileManager.java:33)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:340)
at org.drools.util.CompositeClassLoader$CachingLoader.load(CompositeClassLoader.java:258)
at org.drools.util.CompositeClassLoader$CachingLoader.load(CompositeClassLoader.java:237)
at org.drools.util.CompositeClassLoader.loadClass(CompositeClassLoader.java:88)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.drools.base.ClassTypeResolver.resolveType(ClassTypeResolver.java:155)
at org.drools.rule.builder.PatternBuilder.build(PatternBuilder.java:174)
at org.drools.rule.builder.PatternBuilder.build(PatternBuilder.java:135)
at org.drools.rule.builder.GroupElementBuilder.build(GroupElementBuilder.java:67)
at org.drools.rule.builder.RuleBuilder.build(RuleBuilder.java:85)
at org.drools.compiler.PackageBuilder.addRule(PackageBuilder.java:3230)
at org.drools.compiler.PackageBuilder.compileRules(PackageBuilder.java:1038)
at org.drools.compiler.PackageBuilder.compileAllRules(PackageBuilder.java:946)
at org.drools.compiler.PackageBuilder.addPackage(PackageBuilder.java:938)
at org.drools.compiler.PackageBuilder.addPackageFromDrl(PackageBuilder.java:470)
at org.drools.compiler.PackageBuilder.addKnowledgeResource(PackageBuilder.java:698)
at org.drools.builder.impl.KnowledgeBuilderImpl.add(KnowledgeBuilderImpl.java:51)
at org.drools.builder.impl.KnowledgeBuilderImpl.add(KnowledgeBuilderImpl.java:40)
at bragaglia.skimmer.core.Example.main(Example.java:91)
Как вы можете видеть, Person
класс успешно скомпилирован в памяти и инстанцированный (см сообщение Hello, HAL!
на выходе), однако, если я добавлю его в WM, я получаю Exception in thread "main" java.lang.NoClassDefFoundError: Object (wrong name: Person)
, даже если никакое правило явно не использует Person
s. Теперь я немного изучил это исключение, и я понял, что его увольняют, когда данный класс (Person
) не найден в пределах ClassLoader
, используемого Drools. Поэтому я изменил свой код, добавив конфигурацию со ссылкой на тот же самый ClassLoader
, который использовался для компиляции и создания экземпляра HAL
как для KnowledgeBuilder
, так и для KnowledgeBase
, однако я мог бы сделать что-то неправильно, потому что я все еще получаю то же исключение.
У вас есть идеи, почему это происходит и как это работает? Спасибо заранее!