Skip to content

expression language support

Mahmoud Ben Hassine edited this page Dec 6, 2020 · 14 revisions

Easy Rules provides support for defining rules with MVEL, SpEL and JEXL.

The support for each expression language is provided through a dedicated module: easy-rules-mvel, easy-rules-spel and easy-rules-jexl. These modules provide APIs to define conditions, actions and rules. Please note that conditions and actions written in SpEL should use the #{ ... } template.

EL provider considerations

EL providers have some differences in behaviour. For instance, when a fact is missing in a condition, MVEL throws an exception while SpEL silently ignores that and returns false. Therefore, you should be aware of these differences before choosing which module to use with Easy Rules. Easy Rules does not (and should not) take into account these differences. As far as the rules engine is concerned, it should try evaluate a condition expecting it to return true or false. For any runtime exception (missing fact, typo in the expression, etc), if one EL provider returns false while another throws an exception, Easy Rules will act accordingly (More details in the Error handling in rule definitions section).

Define rules in a programmatic way

Conditions, actions and rules are represented respectively by the MVELCondition/SpELCondition/JexlCondition, MVELAction/SpELAction/JexlAction and MVELRule/SpELRule/JexlRule classes. The following is an example of rule definition using MVEL:

Rule ageRule = new MVELRule()
        .name("age rule")
        .description("Check if person's age is > 18 and marks the person as adult")
        .priority(1)
        .when("person.age > 18")
        .then("person.setAdult(true);");

Create rules from a rule descriptor

You can also define a rule in a descriptor file and use the MVELRuleFactory/SpELRuleFactory/JexlRuleFactory to create a rule from the descriptor. Here is an example of an MVEL rule defined in YAML format in alcohol-rule.yml:

name: "alcohol rule"
description: "children are not allowed to buy alcohol"
priority: 2
condition: "person.isAdult() == false"
actions:
  - "System.out.println(\"Shop: Sorry, you are not allowed to buy alcohol\");"
MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
MVELRule alcoholRule = ruleFactory.createRule(new FileReader("alcohol-rule.yml"));

You can also create multiple rules at the same time from a single file. For instance, here is a rules.yml file:

---
name: adult rule
description: when age is greater than 18, then mark as adult
priority: 1
condition: "person.age > 18"
actions:
  - "person.setAdult(true);"
---
name: weather rule
description: when it rains, then take an umbrella
priority: 2
condition: "rain == true"
actions:
  - "System.out.println(\"It rains, take an umbrella!\");"

To load these rules into a Rules object, you can use the following snippet:

MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
Rules rules = ruleFactory.createRules(new FileReader("rules.yml"));

You can find a complete example of how to use Easy Rules with MVEL in the shop tutorial.

Easy Rules provides support to load rules from a JSON descriptor as well. You can use the JsonRuleDefinitionReader with the MVELRuleFactory as follows:

MVELRuleFactory ruleFactory = new MVELRuleFactory(new JsonRuleDefinitionReader());

Please note that rules descriptors should be defined as an array of JSON object (each object defines a rule) even if a single rule is defined. Here is the previous alcohol-rule expressed in JSON:

[
  {
    "name": "alcohol rule",
    "description": "children are not allowed to buy alcohol",
    "priority": 2,
    "condition": "person.isAdult() == false",
    "actions": [
      "System.out.println(\"Shop: Sorry, you are not allowed to buy alcohol\");"
    ]
  }
]

Error handling in rule definitions

Engine behaviour regarding incorrect expressions in conditions

For any runtime exception that may occur during condition evaluation (missing fact, typo in the expression, etc), the engine will log a warning and consider the condition as evaluated to false. It is possible to listen to evaluation errors using RuleListener#onEvaluationError.

Engine behaviour regarding incorrect expressions in actions

For any runtime exception that may occur while performing an action (missing fact, typo in the expression, etc), the action will not be performed and the engine will log an error. It is possible to listen to action performing exceptions using RuleListener#onFailure. When a rule fails, the engine will move to the next rule unless the skipOnFirstFailedRule parameter is set.