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();
Comment From: sbrannen
@aclement, what are your thoughts on this feature request?
Comment From: 007aniketkumar
Is there any more information needed from my side.
Comment From: aclement
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().getClass().getSimpleName());
Comment From: 007aniketkumar
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.
Comment From: 007aniketkumar
@aclement please let me know in case you require any more information.
Comment From: aclement
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.
Comment From: sbrannen
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.
Comment From: sunnypatel165
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!
Comment From: sbrannen
Team Decision: the requested feature is out of scope for use cases that the Spring Expression Language is intended to cover. In light of that, we are closing this issue.
Comment From: AaronNeufeld
We're similarly interested in leveraging SpEL on its own as a generic expression engine for a project and are looking for a visitor implementation for SpEL expressions, as @aclement suggested. Has anyone come across any such implementations out there?
@sbrannen you mention that "the requested feature is out of scope". Do you mean specifically extending the Expression
API with something high-level like .getOperands()
is out of scope? (Certainly understandable.) Or is the idea of a more general-purpose visitor API also out of scope? Would there be any openness to a contribution of a visitor API, or do you see that being difficult to design in a sufficiently generic way to be considered for inclusion in Spring itself?
Thanks in advance.
Comment From: sbrannen
Hi @AaronNeufeld,
@sbrannen you mention that "the requested feature is out of scope". Do you mean specifically extending the
Expression
API with something high-level like.getOperands()
is out of scope? (Certainly understandable.)
Yes, that is what I meant.
Or is the idea of a more general-purpose visitor API also out of scope? Would there be any openness to a contribution of a visitor API,
If the visitor API were non-intrusive, we might be open to considering it.
or do you see that being difficult to design in a sufficiently generic way to be considered for inclusion in Spring itself?
I'm not aware of anyone in the Spring team having attempted to design/implement such a visitor pattern. Thus, I cannot judge that at this point.
A PR that provides a well thought out proposal would be the first step if anyone wishes for the team to consider this further.
Comment From: salaboy
I vote for this feature too, this will be extremely useful. Are there any examples on how to visit the expression to get the Operands?