Question

In Spring 3 SpEL, #this and #root were introduced.

The variable #root is always defined and refers to the root context object. Although #this may vary as components of an expression are evaluated, #root always refers to the root.

I have gone through the documentation, but I still don't understand what #root means (there is no example). Can someone please give me an example?

Was it helpful?

Solution

Let's say we have the following code snippet, that fills a list with several prime numbers and defines it as a variable in a SpEL context:

// create an array of integers
List<Integer> primes = new ArrayList<Integer>();
primes.addAll(Arrays.asList(2,3,5,7,11,13,17));

// create parser and set variable 'primes' as the array of integers
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext ctx = new StandardEvaluationContext();
ctx.setVariable("primes", primes);

Now, if we want to narrow the list and get all the prime numbers that are > 10, we can use the ?[] selection operator. The statement would be this one:

Expression expression = parser.parseExpression("#primes.?[#this>10]");
List<Integer> primesGreaterThanTen = (List<Integer>) expression.getValue(ctx);

As you can see, the expression to be evaluated is #primes.?[#this > 10]. How does it work ?

  • #primes refers to the primes list.
  • The ?[] selection operator matches every object i in the primes list which is not null and which matches the criteria, given in the brackets. In our example, the criteria is #this > 10. #this refers to the current evaluation object, which in our example would be the object from the list that is being checked at the moment for not-null and > 10.

The result from the evaluation will be a list, containing:

[11, 13, 17]

A SpEL context can have a #root variable. Let's have this simple class:

public class SomeCustomObject {
    public int stringLength(String input) {
        if (input == null) return 0;
        return input.length();
    }
}

and define a instance of our SomeCustomObject as the #root variable.

SomeCustomObject someObject = new SomeCustomObject();
context.setRootObject(someObject);

This will create the someObject variable a root object for the SpEL context.

A simple example with the #root variable.

String name = "kocko";
ctx.setVariable("name", kocko);
String statement = "#root.stringLength(#kocko) == 5";
Expression expression = parser.parseExpression(statement);

boolean result = expression.getValue(context, Boolean.class);

The result variable will be evaluated as true.

What is the power of the #root ?

Through a single root object, you can expose a comprehensive, custom environment to your expressions, for example custom utility methods and/or variables.

More info:

OTHER TIPS

The #this object changes relative to a portion of the expression during something like a collection projection, but the #root object doesn't.

So, if in your context you have two variables: a list of numbers myNumbers and a single number maxNumber, you can create a projection on that list with a SpEL expression like:

myNumbers.?[#this lt #root.maxNumber]

Within the projection expression (inside the square brackets), the #this object is the item in the collection that's being checked to see if it passes the filter, while the #root object is still the variables in the global context.

If you have a list of a more interesting object, like in the Collection Selection documentation example:

Members.?[Nationality == 'Serbian']

That "Nationality" is relative to #this, the member object. If you wanted to compare against a root context variable instead of a string literal, you'd need to do:

Members.?[Nationality == #root.searchedForNationality]

If you had just tried [Nationality == searchedForNationality] it wouldn't work because searchedForNationality isn't part of the member object, but a variable on the root object. You need to use #root to qualify it since by default unqualified references are relative to the #this object.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top