XML ファイルを読み取り、それらのノードを POJO に変換し、それらを Drools の WM にロードし、最終的にそれらにいくつかのルールを適用する単純なユーティリティを作成しています。プロジェクト全体は、私のGitHub プロファイルで見つけることができます。残念ながら、あらゆる努力にもかかわらず、実行時にコンパイルされたクラスのインスタンスを Drools に「いいね」させることはできませんでした。多くの人が ClassLoader にも問題を抱えているのを見たので、それが原因であると思われます... GitHubと以下で入手できる最小限の作業例を用意しました。GitHubでのみ利用可能な他のいくつかの小さなファイル ( 、および) が必要です。MemoryFileManager
MemoryJavaClassObject
MemoryJavaFileObject
簡潔にするために。この例を正しく機能させるには、JVM が JDK >= 6 でありtools.jar
、. 例は次のとおりです。classes.jar
classpath
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)
明示的に s に依存するルールがない場合でもエラーが発生しPerson
ます。ここで、例外を少し調べたところ、指定されたクラス ( ) がDrools によって使用されるクラスPerson
内に見つからない場合に発生することがわかりました。したがって、と の両方にコンパイルおよびインスタンス化するために使用されるものとClassLoader
まったく同じ参照を含む構成を追加して、コードを変更しましたが、それでも同じ例外が発生するため、何か間違っている可能性があります。ClassLoader
HAL
KnowledgeBuilder
KnowledgeBase
なぜこれが起こるのか、それを回避する方法はありますか?よろしくお願いします!