I encountered a similar problem recently and thought I would share my solution in case it could benefit others.
I was working with a script written in Groovy where my task involved retrieving all the callable functions from the script and then filtering them based on certain criteria.
It's worth noting that this particular method is only applicable to scripts written in Groovy...
Obtaining the script engine:
public ScriptEngine getEngine() throws Exception {
if (engine == null)
engine = new ScriptEngineManager().getEngineByName(scriptType);
if (engine == null)
throw new Exception("An implementation of " + scriptType + " could not be found.");
return engine;
}
Compiling and evaluating the script:
public void evaluateScript(String script) throws Exception {
Bindings bindings = getEngine().getBindings(ScriptContext.ENGINE_SCOPE);
bindings.putAll(binding);
try {
if (engine instanceof Compilable)
compiledScript = ((Compilable)getEngine()).compile(script);
getEngine().eval(script);
} catch (Throwable e) {
e.printStackTrace();
}
}
Retrieving functions from the script: I couldn't find any other methods for extracting all callable methods from a script besides using Reflection. While this approach is dependent on the ScriptEngine being used, it seems to be the most reliable one.
public List getInvokableList() throws ScriptException {
List list = new ArrayList();
try {
Class compiledClass = compiledScript.getClass();
Field clasz = compiledClass.getDeclaredField("clasz");
clasz.setAccessible(true);
Class scrClass = (Class)clasz.get(compiledScript);
Method[] methods = scrClass.getDeclaredMethods();
clasz.setAccessible(false);
for (int i = 0, j = methods.length; i < j; i++) {
Annotation[] annotations = methods[i].getDeclaredAnnotations();
boolean ok = false;
for (int k = 0, m = annotations.length; k < m; k++) {
ok = annotations[k] instanceof CalculatedField;
if (ok) break;
}
if (ok)
list.add(methods[i].getName());
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
}
return list;
}
In my project, I didn't require all functions from the script so I created a custom annotation and utilized it within the script:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CalculatedField {
}
An example script:
import com.vssk.CalculatedField;
def utilFunc(s) {
s
}
@CalculatedField
def func3() {
utilFunc('Testing function from Groovy')
}
A method for invoking a script function by its name:
public Object executeFunc(String name) throws Exception {
return ((Invocable)getEngine()).invokeFunction(name);
}