Search code examples
javaobjectarraylistjbossdrools

Need to add multiple items in list - decision table - Drools


I need to create a new multiple instance of objects for the Pojo class in drools decision table. I have implemented using two facts Student fact and subject fact class. I need to fire all the rules in the decision table and I need to add all the values into array-list of the objects. But I'm getting only last rule values of decision table. It seems like decision table values are getting overridden.

Fact 1

Class StudentFact{

 private int id;
 private String name;
 private List<SubejctFact> subjectList;

 public void setId(int id){
    this.id = id;
 }

 public int getId(){
    return id;
 } 

 public void setName(String name){
    this.Name = name;
 }    

 public String getName(){
    return name;
 }

     public void setSubjectList(List<Subject> subjectList) {
        this.subjectList = subjectList;
    }



    public int getSubjectList() {
        return subjectList;
    }




}

Fact 2

Class SubjectFact{
 private int subId;
 private String subjectName;

 public void setSubId(int subId){
     this.subId= subId;
 }

 public int getSubId(){
   return subId;
 }

 public void setSubjectName(String subjectName){
      this.subjectName = subjectName;
 }

 public int getSubejctName(){
      return subjectName;
 }

}

Current Response

{
  "id":123,
  "name": "xyz",
  "subjectList": [
     { 
        "id": 6,
        "name":"Hindi"
     },
     {
        "id": 6,
        "name":"Hindi"
     }
}

Expected Response

 {
      "id":123,
      "name": "xyz",
      "subjectList": [
         { 
            "id": 5,
            "name":"English"
         },
         {
            "id": 6,
            "name":"Hindi"
         }
    }

My Decision Table looks like

enter image description here

Any one pls advise to achieve the expected response?


Solution

  • Each row in a table becomes a rule, each action column becomes a row in then block.
    For each rule you need a statement to create Subject, statements to populate it and statement to add it to matching student.
    Values in 'CREATE' and 'COLLECT' are needed, otherwise action will be skipped.
    ; is required in a cell without 'target object' and it is not required when you provide '$subject' and '$student' objects. Don't ask me why. Just analyzed generated drl.
    You may want to hide two 'technical columns'.

    enter image description here

    This will generate two rules like below

    package draft;
    //generated from Decision Table
    import draft.Student;
    import draft.Subject;
    // rule values at A9, header at A4
    rule "Rule 1"
        when
            $student:Student(id == "123")
        then
            Subject $subject = new Subject();
            $subject.setSubId(5);
            $subject.setSubjectName('English');
            $student.addSubject($subject);
    end
    
    // rule values at A10, header at A4
    rule "Rule 2"
        when
            $student:Student(id == "123")
        then
            Subject $subject = new Subject();
            $subject.setSubId(6);
            $subject.setSubjectName('Hindi');
            $student.addSubject($subject);
    end
    

    PS: I was struggling with " being automatically replaced by Calc editor to `` which was not valid symbol for drools parser, so I used single quotes, which appeared to be special symbol at the start of a cell in the editor and skipped. So actual cell value which finally worked for me was ''English'.

    Here are my models

    public class Student {
        private int id;
        private String name;
        private List<Subject> subjectList = new ArrayList<>();
        
        public Student(int id, String name) {
            this.id = id;
            this.name = name;
        }
        
        public void setId(int id) {
            this.id = id;
        }
        
        public int getId() {
            return id;
        }
        
        public void setName(String name) {
            this.name = name;
        }
        
        public String getName() {
            return name;
        }
        
        public void addSubject(Subject subject) {
            subjectList.add(subject);
        }
        
        public void setSubjectList(List<Subject> subjectList) {
            this.subjectList = subjectList;
        }
        
        public List<Subject> getSubjectList() {
            return subjectList;
        }
    }
    
    public class Subject {
        private int subId;
        private String subjectName;
        
        public void setSubId(int subId) {
            this.subId = subId;
        }
        
        public int getSubId() {
            return subId;
        }
        
        public void setSubjectName(String subjectName) {
            this.subjectName = subjectName;
        }
        
        public String getSubejctName() {
            return subjectName;
        }
    }
    

    test

    @DroolsSession(resources = "draft/ApplicableSubjects.xls",
            builderProperties = "drools.dump.dir = target/dump")
    public class PlaygroundTest {
        
        @Rule
        public DroolsAssert drools = new DroolsAssert();
        
        @Test
        public void testIt() {
            drools.insertAndFire(new Student(123, "Student 123"));
            drools.printFacts();
        }
    }
    

    test output

    00:00:00 --> inserted: Student[id=123,name=Student 123,subjectList=[]]
    00:00:00 --> fireAllRules
    00:00:00 <-- 'Rule 1' has been activated by the tuple [Student]
    00:00:00 <-- 'Rule 2' has been activated by the tuple [Student]
    00:00:00 Facts (1):
    Student[id=123,name=Student 123,subjectList=[draft.Subject@1ded7b14, draft.Subject@29be7749]]