com.hazelcast.org.codehaus.janino.ScriptEvaluator Maven / Gradle / Ivy
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010 Arno Unkrig. All rights reserved.
* Copyright (c) 2015-2016 TIBCO Software Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.hazelcast.org.codehaus.janino;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.hazelcast.org.codehaus.commons.compiler.CompileException;
import com.hazelcast.org.codehaus.commons.compiler.Cookable;
import com.hazelcast.org.codehaus.commons.compiler.IExpressionEvaluator;
import com.hazelcast.org.codehaus.commons.compiler.IScriptEvaluator;
import com.hazelcast.org.codehaus.commons.compiler.Location;
import com.hazelcast.org.codehaus.commons.nullanalysis.Nullable;
import com.hazelcast.org.codehaus.janino.Java.Atom;
import com.hazelcast.org.codehaus.janino.Java.BlockStatement;
import com.hazelcast.org.codehaus.janino.Java.CompilationUnit;
import com.hazelcast.org.codehaus.janino.Java.ExpressionStatement;
import com.hazelcast.org.codehaus.janino.Java.LocalClassDeclaration;
import com.hazelcast.org.codehaus.janino.Java.LocalClassDeclarationStatement;
import com.hazelcast.org.codehaus.janino.Java.LocalVariableDeclarationStatement;
import com.hazelcast.org.codehaus.janino.Java.MethodDeclarator;
import com.hazelcast.org.codehaus.janino.Java.Modifiers;
import com.hazelcast.org.codehaus.janino.Java.Primitive;
import com.hazelcast.org.codehaus.janino.Java.PrimitiveType;
import com.hazelcast.org.codehaus.janino.Java.Type;
import com.hazelcast.org.codehaus.janino.Java.VariableDeclarator;
import com.hazelcast.org.codehaus.janino.Parser.ClassDeclarationContext;
import com.hazelcast.org.codehaus.janino.util.AbstractTraverser;
/**
* An implementation of {@link IScriptEvaluator} that utilizes the JANINO Java compiler.
*
* This implementation implements the concept of "Local methods", i.e. statements may be freely intermixed with
* method declarations. These methods are typically called by the "main code" of the script evaluator. One limitation
* exists: When cooking multiple scripts in one {@link ScriptEvaluator}, then local method signatures
* (names and parameter types) must not collide between scripts.
*
*
* A plethora of "convenience constructors" exist that execute the setup steps instantly. Their use is discouraged,
* in favor of using the default constructor, plus calling a number of setters, and then one of the {@code cook()}
* methods.
*
*/
public
class ScriptEvaluator extends ClassBodyEvaluator implements IScriptEvaluator {
/**
* The name of the generated method(s), if no custom method name is configured with {@link
* #setMethodNames(String[])}.
*
* The {@code '*'} in this string is replaced with the method index, starting at 0.
*
*/
public static final String DEFAULT_METHOD_NAME = "eval*";
/**
* Represents one script that this {@link ScriptEvaluator} declares. Typically there exactly one such
* script, but there can be two or more - see {@link ScriptEvaluator#ScriptEvaluator()}.
*/
class Script {
/**
* Whether the generated method overrides a method declared by a supertype; defaults to {@code false}.
*/
protected boolean overrideMethod;
/**
* Whether the method is generated {@code static}; defaults to {@code true}.
*/
protected boolean staticMethod = true;
/**
* The generated method's return type. Defaults to {@link ScriptEvaluator#getDefaultReturnType()}.
*/
protected Class> returnType = ScriptEvaluator.this.getDefaultReturnType();
/**
* The name of the generated method.
*/
private String methodName;
private String[] parameterNames = new String[0];
private Class>[] parameterTypes = new Class>[0];
private Class>[] thrownExceptions = new Class>[0];
@Nullable private Method result; // null=uncooked
Script(String methodName) { this.methodName = methodName; }
/**
* @return The generated method
* @throws IllegalStateException The {@link ScriptEvaluator} has not yet be cooked
*/
public Method
getResult() {
if (this.result != null) return this.result;
throw new IllegalStateException("Script is not yet cooked");
}
}
/**
* The scripts to compile. Is initialized on the first call to {@link
* #setStaticMethod(boolean[])} or one of its friends.
*/
@Nullable private Script[] scripts;
/**
* @throws IllegalArgumentException count is different from previous invocations of
* this method
*/
public void
setScriptCount(int count) {
Script[] ss = this.scripts;
if (ss == null) {
this.scripts = (ss = new Script[count]);
for (int i = 0; i < count; i++) {
ss[i] = new Script(ScriptEvaluator.DEFAULT_METHOD_NAME.replace("*", Integer.toString(i)));
}
} else {
if (count != ss.length) {
throw new IllegalArgumentException(
"Inconsistent script count; previously " + ss.length + ", now " + count
);
}
}
}
private Script
getScript(int index) {
if (this.scripts != null) return this.scripts[index];
throw new IllegalStateException("\"getScript()\" invoked befor \"setScriptCount()\"");
}
/**
* Equivalent to
*
* ScriptEvaluator se = new ScriptEvaluator();
* se.cook(script);
*
*
* @see #ScriptEvaluator()
* @see Cookable#cook(String)
*/
public
ScriptEvaluator(String script) throws CompileException {
this.cook(script);
}
/**
* Equivalent to
*
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.cook(script);
*
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see Cookable#cook(String)
*/
public
ScriptEvaluator(String script, Class> returnType) throws CompileException {
this.setReturnType(returnType);
this.cook(script);
}
/**
* Equivalent to
*
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.cook(script);
*
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see Cookable#cook(String)
*/
public
ScriptEvaluator(String script, Class> returnType, String[] parameterNames, Class>[] parameterTypes)
throws CompileException {
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.cook(script);
}
/**
* Equivalent to
*
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.cook(script);
*
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see Cookable#cook(String)
*/
public
ScriptEvaluator(
String script,
Class> returnType,
String[] parameterNames,
Class>[] parameterTypes,
Class>[] thrownExceptions
) throws CompileException {
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.cook(script);
}
/**
* Equivalent to
*
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.setParentClassLoader(optionalParentClassLoader);
* se.cook(optionalFileName, is);
*
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(String, InputStream)
*/
public
ScriptEvaluator(
@Nullable String optionalFileName,
InputStream is,
Class> returnType,
String[] parameterNames,
Class>[] parameterTypes,
Class>[] thrownExceptions,
@Nullable ClassLoader optionalParentClassLoader // null = use current thread's context class loader
) throws CompileException, IOException {
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(optionalFileName, is);
}
/**
* Equivalent to
*
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.setParentClassLoader(optionalParentClassLoader);
* se.cook(reader);
*
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(String, Reader)
*/
public
ScriptEvaluator(
@Nullable String optionalFileName,
Reader reader,
Class> returnType,
String[] parameterNames,
Class>[] parameterTypes,
Class>[] thrownExceptions,
@Nullable ClassLoader optionalParentClassLoader // null = use current thread's context class loader
) throws CompileException, IOException {
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(optionalFileName, reader);
}
/**
* Equivalent to
*
* ScriptEvaluator se = new ScriptEvaluator();
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.setParentClassLoader(optionalParentClassLoader);
* se.cook(scanner);
*
*
* @see #ScriptEvaluator()
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(Reader)
*/
public
ScriptEvaluator(
Scanner scanner,
Class> returnType,
String[] parameterNames,
Class>[] parameterTypes,
Class>[] thrownExceptions,
@Nullable ClassLoader optionalParentClassLoader // null = use current thread's context class loader
) throws CompileException, IOException {
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(scanner);
}
/**
* Equivalent to
*
* ScriptEvaluator se = new ScriptEvaluator();
* se.setExtendedType(optionalExtendedType);
* se.setImplementedTypes(implementedTypes);
* se.setReturnType(returnType);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.setParentClassLoader(optionalParentClassLoader);
* se.cook(scanner);
*
*
* @see #ScriptEvaluator()
* @see ClassBodyEvaluator#setExtendedClass(Class)
* @see ClassBodyEvaluator#setImplementedInterfaces(Class[])
* @see #setReturnType(Class)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(Reader)
*/
public
ScriptEvaluator(
Scanner scanner,
@Nullable Class> optionalExtendedType,
Class>[] implementedTypes,
Class> returnType,
String[] parameterNames,
Class>[] parameterTypes,
Class>[] thrownExceptions,
@Nullable ClassLoader optionalParentClassLoader // null = use current thread's context class loader
) throws CompileException, IOException {
this.setExtendedClass(optionalExtendedType);
this.setImplementedInterfaces(implementedTypes);
this.setReturnType(returnType);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(scanner);
}
/**
* Equivalent to
*
* ScriptEvaluator se = new ScriptEvaluator();
* se.setClassName(className);
* se.setExtendedType(optionalExtendedType);
* se.setImplementedTypes(implementedTypes);
* se.setStaticMethod(staticMethod);
* se.setReturnType(returnType);
* se.setMethodName(methodName);
* se.setParameters(parameterNames, parameterTypes);
* se.setThrownExceptions(thrownExceptions);
* se.setParentClassLoader(optionalParentClassLoader);
* se.cook(scanner);
*
*
* @see #ScriptEvaluator()
* @see ClassBodyEvaluator#setClassName(String)
* @see ClassBodyEvaluator#setExtendedClass(Class)
* @see ClassBodyEvaluator#setImplementedInterfaces(Class[])
* @see #setStaticMethod(boolean)
* @see #setReturnType(Class)
* @see #setMethodName(String)
* @see #setParameters(String[], Class[])
* @see #setThrownExceptions(Class[])
* @see SimpleCompiler#setParentClassLoader(ClassLoader)
* @see Cookable#cook(Reader)
*/
public
ScriptEvaluator(
Scanner scanner,
String className,
@Nullable Class> optionalExtendedType,
Class>[] implementedTypes,
boolean staticMethod,
Class> returnType,
String methodName,
String[] parameterNames,
Class>[] parameterTypes,
Class>[] thrownExceptions,
@Nullable ClassLoader optionalParentClassLoader // null = use current thread's context class loader
) throws CompileException, IOException {
this.setClassName(className);
this.setExtendedClass(optionalExtendedType);
this.setImplementedInterfaces(implementedTypes);
this.setStaticMethod(staticMethod);
this.setReturnType(returnType);
this.setMethodName(methodName);
this.setParameters(parameterNames, parameterTypes);
this.setThrownExceptions(thrownExceptions);
this.setParentClassLoader(optionalParentClassLoader);
this.cook(scanner);
}
/**
* Constructs a script evaluator with all the default settings (return type {@code void}
*/
public ScriptEvaluator() {}
/**
* Constructs a script evaluator with the given number of scripts.
*
* The argument of all following invocations of
* {@link #setMethodNames(String[])},
* {@link #setOverrideMethod(boolean[])},
* {@link #setParameters(String[][], Class[][])},
* {@link #setReturnTypes(Class[])},
* {@link #setStaticMethod(boolean[])},
* {@link #setThrownExceptions(Class[][])},
* {@link #cook(com.hazelcast.org.codehaus.janino.util.ClassFile[])},
* {@link #cook(Parser[])},
* {@link #cook(Reader[])},
* {@link #cook(Scanner[])},
* {@link #cook(String[])},
* {@link #cook(String[], Reader[])} and
* {@link #cook(String[], String[])}
* must be arrays with exactly that length.
*
*
* If a different constructor is used, then the first invocation of one of the above method implicitly sets the
* script count.
*
*/
public ScriptEvaluator(int count) { this.setScriptCount(count); }
// ================= SINGLE SCRIPT CONFIGURATION SETTERS =================
@Override public void
setOverrideMethod(boolean overrideMethod) { this.setOverrideMethod(new boolean[] { overrideMethod }); }
@Override public void
setStaticMethod(boolean staticMethod) { this.setStaticMethod(new boolean[] { staticMethod }); }
/**
* Defines the return types of the generated methods.
*
* @param returnType The method's return type; {@code null} means the "default return type", which is the type
* returned by {@link #getDefaultReturnType()} ({@code void.class} for {@link ScriptEvaluator}
* and {@code Object.class} for {@link ExpressionEvaluator})
* @see ScriptEvaluator#getDefaultReturnType()
* @see ExpressionEvaluator#getDefaultReturnType()
*/
@Override public void
setReturnType(Class> returnType) { this.setReturnTypes(new Class[] { returnType }); }
@Override public void
setMethodName(String methodName) { this.setMethodNames(new String[] { methodName }); }
@Override public void
setParameters(String[] parameterNames, Class>[] parameterTypes) {
this.setParameters(new String[][] { parameterNames }, new Class[][] { parameterTypes });
}
@Override public void
setThrownExceptions(Class>[] thrownExceptions) {
this.setThrownExceptions(new Class>[][] { thrownExceptions });
}
// ================= MULTIPLE SCRIPT CONFIGURATION SETTERS =================
@Override public void
setOverrideMethod(boolean[] overrideMethod) {
this.setScriptCount(overrideMethod.length);
for (int i = 0; i < overrideMethod.length; i++) this.getScript(i).overrideMethod = overrideMethod[i];
}
@Override public void
setStaticMethod(boolean[] staticMethod) {
this.setScriptCount(staticMethod.length);
for (int i = 0; i < staticMethod.length; i++) this.getScript(i).staticMethod = staticMethod[i];
}
/**
* Defines the return types of the generated methods.
*
* @param returnTypes The methods' return types; {@code null} elements mean the "default return type", which is the
* type returned by {@link #getDefaultReturnType()} ({@code void.class} for {@link
* ScriptEvaluator} and {@code Object.class} for {@link ExpressionEvaluator})
* @see ScriptEvaluator#getDefaultReturnType()
* @see ExpressionEvaluator#getDefaultReturnType()
*/
@Override public void
setReturnTypes(Class>[] returnTypes) {
this.setScriptCount(returnTypes.length);
for (int i = 0; i < returnTypes.length; i++) {
this.getScript(i).returnType = ScriptEvaluator.or(
returnTypes[i],
ScriptEvaluator.this.getDefaultReturnType()
);
}
}
private static T
or(@Nullable T lhs, T rhs) { return lhs != null ? lhs : rhs; }
@Override public void
setMethodNames(String[] methodNames) {
this.setScriptCount(methodNames.length);
for (int i = 0; i < methodNames.length; i++) this.getScript(i).methodName = methodNames[i];
}
@Override public void
setParameters(String[][] parameterNames, Class>[][] parameterTypes) {
this.setScriptCount(parameterNames.length);
for (int i = 0; i < parameterNames.length; i++) this.getScript(i).parameterNames = parameterNames[i].clone();
this.setScriptCount(parameterTypes.length);
for (int i = 0; i < parameterTypes.length; i++) this.getScript(i).parameterTypes = parameterTypes[i].clone();
}
@Override public void
setThrownExceptions(Class>[][] thrownExceptions) {
this.setScriptCount(thrownExceptions.length);
for (int i = 0; i < thrownExceptions.length; i++) this.getScript(i).thrownExceptions = thrownExceptions[i];
}
// ---------------------------------------------------------------
@Override public final void
cook(String[] strings) throws CompileException { this.cook(null, strings); }
@Override public final void
cook(@Nullable String[] optionalFileNames, String[] strings) throws CompileException {
Reader[] readers = new Reader[strings.length];
for (int i = 0; i < strings.length; ++i) readers[i] = new StringReader(strings[i]);
try {
this.cook(optionalFileNames, readers);
} catch (IOException ex) {
throw new InternalCompilerException("SNO: IOException despite StringReader", ex);
}
}
@Override public final void
cook(Reader[] readers) throws CompileException, IOException {
this.cook(null, readers);
}
/**
* On a 2 GHz Intel Pentium Core Duo under Windows XP with an IBM 1.4.2 JDK, compiling 10000 expressions "a + b"
* (integer) takes about 4 seconds and 56 MB of main memory. The generated class file is 639203 bytes large.
*
* The number and the complexity of the scripts is restricted by the Limitations of the Java
* Virtual Machine, where the most limiting factor is the 64K entries limit of the constant pool. Since every
* method with a distinct name requires one entry there, you can define at best 32K (very simple) scripts.
*
*/
@Override public final void
cook(@Nullable String[] optionalFileNames, Reader[] readers) throws CompileException, IOException {
if (optionalFileNames != null) this.setScriptCount(optionalFileNames.length);
this.setScriptCount(readers.length);
Scanner[] scanners = new Scanner[readers.length];
for (int i = 0; i < readers.length; ++i) {
scanners[i] = new Scanner(optionalFileNames == null ? null : optionalFileNames[i], readers[i]);
}
this.cook(scanners);
}
@Override public final void
cook(Scanner scanner) throws CompileException, IOException { this.cook(new Scanner[] { scanner }); }
/**
* Like {@link #cook(Scanner)}, but cooks a set of scripts into one class. Notice that if any of
* the scripts causes trouble, the entire compilation will fail. If you need to report which of the
* scripts causes the exception, you may want to use the {@code optionalFileName} argument of {@link
* Scanner#Scanner(String, Reader)} to distinguish between the individual token sources.
*
* On a 2 GHz Intel Pentium Core Duo under Windows XP with an IBM 1.4.2 JDK, compiling 10000 expressions "a + b"
* (integer) takes about 4 seconds and 56 MB of main memory. The generated class file is 639203 bytes large.
*
*
* The number and the complexity of the scripts is restricted by the Limitations of the Java
* Virtual Machine, where the most limiting factor is the 64K entries limit of the constant pool. Since every
* method with a distinct name requires one entry there, you can define at best 32K (very simple) scripts.
*
*
* If and only if the number of scanners is one, then that single script may contain leading IMPORT directives.
*
*
* @throws IllegalStateException Any of the preceding {@code set...()} had an array size different from that of
* {@code scanners}
*/
public final void
cook(Scanner[] scanners) throws CompileException, IOException {
this.setScriptCount(scanners.length);
Parser[] parsers = new Parser[scanners.length];
for (int i = 0; i < scanners.length; ++i) parsers[i] = new Parser(scanners[i]);
this.cook(parsers);
}
/**
* @see #cook(Scanner[])
*/
public final void
cook(Parser[] parsers) throws CompileException, IOException {
this.setScriptCount(parsers.length);
// Create compilation unit.
Java.CompilationUnit compilationUnit = this.makeCompilationUnit(parsers.length == 1 ? parsers[0] : null);
// Create class declaration.
final Java.AbstractClassDeclaration
cd = this.addPackageMemberClassDeclaration(parsers[0].location(), compilationUnit);
// Create methods with one block each.
for (int i = 0; i < parsers.length; ++i) {
Script es = this.getScript(i);
Parser parser = parsers[i];
// Create the statements of the method.
List statements = new ArrayList();
List localMethods = new ArrayList();
this.makeStatements(i, parser, statements, localMethods);
// Create the method that holds the statements.
Location loc = parser.location();
cd.addDeclaredMethod(this.makeMethodDeclaration(
loc, // location
( // annotations
es.overrideMethod
? new Java.Annotation[] { new Java.MarkerAnnotation(this.classToType(loc, Override.class)) }
: new Java.Annotation[0]
),
es.staticMethod, // staticMethod
es.returnType, // returnType
es.methodName, // methodName
es.parameterTypes, // parameterTypes
es.parameterNames, // parameterNames
es.thrownExceptions, // thrownExceptions
statements // statements
));
// Also add the "local methods" that a script my declare.
for (MethodDeclarator method : localMethods) {
cd.addDeclaredMethod(method);
}
}
this.cook2(compilationUnit);
}
/**
* Compiles the given compilationUnit, defines it into a {@link ClassLoader}, loads the generated class,
* gets the script methods from that class, and makes them available through {@link #getMethod(int)}.
*/
protected void
cook2(CompilationUnit compilationUnit) throws CompileException {
// Compile and load the compilation unit.
final Class> c = this.compileToClass(compilationUnit);
// Find the script methods by name and parameter types.
assert this.scripts != null;
int count = this.scripts.length;
// Clear the generated methods.
for (int i = 0; i < count; ++i) this.getScript(i).result = null;
// "Class.getDeclaredMethod(name, parameterTypes)" is slow when the class declares MANY methods (say, in
// the thousands). So let's use "Class.getDeclaredMethods()" instead.
// Create a (temporary) mapping of method key to method index.
Map dms = new HashMap