Solon v3.3.0

SnEL 表达式上下文增强和定制

</> markdown

SnEL 的上下文接口为 java.util.function.Function,可以接收 Map::get 作为上下文。

1、基础上下文

Map<String, Object> context = new HashMap<>();
context.put("Math", Math.class);
System.out.println(SnEL.eval("Math.abs(-5) > 4 ? 'A' : 'B'", context));

2、增强上下文

Function 接口有很大的限局,不能接收 Bean 作为上下文。使用 StandardContext 可以增强上下文:

  • Map 作为上下文
  • Bean 作为上下文
  • 可以支持虚拟变量 root

使用 map 作上下文

Map<String, Object> map = new HashMap<>();
map.put("Math", Math.class);

System.out.println(SnEL.eval("Math.abs(-5) > 4 ? 'A' : 'B'", new StandardContext(map)));

使用 bean 作上下文

User user = new User();

System.out.println(SnEL.eval("userId > 12 ? 'A' : 'B'", new StandardContext(user)));
System.out.println(SnEL.eval("root.userId > 12 ? 'A' : 'B'", new StandardContext(user)));

使用 root 虚拟变量

System.out.println(SnEL.eval("root ? 'A' : 'B'", new StandardContext(true)));

3、上下文定制参考

参考 StandardContext 的实现

public class StandardContext implements Function<String, Object> {
    private final Object target;
    private final boolean isMap;
    private Properties properties;

    public StandardContext(Object target) {
        this.target = target;
        this.isMap = target instanceof Map;
    }

    public StandardContext() {
        this.target = Collections.emptyMap();
        this.isMap = true;
    }

    /**
     * 属性设置(用于模板表达式)
     */
    public StandardContext properties(Properties properties) {
        this.properties = properties;
        return this;
    }

    /**
     * 属性获取(用于模板表达式)
     */
    public Properties properties() {
        return properties;
    }

    @Override
    public Object apply(String name) {
        if ("root".equals(name)) {
            return target;
        }

        if (isMap) {
            return ((Map) target).get(name);
        } else {
            PropertyHolder tmp = ReflectionUtil.getProperty(target.getClass(), name);

            try {
                return tmp.getValue(target);
            } catch (Throwable e) {
                throw new EvaluationException("Failed to access property: " + name, e);
            }
        }
    }
}