mveleasy-rules

how to write condition using j-easy easy-rules to find any matching value in a set


I would like to write a condition to evaluate if any one of the set values in the facts, meets the condition.

This is my rule definition:

public void evaluateRule(Facts facts, String ruleNum) {
        SpRuleDefinition spRuleDefinition = spRuleDefinitionService.findByRuleNum(ruleNum);
        System.out.println("Invoke Action : " + spRuleDefinition.getActionNum());
        facts.put("action", "ACTION1");
        MVELRule rule = new MVELRule()
                            .name("Rule1")
                            .description("My Rule")
                            .priority(1)
                            .when("shipment.orgNum=='ORG1' && (shipment.fromAddress.country=='IN' || shipment.toAddress.country=='IN') && shipment.shipmentLines.itemDetail.active==false")
                            .then("shipment.setOutcome(action);");
        Rules rules = new Rules();
        rules.register(rule);   
        //Fire rules on known facts
        RulesEngine rulesEngine = new DefaultRulesEngine();
        rulesEngine.fire(rules, facts);
    }

The input that I am passing can be something like this:

{"orgNum": "ORG1", "fromAddress": { "country": "SGP"}, "shipmentLines": [{ "itemDetail": {"active": true, "countryOfOrigin": "IN"}, "itemNum": "I1", "quantity": 10 }, { "itemDetail": {"active": false, "countryOfOrigin": "US"}, "itemNum": "I2", "quantity": 1 }],"toAddress": { "country": "IN"}}

I would like to evaluate if any one of the shipment lines has itemDetail that has the active flag set to false. The above rule fails with the following exception:

org.mvel2.PropertyAccessException: [Error: could not access: itemDetail; in class: java.util.HashSet]
[Near : {... s.country=='IN') && shipment.shipmentLines.itemDet ....}
]

Solution

  • That's a MVEL question rather than an EasyRules question.

    I would like to evaluate if any one of the shipment lines has itemDetail that has the active flag set to false.

    You can define a function that iterates over the set and checks your condition. Here is an example:

    @Test
    public void testConditionOnSet() {
        Set<ItemDetail> itemDetailSet = new HashSet<>();
        itemDetailSet.add(new ItemDetail(false));
        itemDetailSet.add(new ItemDetail(false));
        itemDetailSet.add(new ItemDetail(true));
    
        String condition = "active = false;\n" +
                "foreach (itemDetail : itemDetails) {\n" +
                "   active = active && itemDetail.active;\n" +
                "}\n" +
                "System.out.println(\"Is there a non active itemDetail?: \" + !active);";
        Map facts = new HashMap();
        facts.put("itemDetails", itemDetailSet);
    
        Object result = MVEL.eval(condition, facts);
    }
    
    static class ItemDetail {
        private boolean active;
    
        public ItemDetail(boolean active) {
            this.active = active;
        }
    
        public boolean isActive() {
            return active;
        }
    }
    

    This example prints: Is there a non active itemDetail? true.

    Hope this helps.