j-easy / easy-rules

The simple, stupid rules engine for Java
https://github.com/j-easy/easy-rules/wiki
MIT License
4.86k stars 1.05k forks source link

How to resolve "unresolvable property or identifier" issue when I define all rules in one YML with more than one fact, but I didn`t put all the facts #343

Closed PanXie closed 3 years ago

PanXie commented 3 years ago

Hi, everyone~

I defined two rules in the YML:

name: "alcohol rule"
description: "children are not allowed to buy alcohol(alcohol content > 10%)"
priority: 2
condition: "person.isAdult() == false && alcohol_content > 0.1 "
actions:
  - "System.out.println(\"Shop: Sorry, you are not allowed to buy alcohol\");"
---
name: "age rule"
description: "Check if person's age is > 18 and mark the person as adult"
priority: 1
condition: "person.age < 18"
actions:
  - "person.setAdult(false);"
  - "System.out.println(\"Not Adult\");"

sometimes, I don`t use the "alcohol rule", so I just put the "person" fact , then I will get an error "unresolvable property or identifier: alcohol_content ", How can I resolve it?(Hmmm, maybe it is a question about MVEL...)

main:

    public static void main(String[] args) throws Exception {
        Person tom = new Person("Tom", 14);
        Facts facts = new Facts();
        facts.put("person", tom);

        MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
        String fileName = args.length != 0 ? args[0] : "src/main/java/org/jeasy/rules/tutorials/shop/alcohol-rule.yml";
        Rules rules = ruleFactory.createRules(new FileReader(fileName));

        //create a default rules engine and fire rules on known facts
        RulesEngine rulesEngine = new DefaultRulesEngine();

        System.out.println("Is Tom adult?");
        rulesEngine.fire(rules, facts);

        System.out.println("Tom: Hi! can I have some Vodka please?");
        facts.put("alcohol_content", 0.5);
        rulesEngine.fire(rules, facts);
    }

output and log:

Is Tom adult?
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'age rule', description = 'Check if person's age is > 18 and mark the person as adult', priority = '1'}
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'alcohol rule', description = 'children are not allowed to buy alcohol(alcohol content > 10%)', priority = '2'}
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact{name='person', value=Person{name='Tom', age=14, adult=false}}
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'age rule' triggered
Not Adult
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'age rule' performed successfully
[main] ERROR org.jeasy.rules.core.DefaultRulesEngine - Rule 'alcohol rule' evaluated with error
[Error: unresolvable property or identifier: alcohol_content]
[Near : {... person.isAdult() == false && alcohol_content > 0.1 ....}]
             ^
[Line: 1, Column: 30]
    at org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.getBeanProperty(ReflectiveAccessorOptimizer.java:702)
    at org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.compileGetChain(ReflectiveAccessorOptimizer.java:364)
    at org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.optimizeAccessor(ReflectiveAccessorOptimizer.java:167)
    at org.mvel2.optimizers.dynamic.DynamicOptimizer.optimizeAccessor(DynamicOptimizer.java:81)
    at org.mvel2.ast.ASTNode.optimize(ASTNode.java:159)
    at org.mvel2.ast.ASTNode.getReducedValueAccelerated(ASTNode.java:115)
    at org.mvel2.ast.BinaryOperation.getReducedValueAccelerated(BinaryOperation.java:139)
    at org.mvel2.ast.And.getReducedValueAccelerated(And.java:35)
    at org.mvel2.compiler.ExecutableAccessor.getValue(ExecutableAccessor.java:42)
    at org.mvel2.MVEL.executeExpression(MVEL.java:984)
    at org.jeasy.rules.mvel.MVELCondition.evaluate(MVELCondition.java:65)
    at org.jeasy.rules.mvel.MVELRule.evaluate(MVELRule.java:120)
    at org.jeasy.rules.core.DefaultRulesEngine.doFire(DefaultRulesEngine.java:97)
    at org.jeasy.rules.core.DefaultRulesEngine.fire(DefaultRulesEngine.java:70)
    at org.jeasy.rules.tutorials.shop.Launcher.main(Launcher.java:86)
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'alcohol rule' has been evaluated to false, it has not been executed
Tom: Hi! can I have some Vodka please?
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'age rule', description = 'Check if person's age is > 18 and mark the person as adult', priority = '1'}
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'alcohol rule', description = 'children are not allowed to buy alcohol(alcohol content > 10%)', priority = '2'}
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact{name='person', value=Person{name='Tom', age=14, adult=false}}
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact{name='alcohol_content', value=0.5}
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'age rule' triggered
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'age rule' performed successfully
Not Adult
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'alcohol rule' triggered
[main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'alcohol rule' performed successfully
Shop: Sorry, you are not allowed to buy alcohol
daidai21 commented 3 years ago
public static void main(String[] args) throws Exception {
        Person tom = new Person("Tom", 14);
        Facts facts = new Facts();
        facts.put("person", tom);

        MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
        String fileName = args.length != 0 ? args[0] : "issues343/src/main/resources/alcohol-rule.yml";
        System.out.println(fileName);
        Rules rules = ruleFactory.createRules(new FileReader(fileName));

        //create a default rules engine and fire rules on known facts
        RulesEngine rulesEngine = new DefaultRulesEngine();

        System.out.println("Is Tom adult?");
        facts.put("alcohol_content", 0.5); // Move this line
        rulesEngine.fire(rules, facts);

        System.out.println("Tom: Hi! can I have some Vodka please?");
        rulesEngine.fire(rules, facts);
    }

facts.put("alcohol_content", 0.5); needs to move before rulesEngine.fire(rules, facts);

PanXie commented 3 years ago

@daidai21 thanks for your reply If I just want to check "Is Tom adult?", just use the "age rule". at that time, I don`t have a fact named "alcohol_content", which is needed in "alcohol rule". so I will get "Error: unresolvable property or identifier: alcohol_content".

Should I put all facts in to the Facts before firing the engine, if I don`t have a fact, I need to create an default one ?

daidai21 commented 3 years ago

You first run rulesEngine.fire(rules, facts); will scan all the rules, but alcohol_content param have not set, so throw error.

So do you get it?

PanXie commented 3 years ago

@daidai21 thank you~