title: Sharing a ClassLoader with Drools 5.6.0 to allow the in-memory compilation of classes at runtime
body: <p>I'm writing a simple utility which reads XML files, converts their nodes into POJOs, loads them into a Drools' WM and finally applies some rules to them. You can find the whole project on my <a href="https://github.com/stefano-bragaglia/Skimmer" rel="nofollow">GitHub profile</a>. Unfortunately, despite all my efforts, I couldn't make Drools to "like" any instance of classes that were compiled at runtime. I saw many people also having problems with the ClassLoader so I suspect it might be its fault... I prepared a <em>Minimal Working Example</em> for you to try which is available on <a href="https://github.com/stefano-bragaglia/Skimmer" rel="nofollow">GitHub</a> and here below. It requires a few other small files (<code>MemoryFileManager</code>, <code>MemoryJavaClassObject</code> and <code>MemoryJavaFileObject</code>) which are only available on <a href="https://github.com/stefano-bragaglia/Skimmer" rel="nofollow">GitHub</a> for brevity. In order to work properly, this example requires that your JVM is a JDK >= 6, and that you have <code>tools.jar</code> or <code>classes.jar</code> on your <code>classpath</code>. The example is the following:</p>
  
  <pre><code>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&gt; \" + $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&lt;JavaFileObject&gt; files = new ArrayList&lt;JavaFileObject&gt;();
          files.add(new MemoryJavaFileObject(name, content));
          compiler.getTask(null, manager, null, null, null, files).call();
  
          try {
              // Instantiate and set the new class
              Class&lt;?&gt; 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.");
      }
  
  }
  </code></pre>
  
  <p>If I run the example, I get the following output:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>As you can see, the <code>Person</code> class is successfully compiled in memory and instantiated (see the message <code>Hello, HAL!</code> in the output), however if I add it to a WM I get an <code>Exception in thread "main" java.lang.NoClassDefFoundError: Object (wrong name: Person)</code> even if no rule explicitly relies on <code>Person</code>s. Now, I investigated the exception a little bit and I realised that it gets fired when the given class (<code>Person</code>) is not found within the <code>ClassLoader</code> used by Drools. Therefore I changed my code by adding a configuration with a reference to the very same <code>ClassLoader</code> used to compile and instantiate <code>HAL</code> to both the <code>KnowledgeBuilder</code> and the <code>KnowledgeBase</code>, however I might be doing something wrong because I still get the same exception.</p>
  
  <p>Do you have any idea why this happens and how to work around it? Many thanks in advance!</p>