Affects: 4.3
Introduce support to return operands and operator of a SpEL expression.
For example SpEL provides a function to retrieve a value:
// Addition
int two = parser.parseExpression("1 + 1").getValue(Integer.class);
But there is no effective way to fetch the operators and operands like:
Object [] operands = parser.parseExpression("1 + 1").getOperands();
@aclement, what are your thoughts on this feature request?
Is there any more information needed from my side.
Hey. What is your use case for this? Why do you want the operands?
You can already get at them although it isn't an optimal route:
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expression = (SpelExpression) parser.parseExpression("1 + 2");
int three = expression.getValue(Integer.class);
SpelNode left = expression.getAST().getChild(0);
SpelNode right = expression.getAST().getChild(1);
// Prints 1
System.out.println(left.getValue(new ExpressionState(new StandardEvaluationContext())));
// Prints 2
System.out.println(right.getValue(new ExpressionState(new StandardEvaluationContext())));
// Prints 3
System.out.println(three);
// Prints OpPlus
System.out.println(expression.getAST());
Thanks for getting back.
Let me explain the use case:
I have a generic calculator, which accepts a String as an expression.
void calculator() {
String expressionString = "a+b-d";
Map<String,Object> tempMap = new HashMap<>();
tempMap.put("a", 10);
tempMap.put("b", 10);
tempMap.put("d", 10);
system.out.println(computeResult(expressionString , tempMap));
}
BigDecimal computeResult (String expresssion, Map< String, BigDecimal> values) {
List<PropertyAccessor> accessors = new ArrayList<>();
accessors.add(new MapAccessor());
context.setRootObject(tempMap);
context.setPropertyAccessors(accessors);
BigDecimal result = expressionParser.parseExpression(expressionString).getValue(context,BigDecimal.class);
return result;}
Above is a very naive and extremely simplified view of what I am trying to do. The point to notice here, is, the expression string is a variable and so is the Map. My user is required to pass a valid expressionString and a valid Map of values.
Now to generate the above, I explicitly need to ask the user to enter the String, and also provide the name of the operands. This is overhead, as my user is supposed to explicitly enter the name of operands all over again, after providing the expressions.
Enter your desired expression : (a+b-c)*d/100
enter the operands : a,b,c,d //this is redundant and unwanted step.
The reason for doing so , is , unlike in your example above, I do not know the length of the expression, So, I cannot just use
SpelNode left = expression.getAST().getChild(0); //or
SpelNode left = expression.getAST().getChild(1);
Either I need to recursively call the tree, keep on checking for operators and operands and then keep on saving them and return the list of operands at the end. This is not very clean.
I feel that a function like getOperands() will be a much cleaner approach if embedded in the library itself.
@aclement please let me know in case you require any more information.
Hey. I'd probably want a few more votes on such a feature before diving into implementing it. You are the first to ask for something like this. But I think I'd probably be more tempted to keep things more general in SpEL itself and implement a generic visitor pattern on parsed SpEL expressions, then folks with different use cases just rely on that. In your case the visitor code in SpEL would be doing the walk of the structure and you'd just pull out the operand names in your visitor implementation (hopefully implementing very few methods to achieve that). I haven't seen other enhancement requests (yet!) that would be solved by this visitor pattern though - if there were a few then I think we'd do it.
Thanks for the feedback, @aclement.
I've moved this to the General Backlog for the time being in order to allow it to garner more community interest.
I had a very similar use case in the past and I ended up going the "non-optimal" way which I also felt is ugly code for a complex app. I hope this gets picked. My vote here!