This is an automated email from the ASF dual-hosted git repository.
yamer pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git
The following commit(s) were added to refs/heads/main by this push:
new 6f9ca2645c [kie-issues#2210] Fix DMN TCK unary test 005 returning null
instead of expected success (#6556)
6f9ca2645c is described below
commit 6f9ca2645ca7506f2b61e1828ee9c03f471a2c78
Author: ChinchuAjith <[email protected]>
AuthorDate: Tue Jan 27 20:44:30 2026 +0530
[kie-issues#2210] Fix DMN TCK unary test 005 returning null instead of
expected success (#6556)
* Code changes based on lenient/strict mode
* passing default as lenient
* Lenient/strict code changes
* Lenient/strict code changes
* Lenient/strict code changes
* Lenient/strict default implementation
* Fix for downstream breaks
* Fixing test cases for Lenient/Strict implementation
* Test fixes Lenient/Strict implementation
* Lenient/Strict implementation changes
* Review comments and test fixes
* Correcting Strict mode test
* fixing test case
* Review comments fix
* Refactoring EvaluationContextImpl class
---
.../core/jsr223/JSR223DTExpressionEvaluator.java | 5 +--
.../kie/dmn/core/ast/DMNDTExpressionEvaluator.java | 10 ++---
.../kie/dmn/core/ast/DMNInvocationEvaluator.java | 6 +--
.../core/ast/DMNLiteralExpressionEvaluator.java | 4 +-
.../org/kie/dmn/core/compiler/DMNFEELHelper.java | 5 ++-
.../java/org/kie/dmn/core/impl/DMNRuntimeImpl.java | 13 +++---
.../dmn/core/DMNDecisionTableHitPolicyTest.java | 9 ++--
.../kie/dmn/core/DMNDecisionTableRuntimeTest.java | 41 ++++++++++++++++--
.../core/impl/DMNContextFEELCtxWrapperTest.java | 1 +
.../org/kie/dmn/feel/lang/EvaluationContext.java | 13 +++++-
.../dmn/feel/lang/impl/EvaluationContextImpl.java | 50 +++++++++++++---------
.../java/org/kie/dmn/feel/lang/impl/FEELImpl.java | 23 ++++++++--
.../impl/SilentWrappingEvaluationContextImpl.java | 15 +++++++
.../runtime/decisiontables/DecisionTableImpl.java | 19 +++++---
.../core/v1_1/DMNDecisionTableHitPolicyTest.java | 32 +++++++++++++-
.../core/v1_1/DMNDecisionTableRuntimeTest.java | 14 +++++-
16 files changed, 196 insertions(+), 64 deletions(-)
diff --git
a/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java
b/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java
index 94f39b0368..d22c9c08b1 100644
---
a/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java
+++
b/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java
@@ -31,14 +31,13 @@ import org.drools.model.functions.Function1;
import org.kie.dmn.api.core.DMNResult;
import org.kie.dmn.api.core.DMNRuntime;
import org.kie.dmn.api.core.DMNVersion;
+import org.kie.dmn.api.core.EvaluatorResult;
+import org.kie.dmn.api.core.EvaluatorResult.ResultType;
import org.kie.dmn.api.core.ast.DMNNode;
-import org.kie.dmn.api.core.ast.DecisionNode;
import org.kie.dmn.api.core.event.DMNRuntimeEventManager;
import org.kie.dmn.api.feel.runtime.events.FEELEvent;
import org.kie.dmn.api.feel.runtime.events.FEELEventListener;
import org.kie.dmn.core.api.DMNExpressionEvaluator;
-import org.kie.dmn.api.core.EvaluatorResult;
-import org.kie.dmn.api.core.EvaluatorResult.ResultType;
import org.kie.dmn.core.ast.DMNDTExpressionEvaluator;
import org.kie.dmn.core.ast.DMNDTExpressionEvaluator.EventResults;
import org.kie.dmn.core.ast.EvaluatorResultImpl;
diff --git
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDTExpressionEvaluator.java
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDTExpressionEvaluator.java
index de2993bbb9..835f3db660 100644
---
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDTExpressionEvaluator.java
+++
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDTExpressionEvaluator.java
@@ -26,13 +26,13 @@ import java.util.function.Function;
import org.kie.dmn.api.core.DMNMessage;
import org.kie.dmn.api.core.DMNResult;
+import org.kie.dmn.api.core.EvaluatorResult;
+import org.kie.dmn.api.core.EvaluatorResult.ResultType;
import org.kie.dmn.api.core.ast.DMNNode;
-import org.kie.dmn.api.core.ast.DecisionNode;
import org.kie.dmn.api.core.event.DMNRuntimeEventManager;
import org.kie.dmn.api.feel.runtime.events.FEELEvent;
import org.kie.dmn.core.api.DMNExpressionEvaluator;
-import org.kie.dmn.api.core.EvaluatorResult;
-import org.kie.dmn.api.core.EvaluatorResult.ResultType;
+import org.kie.dmn.core.compiler.RuntimeModeOption;
import org.kie.dmn.core.impl.DMNResultImpl;
import org.kie.dmn.core.impl.DMNRuntimeEventManagerUtils;
import org.kie.dmn.core.impl.DMNRuntimeImpl;
@@ -40,7 +40,6 @@ import org.kie.dmn.core.util.Msg;
import org.kie.dmn.core.util.MsgUtil;
import org.kie.dmn.feel.FEEL;
import org.kie.dmn.feel.lang.EvaluationContext;
-import org.kie.dmn.feel.lang.impl.EvaluationContextImpl;
import org.kie.dmn.feel.lang.impl.FEELImpl;
import org.kie.dmn.feel.runtime.FEELFunction.Param;
import org.kie.dmn.feel.runtime.events.DecisionTableRulesMatchedEvent;
@@ -78,7 +77,8 @@ public class DMNDTExpressionEvaluator
DMNRuntimeEventManagerUtils.fireBeforeEvaluateDecisionTable(
dmrem, node.getName(), dt.getName(), dtNodeId, result );
List<String> paramNames =
dt.getParameters().get(0).stream().map(Param::getName).toList();
Object[] params = new Object[paramNames.size()];
- EvaluationContextImpl ctx =
feel.newEvaluationContext(List.of(events::add), Collections.emptyMap());
+ boolean isLenient = RuntimeModeOption.MODE.LENIENT ==
((DMNRuntimeImpl) dmrem.getRuntime()).getRuntimeModeOption();
+ EvaluationContext ctx =
feel.newEvaluationContext(List.of(events::add), Collections.emptyMap(),
isLenient);
ctx.setPerformRuntimeTypeCheck(((DMNRuntimeImpl)
dmrem.getRuntime()).performRuntimeTypeCheck(result.getModel()));
Map<String, Object> contextValues = result.getContext().getAll();
diff --git
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNInvocationEvaluator.java
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNInvocationEvaluator.java
index 5370103ee2..7eb122543b 100644
---
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNInvocationEvaluator.java
+++
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNInvocationEvaluator.java
@@ -26,15 +26,15 @@ import java.util.function.BiFunction;
import javax.xml.namespace.QName;
import org.kie.dmn.api.core.DMNContext;
+import org.kie.dmn.api.core.DMNMessage;
import org.kie.dmn.api.core.DMNResult;
import org.kie.dmn.api.core.DMNType;
-import org.kie.dmn.api.core.EvaluatorResult;
-import org.kie.dmn.api.core.DMNMessage;
import org.kie.dmn.api.core.DMNVersion;
+import org.kie.dmn.api.core.EvaluatorResult;
+import org.kie.dmn.api.core.EvaluatorResult.ResultType;
import org.kie.dmn.api.core.event.DMNRuntimeEventManager;
import org.kie.dmn.api.feel.runtime.events.FEELEvent;
import org.kie.dmn.core.api.DMNExpressionEvaluator;
-import org.kie.dmn.api.core.EvaluatorResult.ResultType;
import org.kie.dmn.core.impl.DMNModelImpl;
import org.kie.dmn.core.impl.DMNResultImpl;
import org.kie.dmn.core.util.Msg;
diff --git
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNLiteralExpressionEvaluator.java
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNLiteralExpressionEvaluator.java
index 33c80b4c15..012fe2e9a7 100644
---
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNLiteralExpressionEvaluator.java
+++
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNLiteralExpressionEvaluator.java
@@ -26,13 +26,13 @@ import java.util.stream.Collectors;
import org.kie.dmn.api.core.DMNMessage;
import org.kie.dmn.api.core.DMNResult;
+import org.kie.dmn.api.core.EvaluatorResult;
+import org.kie.dmn.api.core.EvaluatorResult.ResultType;
import org.kie.dmn.api.core.event.DMNRuntimeEventManager;
import org.kie.dmn.api.feel.runtime.events.FEELEvent;
import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
import org.kie.dmn.api.feel.runtime.events.FEELEventListener;
import org.kie.dmn.core.api.DMNExpressionEvaluator;
-import org.kie.dmn.api.core.EvaluatorResult;
-import org.kie.dmn.api.core.EvaluatorResult.ResultType;
import org.kie.dmn.core.impl.DMNResultImpl;
import org.kie.dmn.core.util.Msg;
import org.kie.dmn.core.util.MsgUtil;
diff --git
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java
index 33187ab0a9..001204cdcf 100644
---
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java
+++
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java
@@ -29,8 +29,6 @@ import java.util.Queue;
import javax.xml.namespace.QName;
-import com.github.javaparser.ast.CompilationUnit;
-import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import org.antlr.v4.runtime.CommonToken;
import org.kie.dmn.api.core.DMNContext;
import org.kie.dmn.api.core.DMNMessage;
@@ -65,6 +63,9 @@ import org.kie.dmn.model.api.ItemDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+
public class DMNFEELHelper {
diff --git
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java
index 5930f08f10..3789c799be 100644
---
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java
+++
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java
@@ -18,17 +18,15 @@
*/
package org.kie.dmn.core.impl;
-import javax.xml.namespace.QName;
-
-import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.function.BiConsumer;
import java.util.stream.Collectors;
+
+import javax.xml.namespace.QName;
+
import org.drools.kiesession.rulebase.InternalKnowledgeBase;
import org.kie.dmn.api.core.DMNContext;
import org.kie.dmn.api.core.DMNDecisionResult;
@@ -84,6 +82,7 @@ public class DMNRuntimeImpl
private final DMNRuntimeKB runtimeKB;
private boolean overrideRuntimeTypeCheck = false;
+
private RuntimeModeOption.MODE runtimeModeOption =
RuntimeModeOption.MODE.LENIENT;
private DMNResultImplFactory dmnResultFactory = new DMNResultImplFactory();
@@ -854,4 +853,8 @@ public class DMNRuntimeImpl
public DMNRuntimeKB getRuntimeKB() {
return runtimeKB;
}
+
+ public RuntimeModeOption.MODE getRuntimeModeOption() {
+ return runtimeModeOption;
+ }
}
diff --git
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNDecisionTableHitPolicyTest.java
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNDecisionTableHitPolicyTest.java
index ee649b9e84..1e5e5b7cc2 100644
---
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNDecisionTableHitPolicyTest.java
+++
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNDecisionTableHitPolicyTest.java
@@ -66,14 +66,15 @@ public class DMNDecisionTableHitPolicyTest extends
BaseInterpretedVsCompiledTest
assertThat(dmnModel).isNotNull();
// Risk Category is constrained to "High", "Low", "Medium" and "ASD"
is not allowed
+ // In lenient mode (default), invalid input is set to null and
evaluation continues
final DMNContext context =
getSimpleTableContext(BigDecimal.valueOf(18), "ASD", false);
final DMNResult dmnResult = runtime.evaluateAll(dmnModel, context);
final DMNContext result = dmnResult.getContext();
- assertThat(result.get("Approval Status")).isNull();
- assertThat(dmnResult.getMessages()).hasSizeGreaterThan(0);
- DMNMessage message = dmnResult.getMessages().iterator().next();
- assertThat(message.getText()).isEqualTo("DMN: RiskCategory='ASD' does
not match any of the valid values \"High\", \"Low\", \"Medium\" for decision
table '_0004-simpletable-U'. (DMN id: _0004-simpletable-U, FEEL expression
evaluation error) ");
+ // In lenient mode, the decision table evaluates with null parameter
and returns a result
+ assertThat(result.get("Approval Status")).isEqualTo("Declined");
+ // No error messages in lenient mode
+ assertThat(dmnResult.getMessages()).isEmpty();
}
@ParameterizedTest
diff --git
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNDecisionTableRuntimeTest.java
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNDecisionTableRuntimeTest.java
index d53b372861..92a8d99c69 100644
---
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNDecisionTableRuntimeTest.java
+++
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNDecisionTableRuntimeTest.java
@@ -186,7 +186,7 @@ public class DMNDecisionTableRuntimeTest extends
BaseInterpretedVsCompiledTest {
context.set( "Branches dispersion", "Province" );
context.set( "Number of Branches", BigDecimal.valueOf( 10 ) );
- testDecisionTableInvalidInput( context );
+ testDecisionTableInvalidInputLenient( context );
}
@ParameterizedTest
@@ -197,7 +197,7 @@ public class DMNDecisionTableRuntimeTest extends
BaseInterpretedVsCompiledTest {
context.set( "Branches dispersion", 1 );
context.set( "Number of Branches", BigDecimal.valueOf( 10 ) );
- testDecisionTableInvalidInput( context );
+ testDecisionTableInvalidInputType( context );
}
@ParameterizedTest
@@ -208,18 +208,51 @@ public class DMNDecisionTableRuntimeTest extends
BaseInterpretedVsCompiledTest {
context.set( "Not exists", "Province" );
context.set( "Number of Branches", BigDecimal.valueOf( 10 ) );
- testDecisionTableInvalidInput( context );
+ testDecisionTableMissingDependency( context );
}
- private void testDecisionTableInvalidInput(final DMNContext inputContext) {
+ private void testDecisionTableInvalidInputLenient(final DMNContext
inputContext) {
final DMNRuntime runtime = DMNRuntimeUtil.createRuntime(
"InvalidInput.dmn", this.getClass() );
final DMNModel dmnModel = runtime.getModel(
"http://www.trisotech.com/dmn/definitions/_cdf29af2-959b-4004-8271-82a9f5a62147",
"Dessin 1" );
assertThat(dmnModel).isNotNull();
final DMNResult dmnResult = runtime.evaluateAll( dmnModel,
inputContext );
+ // In lenient mode (default), invalid input values don't generate
errors
+ // The invalid value is set to null and evaluation continues
+ assertThat( dmnResult.hasErrors()).isFalse();
+
+ final DMNContext result = dmnResult.getContext();
+ // Result is defined - evaluation continues with null for invalid input
+ assertThat( result.isDefined( "Branches distribution"
)).isEqualTo(Boolean.TRUE);
+ }
+
+ private void testDecisionTableInvalidInputType(final DMNContext
inputContext) {
+ final DMNRuntime runtime = DMNRuntimeUtil.createRuntime(
"InvalidInput.dmn", this.getClass() );
+ final DMNModel dmnModel = runtime.getModel(
"http://www.trisotech.com/dmn/definitions/_cdf29af2-959b-4004-8271-82a9f5a62147",
"Dessin 1" );
+ assertThat(dmnModel).isNotNull();
+
+ final DMNResult dmnResult = runtime.evaluateAll( dmnModel,
inputContext );
+ // Type errors generate errors regardless of lenient/strict mode
+ // Wrong type (integer instead of string) is a type mismatch error
+ assertThat( dmnResult.hasErrors()).isTrue();
+
+ final DMNContext result = dmnResult.getContext();
+ // With type error, the result cannot be evaluated
+ assertThat( result.isDefined( "Branches distribution"
)).isEqualTo(Boolean.FALSE);
+ }
+
+ private void testDecisionTableMissingDependency(final DMNContext
inputContext) {
+ final DMNRuntime runtime = DMNRuntimeUtil.createRuntime(
"InvalidInput.dmn", this.getClass() );
+ final DMNModel dmnModel = runtime.getModel(
"http://www.trisotech.com/dmn/definitions/_cdf29af2-959b-4004-8271-82a9f5a62147",
"Dessin 1" );
+ assertThat(dmnModel).isNotNull();
+
+ final DMNResult dmnResult = runtime.evaluateAll( dmnModel,
inputContext );
+ // Missing required dependency generates errors regardless of
lenient/strict mode
+ // This is a structural error, not an input validation error
assertThat( dmnResult.hasErrors()).isTrue();
final DMNContext result = dmnResult.getContext();
+ // With missing required dependency, the result cannot be evaluated
assertThat( result.isDefined( "Branches distribution"
)).isEqualTo(Boolean.FALSE);
}
diff --git
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java
index d5322832cf..319cf7f9ea 100644
---
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java
+++
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java
@@ -173,6 +173,7 @@ class DMNContextFEELCtxWrapperTest extends
BaseDMNContextTest {
public DMNVersion getDMNVersion() {
return DMNVersion.getLatest();
}
+
}
}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java
index b521f0dcf0..6ba949b8d0 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java
@@ -53,7 +53,6 @@ public interface EvaluationContext {
void notifyEvt(Supplier<FEELEvent> event);
-
Collection<FEELEventListener> getListeners();
void setRootObject(Object v);
@@ -63,4 +62,16 @@ public interface EvaluationContext {
FEELDialect getFEELDialect();
DMNVersion getDMNVersion();
+
+ default boolean isLenient() {
+ return true; // Default to lenient mode
+ }
+
+ default void setPerformRuntimeTypeCheck(boolean performRuntimeTypeCheck) {
+ // Default implementation does nothing
+ }
+
+ default void enterFrame(int size) {
+ // Default implementation does nothing
+ }
}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java
index 6e1d7c36fe..211597b541 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java
@@ -41,23 +41,27 @@ public class EvaluationContextImpl implements
EvaluationContext {
private static final Logger LOG =
LoggerFactory.getLogger(EvaluationContextImpl.class);
private final FEELEventListenersManager eventsManager;
- private ArrayDeque<ExecutionFrame> stack;
- private DMNRuntime dmnRuntime;
- private boolean performRuntimeTypeCheck = false;
- private ClassLoader rootClassLoader;
+ private final ArrayDeque<ExecutionFrame> stack;
+ private final ClassLoader rootClassLoader;
private final FEELDialect feelDialect;
private final DMNVersion dmnVersion;
+ private final boolean isLenient;
- private EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager
eventsManager, Deque<ExecutionFrame> stack, FEELDialect feelDialect, DMNVersion
dmnVersion) {
+ private DMNRuntime dmnRuntime;
+ private boolean performRuntimeTypeCheck = false;
+
+ private EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager
eventsManager, Deque<ExecutionFrame> stack, FEELDialect feelDialect, DMNVersion
dmnVersion, boolean isLenient) {
this.eventsManager = eventsManager;
this.rootClassLoader = cl;
this.stack = new ArrayDeque<>(stack);
this.feelDialect = feelDialect;
this.dmnVersion = dmnVersion;
+ this.isLenient = isLenient;
}
public EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager
eventsManager, FEELDialect feelDialect, DMNVersion dmnVersion) {
- this(cl, eventsManager, 32, feelDialect, dmnVersion);
+ this(cl, eventsManager, new ArrayDeque<>(), feelDialect, dmnVersion,
true);
+ initializeFrames(32);
}
/**
@@ -68,32 +72,31 @@ public class EvaluationContextImpl implements
EvaluationContext {
}
public EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager
eventsManager, int size, FEELDialect feelDialect, DMNVersion dmnVersion) {
- this(cl, eventsManager, new ArrayDeque<>(), feelDialect, dmnVersion);
- // we create a rootFrame to hold all the built in functions
- push( RootExecutionFrame.INSTANCE );
- // and then create a global frame to be the starting frame
- // for function evaluation
- ExecutionFrameImpl global = new
ExecutionFrameImpl(RootExecutionFrame.INSTANCE, size);
- push( global );
+ this(cl, eventsManager, new ArrayDeque<>(), feelDialect, dmnVersion,
true);
+ initializeFrames(size);
+ }
+
+ public EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager
eventsManager, int size, FEELDialect feelDialect, DMNVersion dmnVersion,
boolean isLenient) {
+ this(cl, eventsManager, new ArrayDeque<>(), feelDialect, dmnVersion,
isLenient);
+ initializeFrames(size);
}
@Deprecated
public EvaluationContextImpl(FEELEventListenersManager eventsManager,
DMNRuntime dmnRuntime, FEELDialect feelDialect, DMNVersion dmnVersion) {
- this(dmnRuntime.getRootClassLoader(), eventsManager, feelDialect,
dmnVersion);
+ this(dmnRuntime.getRootClassLoader(), eventsManager, new
ArrayDeque<>(), feelDialect, dmnVersion, true);
this.dmnRuntime = dmnRuntime;
+ initializeFrames(32);
}
- private EvaluationContextImpl(FEELEventListenersManager eventsManager,
FEELDialect feelDialect, DMNVersion dmnVersion) {
- this.eventsManager = eventsManager;
- this.feelDialect = feelDialect;
- this.dmnVersion = dmnVersion;
+ private void initializeFrames(int size) {
+ push(RootExecutionFrame.INSTANCE);
+ push(new ExecutionFrameImpl(RootExecutionFrame.INSTANCE, size));
}
+
@Override
public EvaluationContext current() {
- EvaluationContextImpl ec = new EvaluationContextImpl(eventsManager,
feelDialect, dmnVersion);
- ec.stack = stack.clone();
- ec.rootClassLoader = this.rootClassLoader;
+ EvaluationContextImpl ec = new EvaluationContextImpl(
this.rootClassLoader, this.eventsManager, this.stack.clone(), this.feelDialect,
this.dmnVersion, this.isLenient);
ec.dmnRuntime = this.dmnRuntime;
ec.performRuntimeTypeCheck = this.performRuntimeTypeCheck;
return ec;
@@ -254,4 +257,9 @@ public class EvaluationContextImpl implements
EvaluationContext {
public DMNVersion getDMNVersion() {
return dmnVersion;
}
+
+ @Override
+ public boolean isLenient() {
+ return isLenient;
+ }
}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELImpl.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELImpl.java
index aadea6e4c4..d8bf1fc5a7 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELImpl.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELImpl.java
@@ -168,16 +168,33 @@ public class FEELImpl
/**
* Creates a new EvaluationContext using this FEEL instance classloader,
and the supplied parameters listeners and inputVariables
*/
- public EvaluationContextImpl
newEvaluationContext(Collection<FEELEventListener> listeners, Map<String,
Object> inputVariables) {
+ public EvaluationContextImpl
newEvaluationContext(Collection<FEELEventListener> listeners, Map<String,
Object> inputVariables ) {
return newEvaluationContext(this.classLoader, listeners,
inputVariables);
}
/**
* Creates a new EvaluationContext with the supplied classloader, and the
supplied parameters listeners and inputVariables
*/
- public EvaluationContextImpl newEvaluationContext(ClassLoader cl,
Collection<FEELEventListener> listeners, Map<String, Object> inputVariables) {
+ public EvaluationContextImpl newEvaluationContext(ClassLoader cl,
Collection<FEELEventListener> listeners, Map<String, Object> inputVariables ) {
FEELEventListenersManager eventsManager = getEventsManager(listeners);
EvaluationContextImpl ctx = new EvaluationContextImpl(cl,
eventsManager, inputVariables.size(), feelDialect, dmnVersion);
+ setupCustomFrame(ctx);
+ ctx.setValues(inputVariables);
+ return ctx;
+ }
+
+ /**
+ * Creates a new EvaluationContext with the supplied classloader, and the
supplied parameters listeners and inputVariables and isLenient
+ */
+ public EvaluationContextImpl
newEvaluationContext(Collection<FEELEventListener> listeners, Map<String,
Object> inputVariables, boolean isLenient ) {
+ FEELEventListenersManager eventsManager = getEventsManager(listeners);
+ EvaluationContextImpl ctx = new
EvaluationContextImpl(this.classLoader, eventsManager, inputVariables.size(),
feelDialect, dmnVersion, isLenient);
+ setupCustomFrame(ctx);
+ ctx.setValues(inputVariables);
+ return ctx;
+ }
+
+ private void setupCustomFrame(EvaluationContextImpl ctx) {
if (customFrame.isPresent()) {
ExecutionFrameImpl globalFrame = (ExecutionFrameImpl) ctx.pop();
ExecutionFrameImpl interveawedFrame = customFrame.get();
@@ -186,8 +203,6 @@ public class FEELImpl
ctx.push(interveawedFrame);
ctx.push(globalFrame);
}
- ctx.setValues(inputVariables);
- return ctx;
}
@Override
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java
index 621b45948f..edb5a77c57 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java
@@ -128,4 +128,19 @@ public class SilentWrappingEvaluationContextImpl
implements EvaluationContext {
public DMNVersion getDMNVersion() {
return wrapped.getDMNVersion();
}
+
+ @Override
+ public void enterFrame(int size) {
+ wrapped.enterFrame(size);
+ }
+
+ @Override
+ public boolean isLenient() {
+ return wrapped.isLenient();
+ }
+
+ @Override
+ public void setPerformRuntimeTypeCheck(boolean performRuntimeTypeCheck) {
+ wrapped.setPerformRuntimeTypeCheck(performRuntimeTypeCheck);
+ }
}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DecisionTableImpl.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DecisionTableImpl.java
index c75f1b2a06..b6131f2469 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DecisionTableImpl.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DecisionTableImpl.java
@@ -229,13 +229,18 @@ public class DecisionTableImpl implements DecisionTable {
}
if ( !satisfies ) {
- String values = input.getInputValuesText();
- return Either.ofLeft(new InvalidInputEvent(
FEELEvent.Severity.ERROR,
-
input.getInputExpression()+"='" + parameter + "' does not match any of the
valid values " + values + " for decision table '" + getName() + "'.",
- getName(),
- null,
- values )
- );
+ // Return error if context is not Lenient
+ if (!ctx.isLenient()) {
+ String values = input.getInputValuesText();
+ return Either.ofLeft(new InvalidInputEvent(
FEELEvent.Severity.ERROR,
+
input.getInputExpression()+"='" + parameter + "' does not match any of the
valid values " + values + " for decision table '" + getName() + "'.",
+ getName(),
+ null,
+ values )
+ );
+ } else {
+ params[i] = null;
+ }
}
}
}
diff --git
a/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNDecisionTableHitPolicyTest.java
b/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNDecisionTableHitPolicyTest.java
index f40d445c42..db8d8f7e57 100644
---
a/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNDecisionTableHitPolicyTest.java
+++
b/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNDecisionTableHitPolicyTest.java
@@ -31,6 +31,7 @@ import org.kie.dmn.api.core.DMNResult;
import org.kie.dmn.api.core.DMNRuntime;
import org.kie.dmn.api.feel.runtime.events.FEELEvent;
import org.kie.dmn.core.api.DMNFactory;
+import org.kie.dmn.core.compiler.RuntimeModeOption;
import org.kie.dmn.core.util.DMNRuntimeUtil;
import org.kie.dmn.feel.runtime.events.HitPolicyViolationEvent;
import org.slf4j.Logger;
@@ -66,9 +67,36 @@ public class DMNDecisionTableHitPolicyTest extends
BaseDMN1_1VariantTest {
final DMNContext context =
getSimpleTableContext(BigDecimal.valueOf(18), "ASD", false);
final DMNResult dmnResult = runtime.evaluateAll(dmnModel, context);
final DMNContext result = dmnResult.getContext();
+
+ // In lenient mode, invalid input value "ASD" is set to null and
evaluation continues
+ // Rule 4 matches: Age=any(-), RiskCategory=any(-), isAffordable=false
-> "Declined"
+ assertThat(result.get("Approval Status")).isEqualTo("Declined");
- assertThat(result.get("Approval Status")).isNull();
- assertThat(dmnResult.getMessages()).hasSizeGreaterThan(0);
+ assertThat(dmnResult.getDecisionResults()).hasSize(1);
+
assertThat(dmnResult.getDecisionResultByName("_0004-simpletable-U")).isNotNull();
+
assertThat(dmnResult.getDecisionResultByName("_0004-simpletable-U").getResult()).isEqualTo("Declined");
+
assertThat(dmnResult.getDecisionResultByName("_0004-simpletable-U").getEvaluationStatus())
+
.isEqualTo(org.kie.dmn.api.core.DMNDecisionResult.DecisionEvaluationStatus.SUCCEEDED);
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("params")
+ void simpleDecisionTableHitPolicyUniqueSatisfiesStrictMode(VariantTestConf
conf) {
+ testConfig = conf;
+ System.setProperty(RuntimeModeOption.PROPERTY_NAME,
RuntimeModeOption.MODE.STRICT.getMode());
+ try {
+ final DMNRuntime runtime =
DMNRuntimeUtil.createRuntime("0004-simpletable-U.dmn", this.getClass());
+ final DMNModel dmnModel =
runtime.getModel("https://github.com/kiegroup/kie-dmn", "0004-simpletable-U");
+ assertThat(dmnModel).isNotNull();
+
+ final DMNContext context =
getSimpleTableContext(BigDecimal.valueOf(18), "Medium", true);
+ final DMNResult dmnResult = runtime.evaluateAll(dmnModel, context);
+
+ assertThat(dmnResult.hasErrors()).isFalse();
+ assertThat(dmnResult.getContext().get("Approval
Status")).isEqualTo("Approved");
+ } finally {
+ System.clearProperty(RuntimeModeOption.PROPERTY_NAME);
+ }
}
@ParameterizedTest(name = "{0}")
diff --git
a/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNDecisionTableRuntimeTest.java
b/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNDecisionTableRuntimeTest.java
index a160371d0e..dbf06a82ab 100644
---
a/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNDecisionTableRuntimeTest.java
+++
b/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNDecisionTableRuntimeTest.java
@@ -163,7 +163,17 @@ public class DMNDecisionTableRuntimeTest extends
BaseDMN1_1VariantTest {
context.set( "Branches dispersion", "Province" );
context.set( "Number of Branches", BigDecimal.valueOf( 10 ) );
- testDecisionTableInvalidInput( context );
+ final DMNRuntime runtime = DMNRuntimeUtil.createRuntime(
"InvalidInput.dmn", this.getClass() );
+ final DMNModel dmnModel = runtime.getModel(
"http://www.trisotech.com/dmn/definitions/_cdf29af2-959b-4004-8271-82a9f5a62147",
"Dessin 1" );
+ assertThat(dmnModel).isNotNull();
+
+ final DMNResult dmnResult = runtime.evaluateAll( dmnModel, context );
+ // In lenient mode, invalid input value is set to null and evaluation
continues
+ assertThat( dmnResult.hasErrors()).isFalse();
+
+ final DMNContext result = dmnResult.getContext();
+ assertThat(result.get("Branches distribution")).isNull();
+ assertThat(result.isDefined( "Branches
distribution")).isEqualTo(Boolean.TRUE);
}
@ParameterizedTest(name = "{0}")
@@ -194,9 +204,11 @@ public class DMNDecisionTableRuntimeTest extends
BaseDMN1_1VariantTest {
assertThat(dmnModel).isNotNull();
final DMNResult dmnResult = runtime.evaluateAll( dmnModel,
inputContext );
+ // Type mismatch or missing required input causes errors
assertThat( dmnResult.hasErrors()).isTrue();
final DMNContext result = dmnResult.getContext();
+ // Result is not defined due to errors
assertThat(result.isDefined( "Branches
distribution")).isEqualTo(Boolean.FALSE);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]