SnEL 表达式上下文增强和定制
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);
}
}
}
}