Issue Details (XML | Word | Printable)

Key: JANINO-11
Type: Bug Bug
Status: Resolved Resolved
Resolution: Won't Fix
Priority: Major Major
Assignee: Arno Unkrig
Reporter: Mark Proctor
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
Janino

ExtendsType using ClassBodyEvaluator throws java.lang.NullPointerException

Created: 12/Apr/05 07:25 PM   Updated: 13/Apr/05 04:27 PM
Component/s: None
Affects Version/s: None
Fix Version/s: None

Time Tracking:
Not Specified


 Description  « Hide
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 )

{ fail( "this should pass" ); }

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 )

{ e.printStackTrace( ); }

}

public static interface Script

{ public boolean invoke() throws Exception; }

}



 All   Comments   Work Log   Change History      Sort Order: Ascending order - Click to sort in descending order
Arno Unkrig added a comment - 13/Apr/05 04:27 PM
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>

  • 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!