Notice
I wrote this article and was originally published on Qiita on 9 September 2019.
What is root object
From Spring Framework Documentation, states that "an expression string that is evaluated against a specific object instance (called the root object)".
Example below is also extracted from same document. Assume class "Inventor" is defined as
import java.util.Date;
import java.util.GregorianCalendar;
public class Inventor {
    private String name;
    private String nationality;
    private String[] inventions;
    private Date birthdate;
    private PlaceOfBirth placeOfBirth;
    public Inventor(String name, String nationality) {
        GregorianCalendar c= new GregorianCalendar();
        this.name = name;
        this.nationality = nationality;
        this.birthdate = c.getTime();
    }
    public Inventor(String name, Date birthdate, String nationality) {
        this.name = name;
        this.nationality = nationality;
        this.birthdate = birthdate;
    }
    public Inventor() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getNationality() {
        return nationality;
    }
    public void setNationality(String nationality) {
        this.nationality = nationality;
    }
    public Date getBirthdate() {
        return birthdate;
    }
    public void setBirthdate(Date birthdate) {
        this.birthdate = birthdate;
    }
    public PlaceOfBirth getPlaceOfBirth() {
        return placeOfBirth;
    }
    public void setPlaceOfBirth(PlaceOfBirth placeOfBirth) {
        this.placeOfBirth = placeOfBirth;
    }
    public void setInventions(String[] inventions) {
        this.inventions = inventions;
    }
    public String[] getInventions() {
        return inventions;
    }
}
"Root object" should be provided when evaluates an expression.
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("name"); 
// parameter pass into method getValue() is called "root object"
String name = (String) exp.getValue(tesla);
// name is "Nikola Tesla"
Passing map object as root object
Below is example
import java.util.HashMap;
import java.util.Map;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
public class SpelRootObjectExample {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("a", "String 'a'");
        map.put("b", "String 'b'");
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.addPropertyAccessor(new MapAccessor());
        ExpressionParser parser = new SpelExpressionParser();
        Expression expA = parser.parseExpression("a");
        Expression expB = parser.parseExpression("b");
        // root object is map
        System.out.println(expA.getValue(context, map));
        System.out.println(expB.getValue(context, map));
    }
}
Output is
String 'a'
String 'b'
Where can find this usage?
In Thymeleaf template engine which used in Spring MVC, similar code can be found on class "org.thymeleaf.spring5.expression.ThymeleafEvaluationContext".
public final class ThymeleafEvaluationContext
            extends StandardEvaluationContext
            implements IThymeleafEvaluationContext {
    public static final String THYMELEAF_EVALUATION_CONTEXT_CONTEXT_VARIABLE_NAME = "thymeleaf::EvaluationContext";
    private static final MapAccessor MAP_ACCESSOR_INSTANCE = new MapAccessor();
    private final ApplicationContext applicationContext;
    private IExpressionObjects expressionObjects = null;
    private boolean variableAccessRestricted = false;
    public ThymeleafEvaluationContext(final ApplicationContext applicationContext, final ConversionService conversionService) {
        super();
        Validate.notNull(applicationContext, "Application Context cannot be null");
        // ConversionService CAN be null
        this.applicationContext = applicationContext;
        this.setBeanResolver(new BeanFactoryResolver(applicationContext));
        if (conversionService != null) {
            this.setTypeConverter(new StandardTypeConverter(conversionService));
        }
        this.addPropertyAccessor(SPELContextPropertyAccessor.INSTANCE);
        // HERE!!
        this.addPropertyAccessor(MAP_ACCESSOR_INSTANCE);
    }
    // ...
}
On method org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(IExpressionContext, IStandardVariableExpression, StandardExpressionExecutionContext), class SPELContextMapWrapper (implementation of java.util.Map interface) act as root object and be used for evaluate an expression.
            final IThymeleafEvaluationContext thymeleafEvaluationContext = (IThymeleafEvaluationContext) evaluationContext;
            /*
             * CONFIGURE THE IThymeleafEvaluationContext INSTANCE: expression objects and restrictions
             *
             * NOTE this is possible even if the evaluation context object is shared for the whole template execution
             * because evaluation contexts are not thread-safe and are only used in a single template execution
             */
            thymeleafEvaluationContext.setExpressionObjects(expressionObjects);
            thymeleafEvaluationContext.setVariableAccessRestricted(expContext.getRestrictVariableAccess());
            /*
             * RESOLVE THE EVALUATION ROOT
             */
            final ITemplateContext templateContext = (context instanceof ITemplateContext ? (ITemplateContext) context : null);
            final Object evaluationRoot =
                    (useSelectionAsRoot && templateContext != null && templateContext.hasSelectionTarget()?
                            templateContext.getSelectionTarget() : new SPELContextMapWrapper(context, thymeleafEvaluationContext));
            /*
             * If no conversion is to be made, JUST RETURN
             */
            if (!expContext.getPerformTypeConversion()) {
                return exp.expression.getValue(thymeleafEvaluationContext, evaluationRoot);
            }
 

 
    
Top comments (0)