在Java对象上评估逻辑表达式的库

4

假设我有以下类:

class Person {
    int age;
    String city;
    Collection<Person> friends;
    Person spouse;
}

我需要一个库,可以让我在给定的“人”对象上评估逻辑表达式是否为真。该表达式可能如下所示:

((age>25 OR spouse.age>27) AND city=="New-York" AND size(friends)>100)

因此,要求如下:

  1. 能够使用基本的逻辑运算符
  2. 访问给定对象的属性
  3. 访问内部对象的属性
  4. 使用简单的数学\sql-like函数,如size、max、sum等

有什么建议吗?


你能否说明为什么不能使用普通的Java来完成这个任务?表达式一定要来自动态字符串吗? - Peter Lawrey
为什么你不自己编写函数呢? - Farnabaz
为什么你需要为此使用任何库? - Rohit Jain
1
为什么你需要一个库呢?因为它比看起来更复杂(主要是解析问题),而且可能会遇到许多陷阱,而一个可靠的库已经消除了这些问题。 - Alex
3个回答

5
你可以使用 ScriptEngine + 反射:
  • 访问对象中的所有字段并创建具有这些值的变量
  • 评估表达式
以下是一个人为制造的示例,输出结果如下:
age = 35
city = "London"
age > 32 && city == "London" => true
age > 32 && city == "Paris" => false
age < 32 && city == "London" => false

如果你想处理非原始类型,比如集合类,那么情况可能会变得相当混乱。

public class Test1 {

    public static void main(String[] args) throws Exception{
        Person p = new Person();
        p.age = 35;
        p.city = "London";

        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("JavaScript");

        Class<Person> c = Person.class;
        for (Field f : c.getDeclaredFields()) {
            Object o = f.get(p);
            String assignement = null;
            if (o instanceof String) {
                assignement = f.getName() + " = \"" + String.valueOf(o) + "\"";
            } else {
                assignement = f.getName() + " = " + String.valueOf(o);
            }
            engine.eval(assignement);
            System.out.println(assignement);
        }

        String condition = "age > 32 && city == \"London\"";
        System.out.println(condition + " => " + engine.eval(condition));

        condition = "age > 32 && city == \"Paris\"";
        System.out.println(condition + " => " + engine.eval(condition));

        condition = "age < 32 && city == \"London\"";
        System.out.println(condition + " => " + engine.eval(condition));
    }

    public static class Person {

        int age;
        String city;
    }
}

3

好的,我找到了我想要的东西,这是对assylias答案的变化,但我更喜欢它,因为它更加标准化(不想特别依赖JavaScript表达式,或者干脆不运行JavaScript)。

显然有一个统一表达式语言用于评估表达式,它最初是为JSP设计的,但也可以用于其他东西。有几个解析器实现,我可能会选择Spring ELJUEL


0

您可以使用Mozilla的rhino库https://github.com/mozilla/rhino

示例:

@Test
public void shouldCheckLogicalOperations(){
    Context cx = Context.enter();
    try {
        Scriptable scope = cx.initStandardObjects();
        ScriptableObject.putProperty(scope, "form_admin_checked", true);
        ScriptableObject.putProperty(scope, "form_limit_value", 50000);

        String script = "((form_admin_checked && form_limit_value<2000) || (form_admin_checked && !form_admin_checked) || form_admin_checked && form_limit_value==50000)";
        String expectedResponse = "true";

        Object result = cx.evaluateString(scope, script, "<cmd>", 1, null);

        Assert.assertEquals(expectedResponse, result.toString());

    } finally {
        // Exit from the context.
        Context.exit();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接