You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kie.apache.org by gi...@apache.org on 2025/02/11 12:36:26 UTC

(incubator-kie-kogito-apps) branch main updated: [incubator-kie-issues#1805] Fix serialization/deserialization inside JITExecutor (#2190)

This is an automated email from the ASF dual-hosted git repository.

gitgabrio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-kogito-apps.git


The following commit(s) were added to refs/heads/main by this push:
     new ae4b1971c [incubator-kie-issues#1805] Fix serialization/deserialization inside JITExecutor (#2190)
ae4b1971c is described below

commit ae4b1971cfa674b1d325ecc9307740ee4f7d83ea
Author: Gabriele Cardosi <ga...@gmail.com>
AuthorDate: Tue Feb 11 13:36:22 2025 +0100

    [incubator-kie-issues#1805] Fix serialization/deserialization inside JITExecutor (#2190)
    
    * [incubator-kie-issues#1805] Fix serialization/deserialization inside JITExecutor
    
    * [incubator-kie-issues#1805] Cleanup
    
    * [incubator-kie-issues#1805] Add multiple hit test on multiple model payload
    
    * [incubator-kie-issues#1805] Fix formatting
    
    ---------
    
    Co-authored-by: Gabriele-Cardosi <ga...@ibm.com>
---
 .../kie/kogito/jitexecutor/dmn/DMNEvaluator.java   |   3 +-
 .../kie/kogito/jitexecutor/dmn/JITDMNListener.java |   4 +-
 .../kogito/jitexecutor/dmn/JITDMNServiceImpl.java  |  20 ++--
 .../dmn/responses/JITDMNDecisionResult.java        |  61 ++++++++---
 .../jitexecutor/dmn/responses/JITDMNMessage.java   |  25 +++++
 .../jitexecutor/dmn/responses/JITDMNResult.java    |  88 +++++++++------
 .../jitexecutor/dmn/api/JITDMNResourceTest.java    |  45 ++++----
 .../jitexecutor/dmn/api/MultipleModelsTest.java    | 122 ++++++++++++++++++---
 .../dmn/responses/JITDMNResultTest.java            |   8 +-
 9 files changed, 276 insertions(+), 100 deletions(-)

diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java
index 841e8d40a..0f364d000 100644
--- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java
+++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java
@@ -71,6 +71,7 @@ public class DMNEvaluator {
                 .buildConfiguration()
                 .fromResources(resources.values())
                 .getOrElseThrow(RuntimeException::new);
+        dmnRuntime.addListener(new JITDMNListener());
         DMNModel mainModel = null;
         for (DMNModel m : dmnRuntime.getModels()) {
             if (m.getResource().getSourcePath().equals(payload.getMainURI())) {
@@ -125,7 +126,7 @@ public class DMNEvaluator {
                 .findFirst()
                 .map(JITDMNListener.class::cast)
                 .map(JITDMNListener::getDecisionEvaluationHitIdsMap);
-        return new JITDMNResult(getNamespace(), getName(), dmnResult,
+        return JITDMNResult.of(getNamespace(), getName(), dmnResult,
                 decisionEvaluationHitIdsMap.orElse(Collections.emptyMap()));
     }
 
diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNListener.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNListener.java
index 6b1fc2572..46ca40651 100644
--- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNListener.java
+++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNListener.java
@@ -100,11 +100,11 @@ public class JITDMNListener implements DMNRuntimeEventListener {
     }
 
     private void logEvent(DMNEvent toLog) {
-        LOGGER.info("{} event {}", toLog.getClass().getSimpleName(), toLog);
+        LOGGER.debug("{} event {}", toLog.getClass().getSimpleName(), toLog);
     }
 
     private void logEvent(AfterConditionalEvaluationEvent toLog) {
-        LOGGER.info("{} event {}", toLog.getClass().getSimpleName(), toLog);
+        LOGGER.debug("{} event {}", toLog.getClass().getSimpleName(), toLog);
     }
 
 }
diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImpl.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImpl.java
index bb0b6513c..13f71b24d 100644
--- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImpl.java
+++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImpl.java
@@ -19,6 +19,7 @@
 package org.kie.kogito.jitexecutor.dmn;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -29,7 +30,6 @@ import java.util.stream.Collectors;
 
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.kie.dmn.api.core.DMNModel;
-import org.kie.dmn.api.core.DMNResult;
 import org.kie.dmn.api.core.ast.DecisionNode;
 import org.kie.kogito.explainability.Config;
 import org.kie.kogito.explainability.api.FeatureImportanceModel;
@@ -79,6 +79,12 @@ public class JITDMNServiceImpl implements JITDMNService {
         return dmnEvaluator.evaluate(context);
     }
 
+    @Override
+    public JITDMNResult evaluateModel(MultipleResourcesPayload payload, Map<String, Object> context) {
+        DMNEvaluator dmnEvaluator = DMNEvaluator.fromMultiple(payload);
+        return dmnEvaluator.evaluate(context);
+    }
+
     @Override
     public DMNResultWithExplanation evaluateModelAndExplain(String modelXML, Map<String, Object> context) {
         DMNEvaluator dmnEvaluator = DMNEvaluator.fromXML(modelXML);
@@ -94,7 +100,7 @@ public class JITDMNServiceImpl implements JITDMNService {
     public DMNResultWithExplanation evaluateModelAndExplain(DMNEvaluator dmnEvaluator, Map<String, Object> context) {
         LocalDMNPredictionProvider localDMNPredictionProvider = new LocalDMNPredictionProvider(dmnEvaluator);
 
-        DMNResult dmnResult = dmnEvaluator.evaluate(context);
+        JITDMNResult dmnResult = dmnEvaluator.evaluate(context);
 
         Prediction prediction = new SimplePrediction(LocalDMNPredictionProvider.toPredictionInput(context),
                 LocalDMNPredictionProvider.toPredictionOutput(dmnResult));
@@ -113,14 +119,14 @@ public class JITDMNServiceImpl implements JITDMNService {
                 Thread.currentThread().interrupt();
             }
             return new DMNResultWithExplanation(
-                    new JITDMNResult(dmnEvaluator.getNamespace(), dmnEvaluator.getName(), dmnResult),
+                    JITDMNResult.of(dmnEvaluator.getNamespace(), dmnEvaluator.getName(), dmnResult, Collections.emptyMap()),
                     new SalienciesResponse(EXPLAINABILITY_FAILED, EXPLAINABILITY_FAILED_MESSAGE, null));
         }
 
         List<SaliencyResponse> saliencyModelResponse = buildSalienciesResponse(dmnEvaluator.getDmnModel(), saliencyMap);
 
         return new DMNResultWithExplanation(
-                new JITDMNResult(dmnEvaluator.getNamespace(), dmnEvaluator.getName(), dmnResult),
+                JITDMNResult.of(dmnEvaluator.getNamespace(), dmnEvaluator.getName(), dmnResult, Collections.emptyMap()),
                 new SalienciesResponse(EXPLAINABILITY_SUCCEEDED, null, saliencyModelResponse));
     }
 
@@ -145,10 +151,4 @@ public class JITDMNServiceImpl implements JITDMNService {
         return new FeatureImportanceModel(model.getFeature().getName(), model.getScore());
     }
 
-    @Override
-    public JITDMNResult evaluateModel(MultipleResourcesPayload payload, Map<String, Object> context) {
-        DMNEvaluator dmnEvaluator = DMNEvaluator.fromMultiple(payload);
-        DMNResult dmnResult = dmnEvaluator.evaluate(context);
-        return new JITDMNResult(dmnEvaluator.getNamespace(), dmnEvaluator.getName(), dmnResult);
-    }
 }
diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNDecisionResult.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNDecisionResult.java
index 5ff45c7ba..4093de947 100644
--- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNDecisionResult.java
+++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNDecisionResult.java
@@ -23,6 +23,8 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 import org.kie.dmn.api.core.DMNDecisionResult;
 import org.kie.dmn.api.core.DMNMessage;
@@ -52,14 +54,14 @@ public class JITDMNDecisionResult implements Serializable,
     }
 
     public static JITDMNDecisionResult of(DMNDecisionResult value, Map<String, Integer> decisionEvaluationHitIdsMap) {
-        JITDMNDecisionResult res = new JITDMNDecisionResult();
-        res.decisionId = value.getDecisionId();
-        res.decisionName = value.getDecisionName();
-        res.setResult(value.getResult());
-        res.setMessages(value.getMessages());
-        res.status = value.getEvaluationStatus();
-        res.evaluationHitIds = decisionEvaluationHitIdsMap;
-        return res;
+        JITDMNDecisionResult toReturn = new JITDMNDecisionResult();
+        toReturn.decisionId = value.getDecisionId();
+        toReturn.decisionName = value.getDecisionName();
+        toReturn.result = internalGetResult(value.getResult());
+        toReturn.messages = internalGetMessages(value.getMessages());
+        toReturn.status = value.getEvaluationStatus();
+        toReturn.evaluationHitIds = decisionEvaluationHitIdsMap;
+        return toReturn;
     }
 
     @Override
@@ -95,18 +97,15 @@ public class JITDMNDecisionResult implements Serializable,
     }
 
     public void setResult(Object result) {
-        this.result = MarshallingStubUtils.stubDMNResult(result, String::valueOf);
+        this.result = result;
     }
 
     public List<DMNMessage> getMessages() {
         return (List) messages;
     }
 
-    public void setMessages(List<DMNMessage> messages) {
-        this.messages = new ArrayList<>();
-        for (DMNMessage m : messages) {
-            this.messages.add(JITDMNMessage.of(m));
-        }
+    public void setMessages(List<JITDMNMessage> messages) {
+        this.messages = messages;
     }
 
     public Map<String, Integer> getEvaluationHitIds() {
@@ -121,4 +120,38 @@ public class JITDMNDecisionResult implements Serializable,
     public boolean hasErrors() {
         return messages != null && messages.stream().anyMatch(m -> m.getSeverity() == DMNMessage.Severity.ERROR);
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof JITDMNDecisionResult that)) {
+            return false;
+        }
+        return Objects.equals(decisionId, that.decisionId) && Objects.equals(decisionName, that.decisionName) && Objects.equals(result, that.result) && Objects.equals(messages, that.messages)
+                && status == that.status && Objects.equals(evaluationHitIds, that.evaluationHitIds);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(decisionId, decisionName, result, messages, status, evaluationHitIds);
+    }
+
+    @Override
+    public String toString() {
+        return "JITDMNDecisionResult{" +
+                "decisionId='" + decisionId + '\'' +
+                ", decisionName='" + decisionName + '\'' +
+                ", result=" + result +
+                ", messages=" + messages +
+                ", status=" + status +
+                ", evaluationHitIds=" + evaluationHitIds +
+                '}';
+    }
+
+    private static Object internalGetResult(Object result) {
+        return MarshallingStubUtils.stubDMNResult(result, String::valueOf);
+    }
+
+    private static List<JITDMNMessage> internalGetMessages(List<DMNMessage> messages) {
+        return messages.stream().map(JITDMNMessage::of).collect(Collectors.toList());
+    }
 }
diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNMessage.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNMessage.java
index fb90a077a..c6ffd042d 100644
--- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNMessage.java
+++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNMessage.java
@@ -19,6 +19,7 @@
 package org.kie.kogito.jitexecutor.dmn.responses;
 
 import java.io.Serializable;
+import java.util.Objects;
 
 import org.kie.dmn.api.core.DMNMessage;
 import org.kie.dmn.api.core.DMNMessageType;
@@ -175,4 +176,28 @@ public class JITDMNMessage implements Serializable, DMNMessage {
     public String getText() {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof JITDMNMessage that)) {
+            return false;
+        }
+        return severity == that.severity && Objects.equals(message, that.message) && messageType == that.messageType && Objects.equals(sourceId, that.sourceId) && Objects.equals(path, that.path);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(severity, message, messageType, sourceId, path);
+    }
+
+    @Override
+    public String toString() {
+        return "JITDMNMessage{" +
+                "severity=" + severity +
+                ", message='" + message + '\'' +
+                ", messageType=" + messageType +
+                ", sourceId='" + sourceId + '\'' +
+                ", path='" + path + '\'' +
+                '}';
+    }
 }
\ No newline at end of file
diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResult.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResult.java
index 9d388b172..2466c238a 100644
--- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResult.java
+++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResult.java
@@ -26,6 +26,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 import org.kie.dmn.api.core.DMNContext;
@@ -48,22 +49,20 @@ public class JITDMNResult implements Serializable,
 
     private List<JITDMNMessage> messages = new ArrayList<>();
 
-    private Map<String, JITDMNDecisionResult> decisionResults = new HashMap<>();
+    private List<DMNDecisionResult> decisionResults;
 
-    public JITDMNResult() {
-        // Intentionally blank.
-    }
-
-    public JITDMNResult(String namespace, String modelName, org.kie.dmn.api.core.DMNResult dmnResult) {
-        this(namespace, modelName, dmnResult, Collections.emptyMap());
+    public static JITDMNResult of(String namespace, String modelName, org.kie.dmn.api.core.DMNResult dmnResult, Map<String, Map<String, Integer>> decisionEvaluationHitIdsMap) {
+        JITDMNResult toReturn = new JITDMNResult();
+        toReturn.namespace = namespace;
+        toReturn.modelName = modelName;
+        toReturn.dmnContext = internalGetContext(dmnResult.getContext().getAll());
+        toReturn.messages = internalGetMessages(dmnResult.getMessages());
+        toReturn.decisionResults = internalGetDecisionResults(dmnResult.getDecisionResults(), decisionEvaluationHitIdsMap);
+        return toReturn;
     }
 
-    public JITDMNResult(String namespace, String modelName, org.kie.dmn.api.core.DMNResult dmnResult, Map<String, Map<String, Integer>> decisionEvaluationHitIdsMap) {
-        this.namespace = namespace;
-        this.modelName = modelName;
-        this.setDmnContext(dmnResult.getContext().getAll());
-        this.setMessages(dmnResult.getMessages());
-        this.internalSetDecisionResults(dmnResult.getDecisionResults(), decisionEvaluationHitIdsMap);
+    public JITDMNResult() {
+        // Intentionally blank.
     }
 
     public String getNamespace() {
@@ -87,24 +86,11 @@ public class JITDMNResult implements Serializable,
     }
 
     public void setDmnContext(Map<String, Object> dmnContext) {
-        this.dmnContext = new HashMap<>();
-        for (Entry<String, Object> kv : dmnContext.entrySet()) {
-            this.dmnContext.put(kv.getKey(), MarshallingStubUtils.stubDMNResult(kv.getValue(), String::valueOf));
-        }
+        this.dmnContext = dmnContext;
     }
 
-    public void setMessages(List<? extends DMNMessage> messages) {
-        this.messages = new ArrayList<>();
-        for (DMNMessage m : messages) {
-            this.messages.add(JITDMNMessage.of(m));
-        }
-    }
-
-    public void setDecisionResults(List<? extends DMNDecisionResult> decisionResults) {
-        this.decisionResults = new HashMap<>();
-        for (DMNDecisionResult dr : decisionResults) {
-            this.decisionResults.put(dr.getDecisionId(), JITDMNDecisionResult.of(dr));
-        }
+    public void setMessages(List<JITDMNMessage> messages) {
+        this.messages = messages;
     }
 
     @JsonIgnore
@@ -130,14 +116,18 @@ public class JITDMNResult implements Serializable,
         return messages.stream().anyMatch(m -> DMNMessage.Severity.ERROR.equals(m.getSeverity()));
     }
 
+    public void setDecisionResults(List<DMNDecisionResult> decisionResults) {
+        this.decisionResults = decisionResults;
+    }
+
     @Override
     public List<DMNDecisionResult> getDecisionResults() {
-        return new ArrayList<>(decisionResults.values());
+        return decisionResults;
     }
 
     @Override
     public DMNDecisionResult getDecisionResultByName(String name) {
-        return decisionResults.values().stream()
+        return decisionResults.stream()
                 .filter(dr -> dr.getDecisionName().equals(name))
                 .findFirst()
                 .orElseThrow(() -> new RuntimeException("Unknown decision result name."));
@@ -145,7 +135,24 @@ public class JITDMNResult implements Serializable,
 
     @Override
     public DMNDecisionResult getDecisionResultById(String id) {
-        return decisionResults.get(id);
+        return decisionResults.stream()
+                .filter(dr -> dr.getDecisionId().equals(id))
+                .findFirst()
+                .orElseThrow(() -> new RuntimeException("Unknown decision result id."));
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof JITDMNResult that)) {
+            return false;
+        }
+        return Objects.equals(namespace, that.namespace) && Objects.equals(modelName, that.modelName) && Objects.equals(dmnContext, that.dmnContext) && Objects.equals(messages, that.messages)
+                && Objects.equals(decisionResults, that.decisionResults);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(namespace, modelName, dmnContext, messages, decisionResults);
     }
 
     @Override
@@ -159,10 +166,19 @@ public class JITDMNResult implements Serializable,
                 .append("]").toString();
     }
 
-    private void internalSetDecisionResults(List<? extends DMNDecisionResult> decisionResults, Map<String, Map<String, Integer>> decisionEvaluationHitIdsMap) {
-        this.decisionResults = new HashMap<>();
-        for (DMNDecisionResult dr : decisionResults) {
-            this.decisionResults.put(dr.getDecisionId(), JITDMNDecisionResult.of(dr, decisionEvaluationHitIdsMap.getOrDefault(dr.getDecisionName(), Collections.emptyMap())));
+    private static Map<String, Object> internalGetContext(Map<String, Object> source) {
+        Map<String, Object> toReturn = new HashMap<>();
+        for (Entry<String, Object> kv : source.entrySet()) {
+            toReturn.put(kv.getKey(), MarshallingStubUtils.stubDMNResult(kv.getValue(), String::valueOf));
         }
+        return toReturn;
+    }
+
+    private static List<JITDMNMessage> internalGetMessages(List<? extends DMNMessage> messages) {
+        return messages.stream().map(JITDMNMessage::of).collect(Collectors.toList());
+    }
+
+    private static List<DMNDecisionResult> internalGetDecisionResults(List<? extends DMNDecisionResult> decisionResults, Map<String, Map<String, Integer>> decisionEvaluationHitIdsMap) {
+        return decisionResults.stream().map(dr -> JITDMNDecisionResult.of(dr, decisionEvaluationHitIdsMap.getOrDefault(dr.getDecisionName(), Collections.emptyMap()))).collect(Collectors.toList());
     }
 }
diff --git a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java
index 4f6be26da..b14a775c3 100644
--- a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java
+++ b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java
@@ -51,14 +51,15 @@ import static org.kie.kogito.jitexecutor.dmn.TestingUtils.getModelFromIoUtils;
 @QuarkusTest
 public class JITDMNResourceTest {
 
-    private static String model;
-    private static String invalidModel;
+    private static String invalidModel1x;
+    private static String invalidModel15;
+    private static String validModel15;
     private static String modelWithExtensionElements;
     private static String modelWithMultipleEvaluationHitIds;
 
     private static final ObjectMapper MAPPER = new ObjectMapper();
 
-    private static final String EVALUATION_HIT_IDS_FIELD_NAME = "evaluationHitIds";
+    static final String EVALUATION_HIT_IDS_FIELD_NAME = "evaluationHitIds";
 
     static {
         MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
@@ -66,15 +67,16 @@ public class JITDMNResourceTest {
 
     @BeforeAll
     public static void setup() throws IOException {
-        model = getModelFromIoUtils("invalid_models/DMNv1_x/test.dmn");
-        invalidModel = getModelFromIoUtils("invalid_models/DMNv1_5/DMN-Invalid.dmn");
+        invalidModel1x = getModelFromIoUtils("invalid_models/DMNv1_x/test.dmn");
+        invalidModel15 = getModelFromIoUtils("invalid_models/DMNv1_5/DMN-Invalid.dmn");
+        validModel15 = getModelFromIoUtils("valid_models/DMNv1_5/RiskScore_Simple.dmn");
         modelWithExtensionElements = getModelFromIoUtils("valid_models/DMNv1_x/testWithExtensionElements.dmn");
         modelWithMultipleEvaluationHitIds = getModelFromIoUtils("valid_models/DMNv1_5/MultipleHitRules.dmn");
     }
 
     @Test
     void testjitEndpoint() {
-        JITDMNPayload jitdmnpayload = new JITDMNPayload(model, buildContext());
+        JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel1x, buildContext());
         given()
                 .contentType(ContentType.JSON)
                 .body(jitdmnpayload)
@@ -182,14 +184,17 @@ public class JITDMNResourceTest {
 
     @Test
     void testjitExplainabilityEndpoint() {
-        JITDMNPayload jitdmnpayload = new JITDMNPayload(model, buildContext());
+        Map<String, Object> context = new HashMap<>();
+        context.put("Credit Score", "Poor");
+        context.put("DTI", 33);
+        JITDMNPayload jitdmnpayload = new JITDMNPayload(validModel15, context);
         given()
                 .contentType(ContentType.JSON)
                 .body(jitdmnpayload)
                 .when().post("/jitdmn/evaluateAndExplain")
                 .then()
                 .statusCode(200)
-                .body(containsString("dmnResult"), containsString("saliencies"), containsString("xls2dmn"),
+                .body(containsString("dmnResult"), containsString("saliencies"), containsString("DMN_A77074C1-21FE-4F7E-9753-F84661569AFC"),
                         containsString("featureName"));
     }
 
@@ -211,7 +216,7 @@ public class JITDMNResourceTest {
 
     @Test
     void testjitEndpointFailure() {
-        JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel, buildContext());
+        JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel15, buildContext());
         given()
                 .contentType(ContentType.JSON)
                 .body(jitdmnpayload)
@@ -223,7 +228,7 @@ public class JITDMNResourceTest {
 
     @Test
     void testjitdmnEvaluateInvalidModel() {
-        JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel, buildInvalidModelContext());
+        JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel15, buildInvalidModelContext());
         given()
                 .contentType(ContentType.JSON)
                 .body(jitdmnpayload)
@@ -235,7 +240,7 @@ public class JITDMNResourceTest {
 
     @Test
     void testjitdmnEvaluateAndExplainInvalidModel() {
-        JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel, buildInvalidModelContext());
+        JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel15, buildInvalidModelContext());
         given()
                 .contentType(ContentType.JSON)
                 .body(jitdmnpayload)
@@ -245,15 +250,7 @@ public class JITDMNResourceTest {
                 .body(containsString("Error compiling FEEL expression 'Person Age >= 18' for name 'Can Drive?' on node 'Can Drive?': syntax error near 'Age'"));
     }
 
-    private Map<String, Object> buildContext() {
-        Map<String, Object> context = new HashMap<>();
-        context.put("FICO Score", 800);
-        context.put("DTI Ratio", .1);
-        context.put("PITI Ratio", .1);
-        return context;
-    }
-
-    private Map<String, Object> buildMultipleHitContext() {
+    static Map<String, Object> buildMultipleHitContext() {
         final List<BigDecimal> numbers = new ArrayList<>();
         numbers.add(BigDecimal.valueOf(10));
         numbers.add(BigDecimal.valueOf(2));
@@ -263,6 +260,14 @@ public class JITDMNResourceTest {
         return context;
     }
 
+    private Map<String, Object> buildContext() {
+        Map<String, Object> context = new HashMap<>();
+        context.put("FICO Score", 800);
+        context.put("DTI Ratio", .1);
+        context.put("PITI Ratio", .1);
+        return context;
+    }
+
     private Map<String, Object> buildInvalidModelContext() {
         Map<String, Object> context = new HashMap<>();
         context.put("Can Drive?", false);
diff --git a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/MultipleModelsTest.java b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/MultipleModelsTest.java
index e0405f538..cd4fa8b8b 100644
--- a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/MultipleModelsTest.java
+++ b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/MultipleModelsTest.java
@@ -22,7 +22,10 @@ import java.io.IOException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
+import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.kie.dmn.api.core.DMNDecisionResult;
@@ -37,15 +40,21 @@ import org.kie.kogito.jitexecutor.dmn.responses.JITDMNResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.fasterxml.jackson.databind.type.CollectionType;
 import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
 
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
+import io.restassured.response.Response;
+import io.restassured.response.ResponseBody;
 
 import static io.restassured.RestAssured.given;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -54,15 +63,21 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.kie.kogito.jitexecutor.dmn.TestingUtils.getModelFromIoUtils;
+import static org.kie.kogito.jitexecutor.dmn.api.JITDMNResourceTest.EVALUATION_HIT_IDS_FIELD_NAME;
+import static org.kie.kogito.jitexecutor.dmn.api.JITDMNResourceTest.buildMultipleHitContext;
 
 @QuarkusTest
 public class MultipleModelsTest {
     private static final Logger LOG = LoggerFactory.getLogger(MultipleModelsTest.class);
 
-    private static final String URI1 = "invalid_models/DMNv1_x/multiple/importing.dmn";
-    private static final String URI2 = "valid_models/DMNv1_x/multiple/stdlib.dmn";
-    private static ResourceWithURI model1;
-    private static ResourceWithURI model2;
+    private static final String IMPORTING_MODEL_URI = "invalid_models/DMNv1_x/multiple/importing.dmn";
+    private static final String STDLIB_MODEL_URI = "valid_models/DMNv1_x/multiple/stdlib.dmn";
+    private static final String SAMPLE_MODEL_URI = "valid_models/DMNv1_5/Sample.dmn";
+    private static final String MULTIPLE_HIT_MODEL_URI = "valid_models/DMNv1_5/MultipleHitRules.dmn";
+    private static ResourceWithURI importingModel;
+    private static ResourceWithURI stdLibModel;
+    private static ResourceWithURI sampleModel;
+    private static ResourceWithURI multipleHitModel;
 
     private static final String XAIURI1 = "invalid_models/DMNv1_x/test.dmn";
     private static ResourceWithURI xaimodel1;
@@ -90,8 +105,10 @@ public class MultipleModelsTest {
     @BeforeAll
     public static void setup() throws IOException {
         RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
-        model1 = new ResourceWithURI(URI1, getModelFromIoUtils(URI1));
-        model2 = new ResourceWithURI(URI2, getModelFromIoUtils(URI2));
+        importingModel = new ResourceWithURI(IMPORTING_MODEL_URI, getModelFromIoUtils(IMPORTING_MODEL_URI));
+        stdLibModel = new ResourceWithURI(STDLIB_MODEL_URI, getModelFromIoUtils(STDLIB_MODEL_URI));
+        sampleModel = new ResourceWithURI(SAMPLE_MODEL_URI, getModelFromIoUtils(SAMPLE_MODEL_URI));
+        multipleHitModel = new ResourceWithURI(MULTIPLE_HIT_MODEL_URI, getModelFromIoUtils(MULTIPLE_HIT_MODEL_URI));
         xaimodel1 = new ResourceWithURI(XAIURI1, getModelFromIoUtils(XAIURI1));
         ch11model1 = new ResourceWithURI(CH11URI1, getModelFromIoUtils(CH11URI1));
         ch11model2 = new ResourceWithURI(CH11URI2, getModelFromIoUtils(CH11URI2));
@@ -101,7 +118,7 @@ public class MultipleModelsTest {
     void testForm() {
         given()
                 .contentType(ContentType.JSON)
-                .body(new MultipleResourcesPayload(URI1, List.of(model1, model2)))
+                .body(new MultipleResourcesPayload(IMPORTING_MODEL_URI, List.of(importingModel, stdLibModel)))
                 .when().post("/jitdmn/schema/form")
                 .then()
                 .statusCode(200)
@@ -112,7 +129,7 @@ public class MultipleModelsTest {
     void testSchema() {
         given()
                 .contentType(ContentType.JSON)
-                .body(new MultipleResourcesPayload(URI1, List.of(model1, model2)))
+                .body(new MultipleResourcesPayload(IMPORTING_MODEL_URI, List.of(importingModel, stdLibModel)))
                 .when().post("/jitdmn/schema")
                 .then()
                 .statusCode(200)
@@ -121,7 +138,7 @@ public class MultipleModelsTest {
 
     @Test
     void testjitEndpoint() {
-        JITDMNPayload jitdmnpayload = new JITDMNPayload(URI1, List.of(model1, model2), buildContext());
+        JITDMNPayload jitdmnpayload = new JITDMNPayload(IMPORTING_MODEL_URI, List.of(importingModel, stdLibModel), buildContext());
         given()
                 .contentType(ContentType.JSON)
                 .body(jitdmnpayload)
@@ -133,7 +150,7 @@ public class MultipleModelsTest {
 
     @Test
     void testjitdmnResultEndpoint() {
-        JITDMNPayload jitdmnpayload = new JITDMNPayload(URI1, List.of(model1, model2), buildContext());
+        JITDMNPayload jitdmnpayload = new JITDMNPayload(IMPORTING_MODEL_URI, List.of(importingModel, stdLibModel), buildContext());
         given()
                 .contentType(ContentType.JSON)
                 .body(jitdmnpayload)
@@ -143,11 +160,90 @@ public class MultipleModelsTest {
                 .body("dmnContext.'my decision'", is("Ciao, John Doe (age:47)."));
     }
 
+    @Test
+    void testEvaluationHitIds() throws IOException {
+        final String ruleId0 = "_1FA12B9F-288C-42E8-B77F-BE2D3702B7B6";
+        final String ruleId1 = "_C8FA33B1-AF6E-4A59-B7B9-6FDF1F495C44";
+        Map<String, Object> context = new HashMap<>();
+        context.put("Credit Score", Map.of("FICO", 700));
+        Map<String, Object> monthly = new HashMap<>();
+        monthly.put("Income", 121233);
+        monthly.put("Repayments", 33);
+        monthly.put("Expenses", 123);
+        monthly.put("Tax", 32);
+        monthly.put("Insurance", 55);
+        Map<String, Object> applicantData = new HashMap<>();
+        applicantData.put("Age", 32);
+        applicantData.put("Marital Status", "S");
+        applicantData.put("Employment Status", "Employed");
+        applicantData.put("Monthly", monthly);
+        context.put("Applicant Data", applicantData);
+        Map<String, Object> requestedProduct = new HashMap<>();
+        requestedProduct.put("Type", "Special Loan");
+        requestedProduct.put("Rate", 1);
+        requestedProduct.put("Term", 2);
+        requestedProduct.put("Amount", 333);
+        context.put("Requested Product", requestedProduct);
+        context.put("id", "_0A185BAC-7692-45FA-B722-7C86C626BD51");
+        JITDMNPayload jitdmnpayload = new JITDMNPayload(SAMPLE_MODEL_URI, List.of(sampleModel), context);
+
+        Response response = given().contentType(ContentType.JSON)
+                .body(jitdmnpayload)
+                .when().post("/jitdmn/dmnresult");
+
+        ResponseBody body = response.getBody();
+        String responseString = body.asString();
+        JsonNode retrieved = MAPPER.readTree(responseString);
+        ArrayNode decisionResultsNode = (ArrayNode) retrieved.get("decisionResults");
+        Iterable<JsonNode> iterable = () -> decisionResultsNode.elements();
+        Stream<JsonNode> targetStream = StreamSupport.stream(iterable.spliterator(), false);
+        ObjectNode decisionNode = (ObjectNode) targetStream.filter(node -> node.get("decisionName").asText().equals("Credit Score Rating")).findFirst().get();
+        ObjectNode evaluationHitIdsNode = (ObjectNode) decisionNode.get(EVALUATION_HIT_IDS_FIELD_NAME);
+        Assertions.assertThat(evaluationHitIdsNode).hasSize(1);
+        Map<String, Integer> expectedEvaluationHitIds0 = Map.of(ruleId0, 1);
+        evaluationHitIdsNode.fields().forEachRemaining(entry -> Assertions.assertThat(expectedEvaluationHitIds0).containsEntry(entry.getKey(), entry.getValue().asInt()));
+
+        targetStream = StreamSupport.stream(iterable.spliterator(), false);
+        decisionNode = (ObjectNode) targetStream.filter(node -> node.get("decisionName").asText().equals("Loan Pre-Qualification")).findFirst().get();
+        evaluationHitIdsNode = (ObjectNode) decisionNode.get(EVALUATION_HIT_IDS_FIELD_NAME);
+        Assertions.assertThat(evaluationHitIdsNode).hasSize(1);
+        Map<String, Integer> expectedEvaluationHitIds1 = Map.of(ruleId1, 1);
+        evaluationHitIdsNode.fields().forEachRemaining(entry -> Assertions.assertThat(expectedEvaluationHitIds1).containsEntry(entry.getKey(), entry.getValue().asInt()));
+    }
+
+    @Test
+    void testjitdmnResultEndpointWithEvaluationHitIds() throws JsonProcessingException {
+        JITDMNPayload jitdmnpayload = new JITDMNPayload(MULTIPLE_HIT_MODEL_URI, List.of(multipleHitModel), buildMultipleHitContext());
+        final String rule0 = "_E5C380DA-AF7B-4401-9804-C58296EC09DD";
+        final String rule1 = "_DFD65E8B-5648-4BFD-840F-8C76B8DDBD1A";
+        final String rule2 = "_E80EE7F7-1C0C-4050-B560-F33611F16B05";
+        String response = given().contentType(ContentType.JSON)
+                .body(jitdmnpayload)
+                .when().post("/jitdmn/dmnresult")
+                .then()
+                .statusCode(200)
+                .body(containsString("Statistics"),
+                        containsString(EVALUATION_HIT_IDS_FIELD_NAME),
+                        containsString(rule0),
+                        containsString(rule1),
+                        containsString(rule2))
+                .extract()
+                .asString();
+        JsonNode retrieved = MAPPER.readTree(response);
+        ArrayNode decisionResultsNode = (ArrayNode) retrieved.get("decisionResults");
+        ObjectNode decisionNode = (ObjectNode) decisionResultsNode.get(0);
+        ObjectNode evaluationHitIdsNode = (ObjectNode) decisionNode.get(EVALUATION_HIT_IDS_FIELD_NAME);
+        Assertions.assertThat(evaluationHitIdsNode).hasSize(3);
+
+        final Map<String, Integer> expectedEvaluationHitIds = Map.of(rule0, 3, rule1, 2, rule2, 1);
+        evaluationHitIdsNode.fields().forEachRemaining(entry -> Assertions.assertThat(expectedEvaluationHitIds).containsEntry(entry.getKey(), entry.getValue().asInt()));
+    }
+
     @Test
     void testValidation() throws IOException {
         String response = given()
                 .contentType(ContentType.JSON)
-                .body(new MultipleResourcesPayload(URI1, List.of(model1, model2)))
+                .body(new MultipleResourcesPayload(IMPORTING_MODEL_URI, List.of(importingModel, stdLibModel)))
                 .when()
                 .post("/jitdmn/validate")
                 .then()
@@ -158,12 +254,12 @@ public class MultipleModelsTest {
         LOG.info("Validate response: {}", response);
         List<JITDMNMessage> messages = MAPPER.readValue(response, LIST_OF_MSGS);
         assertEquals(1, messages.size());
-        assertThat(messages.get(0)).hasFieldOrPropertyWithValue("path", URI1);
+        assertThat(messages.get(0)).hasFieldOrPropertyWithValue("path", IMPORTING_MODEL_URI);
     }
 
     @Test
     void testjitExplainabilityEndpoint() {
-        JITDMNPayload jitdmnpayload = new JITDMNPayload(XAIURI1, List.of(xaimodel1, model1, model2), Map.of("FICO Score", 800, "DTI Ratio", .1, "PITI Ratio", .1));
+        JITDMNPayload jitdmnpayload = new JITDMNPayload(XAIURI1, List.of(xaimodel1, importingModel, stdLibModel), Map.of("FICO Score", 800, "DTI Ratio", .1, "PITI Ratio", .1));
         given()
                 .contentType(ContentType.JSON)
                 .body(jitdmnpayload)
diff --git a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResultTest.java b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResultTest.java
index f14d8b3a1..aeb8d5365 100644
--- a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResultTest.java
+++ b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResultTest.java
@@ -78,12 +78,12 @@ class JITDMNResultTest {
         dmnResult.setContext(createContext());
         dmnResult.addDecisionResult(decisionResult);
 
-        JITDMNResult jitdmnResult = new JITDMNResult("http://www.trisotech.com/definitions/_9d01a0c4-f529-4ad8-ad8e-ec5fb5d96ad4", "Chapter 11 Example", dmnResult);
+        JITDMNResult jitdmnResult = JITDMNResult.of("http://www.trisotech.com/definitions/_9d01a0c4-f529-4ad8-ad8e-ec5fb5d96ad4", "Chapter 11 Example", dmnResult, Collections.emptyMap());
         String retrieved = MAPPER.writeValueAsString(jitdmnResult);
         assertThat(retrieved).isNotNull().isNotBlank();
-        System.out.println(retrieved);
         JITDMNResult result = MAPPER.readValue(retrieved, JITDMNResult.class);
-        assertThat(result).isNotNull();
+        assertThat(result).isNotNull().isEqualTo(jitdmnResult);
+
     }
 
     @Test
@@ -459,7 +459,7 @@ class JITDMNResultTest {
                 "      \"decisionName\": \"Required monthly installment\",\n" +
                 "      \"result\": 333.3636546143084985132842970339110,\n" +
                 "      \"messages\": [],\n" +
-                "      \"evaluationHitIds\": {},\n" +
+                "      \"evaluationHitIds\": {\"_1FA12B9F-288C-42E8-B77F-BE2D3702B7B6\": 1},\n" +
                 "      \"evaluationStatus\": \"SUCCEEDED\"\n" +
                 "    },\n" +
                 "    {\n" +


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org