Оценка Мвел

Постановка задачи: Допустим, у меня есть выражение (a + b + c), и я хочу вычислить его значение и присвоить его некоторой переменной. Позже я хочу использовать это значение переменной в какой-то другой логике. Это все делается через МВЭЛ. Проблема в том, что если кто-то из (a,b,c) является null, MVEL оценивает в строковом формате.

Поэтому, чтобы избежать этого, я создал свою собственную функцию для передачи каждого объекта, и если он равен нулю, сделать его равным нулю.

Пример кода ниже

public class MvelTest {

    public static void main(String[] args) {

        Map map = new HashMap();

        VariableResolverFactory functionFactory = new MapVariableResolverFactory(map);
        MVEL.eval("checkNullValue = def (x) { x == null ? 0 : x };", functionFactory);

        map.put("a", null);
        map.put("b", 1);
        map.put("c", 1);

        Serializable str = MVEL.compileExpression("( ( checkNullValue(a) + checkNullValue(b) + checkNullValue(c) ) > 2 ) ? d=2 : d=3");

        MVEL.executeExpression(str, map, functionFactory);
        System.out.println(map);
        System.out.println(map.get("d"));
    }
}

Выход

{checkNullValue=function_prototype:null, b=1, c=1, a=null}
null

Я не могу получить здесь значение "d", и если я удалю фабрику и функцию проверки нуля, она будет себя вести, и я смогу получить значение "d". Но я должен сделать его нулевым безопасным для арифметических операций, так как MVEL не может с этим справиться.

Также (null * 23), МВЭЛ возвращается как false.


person Ankur Singhal    schedule 16.06.2014    source источник
comment
Я пробовал это с Parser Context, также передавая собственный класс со статическим методом, выполняя те же манипуляции, но все же я не мог получить значение d   -  person Ankur Singhal    schedule 16.06.2014
comment
Не знаю почему, но это работает, если вы поместите присваивание в начало троичного выражения: MVEL.compileExpression("d = (cnv(a) + cnv(b) + cnv(c) > 2) ? 2 : 3")   -  person tobias_k    schedule 16.06.2014
comment
... использовать эту переменную в какой-то другой логике. Переменные в правиле имеют область действия, ограниченную правилом, иначе это было бы хаосом. Итак, у меня есть некоторые сомнения, будет ли этот d доступен в другом правиле, не говоря уже о проблеме, что порядок оценки (не срабатывания!) логики LHS абсолютно не определен. Передача данных между правилами должна осуществляться с помощью фактов.   -  person laune    schedule 16.06.2014


Ответы (2)


Проблема с вашим тернарным оператором. Я не уверен, как MVEL их оценивает (то, как вы их используете, было бы незаконным в Java), но кажется, что размещение присваивания в части then/else не работает... или, скорее, оно (по какой-то причине) < em>работает для части «затем» (до :), но не работает для части «еще» (после :).

Итак, если сумма равна > 2, она работает, независимо от того, используете ли вы функцию проверки нуля, а в противном случае она не работает.

Вы должны исправить свое выражение и поставить присваивание перед тернарным оператором:

MVEL.compileExpression("d = cnv(a) + cnv(b) + cnv(c) > 2 ? 2 : 3")

Обновление: как правило, это то, что я наблюдал независимо от a, b, c и cnv:

MVEL.compileExpression("true  ? d=1 : d=2"); // d ends up as 1
MVEL.compileExpression("false ? d=1 : d=2"); // d is null / unknown
MVEL.compileExpression("d = guard ? 1 : 2"); // always works
person tobias_k    schedule 16.06.2014
comment
Но то же самое работает и для меня, если я удаляю объекты фабрики или парсера. Laune Это вы можете переосмыслить для концепции цепочки правил, вывод одного становится вводом для другого и так далее, это работает для меня, используя сам MVEL API, просто некоторые проблемы при использовании cnv - person Ankur Singhal; 16.06.2014
comment
@ankur-singhal Проверьте еще раз. Тщательно протестировал: с cnv и без, и при разных значениях a, b, c. Когда a+b+c›2 (или любое другое значение отсечки), то это работало в обоих случаях, если не было, то не работало. Смотрите мою правку. - person tobias_k; 16.06.2014
comment
public static void main(String[] args) { Map map = new HashMap(); VariableResolverFactory functionFactory = new MapVariableResolverFactory(map); MVEL.eval(checkNullValue = def (x) { x == null ? 0 : x };, functionFactory); map.put(а, 3); карта.пут(б, 1); карта.пут(с, 1); Сериализуемый str = MVEL.compileExpression(( ( ( (a) + (b) + (c)) ) › 2 ) ? d=2 : d=3); MVEL.executeExpression(str, map, functionFactory); System.out.println(карта); System.out.println(map.get(d)); } вывод d=2 - person Ankur Singhal; 16.06.2014
comment
@ankur-singhal Да, я знаю. А теперь установите a на 0 и повторите попытку. (не null, а 0, или -1, или любое другое значение, которое запускает случай else) - person tobias_k; 16.06.2014

Проблема была решена, я фактически создавал статическую ссылку для VariableResolverFactory и ссылался на нее для каждой оценки, я изменил ее на новый экземпляр для каждого выполнения, и это сработало.

 public VariableResolverFactory getMvelFactory(Map contextMap) {
        VariableResolverFactory functionFactory = new MapVariableResolverFactory(contextMap);
        MVEL.eval("checkNullValue = def (x) { x == null ? 0 : x };", functionFactory);

        return functionFactory;
    }
person Ankur Singhal    schedule 17.06.2014
comment
Итак ... реальная проблема была совершенно не связана с кодом, опубликованным в вашем вопросе, а проблема «d is null», которую вы описываете в вопросе, была совершенно не связана с вашей реальной проблемой? Просто спрашиваю... - person tobias_k; 23.06.2014
comment
Не совсем, на самом деле все еще выясняю, как эта статическая фабрика вызывает проблемы. - person Ankur Singhal; 23.06.2014
comment
А вы уверены, что это не та проблема, которую я описал в своем ответе? Вы пробовали изменить выражение, чтобы присваивание находилось перед тернарным оператором, то есть d = <cond> ? 2 : 3? - person tobias_k; 23.06.2014
comment
Да, я пытался, даже если вы запустите мой пример кода без использования VariableResolverFactory, он будет выполняться правильно. - person Ankur Singhal; 23.06.2014
comment
Мне жаль, что я вынужден настаивать на этом, но это не то, что я испытал. Когда вы запускали его без функции проверки нуля, вы установили a в 0 или что-то другое, например. a=3? Пожалуйста, посмотрите последнюю часть моего ответа (обновление:...) и проверьте, получаете ли вы те же результаты для этого. - person tobias_k; 23.06.2014
comment
Да правильно, повторил то же самое и получил результат. Мое выражение было неправильным, но в моем случае, я полагаю, была какая-то проблема со статической ссылкой. - person Ankur Singhal; 23.06.2014
comment
Понял. Итак, мой ответ правильно определил и решил проблему в вашем вопросе, но у вас все еще есть другая проблема, которая на самом деле не связана с этим. - person tobias_k; 23.06.2014