Details
-
Type:
Bug
-
Status:
Resolved
-
Priority:
Major
-
Resolution: Won't Fix
-
Affects Version/s: None
-
Fix Version/s: None
-
Component/s: None
-
Labels:None
-
Number of attachments :
Description
As soon as you have a ScriptEvaluator that extends a class it breaks - this was something that definitely worked in 2.1.0:
java.lang.NullPointerException
at org.codehaus.janino.Java$ClassDeclaration.compile(Java.java:850)
at org.codehaus.janino.Java$CompilationUnit.compile(Java.java:378)
at org.codehaus.janino.Java$CompilationUnit.compile(Java.java:367)
at org.codehaus.janino.EvaluatorBase.compileAndLoad(EvaluatorBase.java:259)
at org.codehaus.janino.EvaluatorBase.compileAndLoad(EvaluatorBase.java:293)
at org.codehaus.janino.ScriptEvaluator.<init>(ScriptEvaluator.java:323)
at org.codehaus.janino.ScriptEvaluator.createFastScriptEvaluator(ScriptEvaluator.java:416)
at org.drools.semantics.java.TestJanino.test1(TestJanino.java:47)
I have made a junit test script to prove this:
package org.drools.semantics.java;
import java.util.HashMap;
import org.codehaus.janino.ByteArrayClassLoader;
import org.codehaus.janino.ClassBodyEvaluator;
import org.codehaus.janino.Scanner;
import org.codehaus.janino.ScriptEvaluator;
import junit.framework.TestCase;
public class TestJanino extends TestCase
{
public void test1() throws Exception
{
String func = "public void helloWorld(java.lang.String hello)";
func += "{";
func += " System.err.println(hello + \" World\");";
func += "}";
ClassLoader classLoader = new ByteArrayClassLoader( new HashMap( ),
Thread.currentThread( ).getContextClassLoader( ) );
ClassBodyEvaluator classBody = new ClassBodyEvaluator( new Scanner( null,
new java.io.StringReader( func ) ),
"func0",
null,
new Class[]{},
classLoader );
Class funcClass = classBody.evaluate( );
String text = "return true;";
try
{
Script script = (Script) ScriptEvaluator.createFastScriptEvaluator( new Scanner( null,
new java.io.StringReader( text ) ),
"condition0",
null,
Script.class,
new String[]{},
classLoader );
}
catch ( Exception e )
try
{
Script script = (Script) ScriptEvaluator.createFastScriptEvaluator( new Scanner( null,
new java.io.StringReader( text ) ),
"condition0",
funcClass,
Script.class,
new String[]{},
classLoader );
fail( "this should fail" );
}
catch ( Exception e )
}
public static interface Script
{ public boolean invoke() throws Exception; }}
Hi Mark,
your problem is caused by a subtle incompatible change that I introduced in version 2.2.0 and didn't document clearly enough. I'll make good for that in the next version (JAVADOC and change log).
<p>
The description of the incompatible change is:
<pre>
* otherwise a new {@link ByteArrayClassLoader} was created with the
* <dt>2.2.0
* <dd>A new {@link ByteArrayClassLoader} is always created with the
* <code>optionalClassLoader</code> as the parent {@link ClassLoader}.
</pre>
As a consequence, the "old trick":
<pre>
ClassLoader cl = new ByteArrayClassLoader();
Class class1 = new ClassBodyEvaluator(... , cl);
new XyzEvaluator(... , class1, ... , cl);
</pre>
doesn't work any more, instead you have to write:
<pre>
Class class1 = new ClassBodyEvaluator(...);
new XyzEvaluator(... , class1, ... , class1.getClassLoader());
</pre>
Notice that the new code works both for 2.1.0 AND 2.2.0.
<p>
I also added code that avoids the NullPointerException and throws a verbose
RuntimeException instead:
<p>
java.lang.RuntimeException: Cannot load class "func0" through the given ClassLoader
<p>
Sorry for the inconvenience!
- Notice that from version 2.1.0 to 2.2.0, the parameter was renamed from
- <code>optionalClassLoader</code> to <code>optionalparentClassLoader</code>
- together with an incompatible semantic change:
- <dl>
- <dt>2.1.0
- <dd>If the <code>optionalClassLoader</code> was a
- {@link ByteArrayClassLoader}, the generated classes were loaded into it,
* otherwise a new {@link ByteArrayClassLoader} was created with the
- <code>optionalClassLoader</code> as the parent {@link ClassLoader}.
* <dt>2.2.0
* <dd>A new {@link ByteArrayClassLoader} is always created with the
* <code>optionalClassLoader</code> as the parent {@link ClassLoader}.
- </dl>
- The old behavior was regarded as ugly because it depends on an argument's
- type.
</pre>
As a consequence, the "old trick": <pre> ClassLoader cl = new ByteArrayClassLoader(); Class class1 = new ClassBodyEvaluator(... , cl); new XyzEvaluator(... , class1, ... , cl); </pre> doesn't work any more, instead you have to write: <pre> Class class1 = new ClassBodyEvaluator(...); new XyzEvaluator(... , class1, ... , class1.getClassLoader()); </pre> Notice that the new code works both for 2.1.0 AND 2.2.0. <p> I also added code that avoids the NullPointerException and throws a verbose RuntimeException instead: <p> java.lang.RuntimeException: Cannot load class "func0" through the given ClassLoader <p> Sorry for the inconvenience!