Reputation: 23
I am looking to evaluate math expressions from String values using groovy in java code. I have created groovy script like below:
def sum(List<MyObject> myObjList) {
int sum =0
myObjList.each {it -> sum += it.grade}
return sum
}
The class MyObject is defined as:
public class MyObject
{
private String name;
private String description;
private double grade;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public double getGrade()
{
return grade;
}
public void setGrade(double grade)
{
this.grade = grade;
}
}
The code to evaluate the expression is:
public class Test
{
public static void main(String[] args) throws IOException
{
List<MyObject> objects = new ArrayList<>();
MyObject myObject = new MyObject();
myObject.setGrade(2.0);
objects.add(myObject);
myObject = new MyObject();
myObject.setGrade(1.0);
objects.add(myObject);
ClassPathResource resource = new ClassPathResource("/groovy-scripts/functions.groovy",Test.class);
File file = resource.getFile();
Binding binding = new Binding();
GroovyShell shell = new GroovyShell(binding);
Script script = shell.parse(file);
binding.setProperty("objects",objects);
String formula = "sum(objects)";
Object result = script.evaluate(formula);
System.out.println(result);
}
}
I keep getting the below exception when I try to run the code:
signature of method: Script1.sum() is applicable for argument types: (java.util.ArrayList) values: [[com.example.MyObject@3081f72c, com.example.MyObject@3148f668]] Possible solutions: run(), run(), dump(), use([Ljava.lang.Object;), any(), use(java.lang.Class, groovy.lang.Closure) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:71) at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:80) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:157) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:169) at Script1.run(Script1.groovy:1) at groovy.lang.GroovyShell.evaluate(GroovyShell.java:574) at groovy.lang.GroovyShell.evaluate(GroovyShell.java:612) at groovy.lang.GroovyShell.evaluate(GroovyShell.java:583) at groovy.lang.Script.evaluate(Script.java:210) at com.example.Test.main(Test.java:37) ```
Please suggest the correct approach to achieve this
Upvotes: 1
Views: 782
Reputation: 28634
i'm using groovy to implement main
but it's not far from java.
option 1 : use closures instead of functions
List objects = [ [grade: 111], [grade: 222] ];
GroovyShell shell = new GroovyShell();
//use undeclared closure variables
Script functions = shell.parse('''
sum = {List myObjList ->
int sum =0
myObjList.each {it -> sum += it.grade}
return sum
}
''');
functions.run(); // all closure variables assigned into binding
functions.getBinding().setProperty("objects", objects);
Object result = functions.evaluate("sum(objects)");
println("result="+result);
option 2: use script inheritance
List objects = [ [grade: 111], [grade: 222] ];
GroovyShell shell_1 = new GroovyShell();
shell_1.parse('''
def sum (List myObjList) {
int sum =0
myObjList.each {it -> sum += it.grade}
return sum
}
''', "FUNCTIONS"); // give a class name to parsed script
def cc = new org.codehaus.groovy.control.CompilerConfiguration();
cc.setScriptBaseClass("FUNCTIONS"); // any parsed scripts will extend FUNCTIONS script class
//use shell_1 class loader because it contains FUNCTIONS class definition
GroovyShell shell_2 = new GroovyShell(shell_1.getClassLoader(), cc);
Binding binding = new Binding();
binding.setProperty("objects", objects);
Script formula = shell_2.parse("sum(objects)");
formula.setBinding(binding);
Object result = formula.run();
println("result="+result);
option 3: groovy itself could be much shorter and probably you don't need over-complicated solution
List objects = [ [grade: 111], [grade: 222] ];
Object result = groovy.util.Eval.me("objects", objects, "objects.sum{it.grade}");
println("result="+result);
Upvotes: 1