Получить значения выражений в JEXL
Имея следующее JEXL выражение:
String expression = "myVar >= 12345 && mySecondVar <= 56789";
Я могу вызвать createScript и getVariables, чтобы получить myVar и mySecondVar в качестве значений, таких как:
Set<List<String>> expressionVars = JEXL.createScript(expression).getVariables();
Что я хотел бы знать, так это то, что при наличии того же выражения я мог бы вызвать какой-то другой метод, который бы возвращал значения для этих переменных. Причина в том, что я хотел бы проверить ввод некоторых из этих значений. Я проверил документы и поиграл с классом JexlScript, но не могу найти элегантный способ сделать это.
Поскольку JEXL уже выполняет работу по синтаксическому анализу моего выражения, было бы замечательно иметь возможность извлекать эту информацию и не нужно вручную анализировать мое выражение, чтобы получить эти значения.
Что-то в линии script.getValue("myVar");
возвращение 12345
1 ответ
С JEXL вы оцениваете скрипт / выражение в заданном контексте (JexlContext), который содержит переменные и их значения. JexlContext предоставляет методы has и get, которые соответственно проверяют существование и получают значение переменных. В вашем случае вам нужно выяснить, какой у вас JexlContext (или должен быть); оттуда, это просто итерировать ваши переменные (извлеченные из вашего скрипта) и проверить их значения (из контекста).
Смотрите: http://commons.apache.org/proper/commons-jexl/apidocs/org/apache/commons/jexl3/JexlContext.html http://commons.apache.org/proper/commons-jexl/apidocs/org/apache/commons/jexl3/JexlScript.html
Вы должны реализовать свой собственный контекст:
public class ZenContext implements JexlContext {
static private final Map<String, Object> reservedVars = new HashMap<String, Object>();
private final Map<String, Object> scriptDefinedVars = new HashMap<String, Object>();
static {
reservedVars.put("math", java.lang.Math.class);
reservedVars.put("stats", apache.commons.math3.stats.Stats);
// whatever else ...
}
public boolean has(String name) {
if (reservedVars .get(name) != null) return true;
return scriptDefinedVars.get(name) != null;
}
public boolean get (String name) {
Object value = null;
if ((value = reservedVars .get(name)) != null) return value;
return scriptDefinedVars.get(name);
}
public void set(String name, Object value) {
scriptDefinedVars.set(name, value);
}
public Map<String, Object> getReservedVars () {
return reservedVars;
}
public Map<String, Object> getScriptDefinedVars () {
return scriptDefinedVars ;
}
}
Таким образом, у вас будет
- карта зарезервированных имен переменных для объектов, которые вы не разрешаете скриптам изменять их значения. например,
- отдельная карта варов, которая может быть установлена из скрипта.
А потом добавьте эти методы.
public Object execute(File scriptFile) {
JexlScript script = jexlEngine.createScript(scriptFile);
return script.execute(this); // supply this as the context
}
public Object execute (String scriptText) {
JexlScript script = jexlEngine.createScript(scriptText);
return script.execute(this); // supply this as the context
}
Вы можете изменить метод набора, который я написал здесь, чтобы проверить переменные в картах, прежде чем разрешить им установку.
Однако это не сработает для локальных переменных скрипта.
var greeting = 'The rain in Maine falls plainly insane';
Поскольку локальная переменная полагается на другой механизм, org.apache.commons.jexl3.internal.Scope, использующий метод getLocalVariables(), в котором есть ошибка.