You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kie.apache.org by "AthiraHari77 (via GitHub)" <gi...@apache.org> on 2026/06/25 07:06:08 UTC
[PR] [Incubator kie issues#2188] Fix the compilation failure on DecisionService–Decision output type mismatch [incubator-kie-drools]
AthiraHari77 opened a new pull request, #6776:
URL: https://github.com/apache/incubator-kie-drools/pull/6776
Closes : https://github.com/apache/incubator-kie-issues/issues/2188
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org
Re: [PR] [Incubator kie issues#2188] Fix the compilation failure on DecisionService–Decision output type mismatch [incubator-kie-drools]
Posted by "yesamer (via GitHub)" <gi...@apache.org>.
yesamer commented on PR #6776:
URL: https://github.com/apache/incubator-kie-drools/pull/6776#issuecomment-4807471947
@AthiraHari77 Is this ready to be reviewed? Can you please provide Unit Tests?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org
Re: [PR] [Incubator kie issues#2188] Fix the compilation failure on DecisionService–Decision output type mismatch [incubator-kie-drools]
Posted by "yesamer (via GitHub)" <gi...@apache.org>.
yesamer commented on code in PR #6776:
URL: https://github.com/apache/incubator-kie-drools/pull/6776#discussion_r3527420016
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDecisionServiceEvaluator.java:
##########
@@ -84,8 +93,9 @@ public EvaluatorResult evaluate(DMNRuntimeEventManager eventManager, DMNResult r
}
}
boolean typeCheck = ((DMNRuntimeImpl) eventManager.getRuntime()).performRuntimeTypeCheck(result.getModel());
+ Object finalResult = decisionIDs.size() == 1 ? ctx.values().iterator().next() : ctx;
if (typeCheck) {
- Object c = DMNRuntimeUtils.coerceUsingType(decisionIDs.size() == 1 ? ctx.values().iterator().next() : ctx,
+ Object c = DMNRuntimeUtils.coerceUsingType(finalResult,
Review Comment:
ok, but you changed the scope of the finalResult variable, previously it was managed inside the if, now is outside, is that necessary?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org
Re: [PR] [Incubator kie issues#2188] Fix the compilation failure on DecisionService–Decision output type mismatch [incubator-kie-drools]
Posted by "gitgabrio (via GitHub)" <gi...@apache.org>.
gitgabrio commented on code in PR #6776:
URL: https://github.com/apache/incubator-kie-drools/pull/6776#discussion_r3506712949
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDecisionServiceEvaluator.java:
##########
@@ -73,7 +75,14 @@ public EvaluatorResult evaluate(DMNRuntimeEventManager eventManager, DMNResult r
for (String id : decisionIDs) {
DMNDecisionResult decisionResultById = evaluateById.getDecisionResultById(id);
String decisionName = dmnModel.getDecisionById(id).getName();
- ctx.put(decisionName, decisionResultById.getResult());
+
+ DMNType expectedType = dsNode.getResultType();
+ Object originalResult = decisionResultById.getResult();
+ Object coercedResult = CoerceUtil.coerceValue(expectedType, originalResult);
+ if (coercedResult != originalResult) {
Review Comment:
HI @AthiraHari77
Please check for `null` here. both `originalResult`and `courcedResult` could be `null`, IINW
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org
Re: [PR] [Incubator kie issues#2188] Fix the compilation failure on DecisionService–Decision output type mismatch [incubator-kie-drools]
Posted by "AthiraHari77 (via GitHub)" <gi...@apache.org>.
AthiraHari77 commented on code in PR #6776:
URL: https://github.com/apache/incubator-kie-drools/pull/6776#discussion_r3526852357
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDecisionServiceEvaluator.java:
##########
@@ -84,8 +93,9 @@ public EvaluatorResult evaluate(DMNRuntimeEventManager eventManager, DMNResult r
}
}
boolean typeCheck = ((DMNRuntimeImpl) eventManager.getRuntime()).performRuntimeTypeCheck(result.getModel());
+ Object finalResult = decisionIDs.size() == 1 ? ctx.values().iterator().next() : ctx;
if (typeCheck) {
- Object c = DMNRuntimeUtils.coerceUsingType(decisionIDs.size() == 1 ? ctx.values().iterator().next() : ctx,
+ Object c = DMNRuntimeUtils.coerceUsingType(finalResult,
Review Comment:
The extraction was kept for better readability.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org
Re: [PR] [Incubator kie issues#2188] Fix the compilation failure on DecisionService–Decision output type mismatch [incubator-kie-drools]
Posted by "gitgabrio (via GitHub)" <gi...@apache.org>.
gitgabrio commented on code in PR #6776:
URL: https://github.com/apache/incubator-kie-drools/pull/6776#discussion_r3526974433
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDecisionServiceEvaluator.java:
##########
@@ -22,14 +22,15 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
import org.kie.dmn.api.core.DMNDecisionResult;
import org.kie.dmn.api.core.DMNMessage;
import org.kie.dmn.api.core.DMNMessage.Severity;
import org.kie.dmn.api.core.DMNModel;
import org.kie.dmn.api.core.DMNResult;
import org.kie.dmn.api.core.DMNRuntime;
+import org.kie.dmn.api.core.DMNType;
+import org.kie.dmn.api.core.ast.DecisionNode;
Review Comment:
HI @AthiraHari77 IINW, this import is unneeded
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDecisionServiceEvaluator.java:
##########
@@ -84,8 +93,9 @@ public EvaluatorResult evaluate(DMNRuntimeEventManager eventManager, DMNResult r
}
}
boolean typeCheck = ((DMNRuntimeImpl) eventManager.getRuntime()).performRuntimeTypeCheck(result.getModel());
+ Object finalResult = decisionIDs.size() == 1 ? ctx.values().iterator().next() : ctx;
if (typeCheck) {
- Object c = DMNRuntimeUtils.coerceUsingType(decisionIDs.size() == 1 ? ctx.values().iterator().next() : ctx,
+ Object c = DMNRuntimeUtils.coerceUsingType(finalResult,
Review Comment:
@AthiraHari77
I know that code was already there, but the name of this method:
`DMNRuntimeUtils.coerceUsingType` is unclear and, keeping in mind we also have `CoerceUtil.coerceValue` , the overall result is pretty confusing.
`DMNRuntimeUtils.coerceUsingType` actually deals only with `Collections`: could you please verify that and, eventually, rename it to make that clearer ? Just to reduce a bit tech debts while we found them. Thanks!
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DecisionServiceCompiler.java:
##########
@@ -216,115 +219,166 @@ private void reportReferenceError(DecisionServiceNodeImpl ni, DMNModelImpl model
ni.getName());
}
- private void checkFnConsistency(DMNModelImpl model, DecisionServiceNodeImpl ni, DMNType type, List<DecisionNode> outputDecisions) {
- SimpleFnTypeImpl fnType = ((SimpleFnTypeImpl) type);
- FunctionItem fi = fnType.getFunctionItem();
- if (fi.getParameters().size() != ni.getInputParameters().size()) {
+ private void validateDecisionServiceFunctionSignature(DMNModelImpl model, DecisionServiceNodeImpl decisionServiceNode, DMNType decisionServiceFunctionType, List<DecisionNode> outputDecisions) {
+ SimpleFnTypeImpl functionType = ((SimpleFnTypeImpl) decisionServiceFunctionType);
+ FunctionItem functionItem = functionType.getFunctionItem();
+ if (functionItem.getParameters().size() != decisionServiceNode.getInputParameters().size()) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_COUNT_MISMATCH_COMPILING,
- ni.getName(),
- fi.getParameters().size(),
- ni.getInputParameters().size());
+ decisionServiceNode.getName(),
+ functionItem.getParameters().size(),
+ decisionServiceNode.getInputParameters().size());
return;
}
- for (int i = 0; i < fi.getParameters().size(); i++) {
- InformationItem fiII = fi.getParameters().get(i);
- String fpName = ni.getInputParameters().keySet().stream().skip(i).findFirst().orElse(null);
- if (!fiII.getName().equals(fpName)) {
- List<String> fiParamNames = fi.getParameters().stream().map(InformationItem::getName).collect(Collectors.toList());
- List<String> funcDefParamNames = ni.getInputParameters().keySet().stream().collect(Collectors.toList());
+ for (int i = 0; i < functionItem.getParameters().size(); i++) {
+ InformationItem functionParameter = functionItem.getParameters().get(i);
+ String functionParameterName = decisionServiceNode.getInputParameters().keySet().stream().skip(i).findFirst().orElse(null);
+ if (!functionParameter.getName().equals(functionParameterName)) {
+ List<String> functionItemParamNames = functionItem.getParameters().stream().map(InformationItem::getName).collect(Collectors.toList());
+ List<String> decisionServiceParamNames = decisionServiceNode.getInputParameters().keySet().stream().collect(Collectors.toList());
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_NAMES_MISMATCH_COMPILING,
- ni.getName(),
- fiParamNames,
- funcDefParamNames);
+ decisionServiceNode.getName(),
+ functionItemParamNames,
+ decisionServiceParamNames);
return;
}
- QName fiQname = fiII.getTypeRef();
- QName fdQname = null;
- DMNNode fpDMNNode = ni.getInputParameters().get(fpName);
- if (fpDMNNode instanceof InputDataNodeImpl) {
- fdQname = ((InputDataNodeImpl) fpDMNNode).getInputData().getVariable().getTypeRef();
- } else if (fpDMNNode instanceof DecisionNodeImpl) {
- fdQname = ((DecisionNodeImpl) fpDMNNode).getDecision().getVariable().getTypeRef();
+ QName functionParameterTypeRef = functionParameter.getTypeRef();
+ QName decisionServiceParameterTypeRef = null;
+ DMNNode inputParameterNode = decisionServiceNode.getInputParameters().get(functionParameterName);
+ if (inputParameterNode instanceof InputDataNodeImpl) {
+ decisionServiceParameterTypeRef = ((InputDataNodeImpl) inputParameterNode).getInputData().getVariable().getTypeRef();
+ } else if (inputParameterNode instanceof DecisionNodeImpl) {
+ decisionServiceParameterTypeRef = ((DecisionNodeImpl) inputParameterNode).getDecision().getVariable().getTypeRef();
}
- if (fiQname != null && fdQname != null && !fiQname.equals(fdQname)) {
+ if (functionParameterTypeRef != null && decisionServiceParameterTypeRef != null && !functionParameterTypeRef.equals(decisionServiceParameterTypeRef)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiII.getName(),
- fiQname,
- fdQname);
+ decisionServiceNode.getName(),
+ functionParameter.getName(),
+ functionParameterTypeRef,
+ decisionServiceParameterTypeRef);
}
}
- QName fiReturnType = fi.getOutputTypeRef();
- if (ni.getDecisionService().getOutputDecision().size() == 1) {
- QName fdReturnType = outputDecisions.get(0).getDecision().getVariable().getTypeRef();
- if (fiReturnType != null && fdReturnType != null && !fiReturnType.equals(fdReturnType)) {
+ QName functionReturnTypeRef = functionItem.getOutputTypeRef();
+ if (decisionServiceNode.getDecisionService().getOutputDecision().size() == 1) {
+ QName outputDecisionReturnTypeRef = outputDecisions.get(0).getDecision().getVariable().getTypeRef();
+ if (functionReturnTypeRef != null && outputDecisionReturnTypeRef != null && !functionReturnTypeRef.equals(outputDecisionReturnTypeRef) && !isReturnTypeCollectionCompatible(functionReturnTypeRef, outputDecisionReturnTypeRef, model)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiReturnType,
- fdReturnType);
+ decisionServiceNode.getName(),
+ functionReturnTypeRef,
+ outputDecisionReturnTypeRef);
}
- } else if (ni.getDecisionService().getOutputDecision().size() > 1) {
- final Function<QName, QName> lookupFn = (in) -> NamespaceUtil.getNamespaceAndName(ni.getDecisionService(), model.getImportAliasesForNS(), in, model.getNamespace());
- LinkedHashMap<String, QName> fdComposite = new LinkedHashMap<>();
- for (DecisionNode dn : outputDecisions) {
- fdComposite.put(dn.getName(), lookupFn.apply(dn.getDecision().getVariable().getTypeRef()));
+ } else if (decisionServiceNode.getDecisionService().getOutputDecision().size() > 1) {
+ final Function<QName, QName> namespaceQNameLookup = (qname) -> NamespaceUtil.getNamespaceAndName(decisionServiceNode.getDecisionService(), model.getImportAliasesForNS(), qname, model.getNamespace());
+ LinkedHashMap<String, QName> decisionServiceCompositeType = new LinkedHashMap<>();
+ for (DecisionNode decisionNode : outputDecisions) {
+ decisionServiceCompositeType.put(decisionNode.getName(), namespaceQNameLookup.apply(decisionNode.getDecision().getVariable().getTypeRef()));
}
- final QName lookup = lookupFn.apply(fiReturnType);
- Optional<ItemDefNodeImpl> composite = model.getItemDefinitions().stream().filter(id -> id.getModelNamespace().equals(lookup.getNamespaceURI()) && id.getName().equals(lookup.getLocalPart())).map(ItemDefNodeImpl.class::cast).findFirst();
- if (composite.isEmpty()) {
+ final QName resolvedFunctionReturnTypeRef = namespaceQNameLookup.apply(functionReturnTypeRef);
+ Optional<ItemDefNodeImpl> matchedItemDefNode = model.getItemDefinitions().stream().filter(id -> id.getModelNamespace().equals(resolvedFunctionReturnTypeRef.getNamespaceURI()) && id.getName().equals(resolvedFunctionReturnTypeRef.getLocalPart())).map(ItemDefNodeImpl.class::cast).findFirst();
+ if (matchedItemDefNode.isEmpty()) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- lookup,
- fdComposite);
+ decisionServiceNode.getName(),
+ resolvedFunctionReturnTypeRef,
+ decisionServiceCompositeType);
return;
}
- LinkedHashMap<String, QName> fiComposite = new LinkedHashMap<>();
- for (ItemDefinition ic : composite.get().getItemDef().getItemComponent()) {
- fiComposite.put(ic.getName(), lookupFn.apply(ic.getTypeRef()));
+ LinkedHashMap<String, QName> functionCompositeType = new LinkedHashMap<>();
+ for (ItemDefinition itemDefinition : matchedItemDefNode.get().getItemDef().getItemComponent()) {
+ functionCompositeType.put(itemDefinition.getName(), namespaceQNameLookup.apply(itemDefinition.getTypeRef()));
}
- if (!fiComposite.equals(fdComposite)) {
+ if (!functionCompositeType.equals(decisionServiceCompositeType)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiComposite,
- fdComposite);
+ decisionServiceNode.getName(),
+ functionCompositeType,
+ decisionServiceCompositeType);
}
}
}
+ static boolean isReturnTypeCollectionCompatible(QName functionReturnTypeRef, QName outputDecisionReturnTypeRef, DMNModelImpl model) {
Review Comment:
Hi @AthiraHari77
Those two static methods IMO should go to some common utility class, since there behavior is very "generic" and probably already needed elsewhere.
Maybe inside `DMNRuntimeUtils` ? Or maybe there is already some "util" class that deals with similar implementations ?
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DecisionServiceCompiler.java:
##########
@@ -216,115 +219,166 @@ private void reportReferenceError(DecisionServiceNodeImpl ni, DMNModelImpl model
ni.getName());
}
- private void checkFnConsistency(DMNModelImpl model, DecisionServiceNodeImpl ni, DMNType type, List<DecisionNode> outputDecisions) {
- SimpleFnTypeImpl fnType = ((SimpleFnTypeImpl) type);
- FunctionItem fi = fnType.getFunctionItem();
- if (fi.getParameters().size() != ni.getInputParameters().size()) {
+ private void validateDecisionServiceFunctionSignature(DMNModelImpl model, DecisionServiceNodeImpl decisionServiceNode, DMNType decisionServiceFunctionType, List<DecisionNode> outputDecisions) {
Review Comment:
👍 🙏 ❤️
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+ when(registry.resolveType("ns", "string"))
+ .thenReturn(null);
+
+ QName qName = new QName("", "string");
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(qName, model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveDMNTypeDateAndTime() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
Review Comment:
Same comment as above
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+ when(registry.resolveType("ns", "string"))
+ .thenReturn(null);
+
+ QName qName = new QName("", "string");
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(qName, model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveDMNTypeDateAndTime() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("", "date and time"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.DATE_TIME);
+ assertThat(result.isCollection()).isFalse();
+ }
+
+ @Test
+ void resolveDMNType_listBuiltInIsMarkedAsCollection() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
Review Comment:
Same comment as above
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
Review Comment:
@AthiraHari77
The need of those mocks (that actually creates a "fake" implementation) is related to that implementation ->
```java
static DMNType resolveDMNType(QName typeRef, DMNModelImpl model) {
DMNType type = model.getTypeRegistry().resolveType(model.getNamespace(), typeRef.getLocalPart());
if (type == null) {
BuiltInType builtInType = resolveBuiltInType(typeRef.getLocalPart());
if (builtInType != null) {
boolean isCollection = (builtInType == BuiltInType.LIST);
type = new SimpleTypeImpl(
model.getNamespace(),
builtInType.getName(),
null,
isCollection,
null,
null,
null,
builtInType
);
}
}
return type;
}
```
What this test is about is the `type==null` branch of execution but, since it is embedded inside the `DMNType resolveDMNTYpe`, hence the need of (slightly contrived) mocking.
Extracting the content of `type==null` branch to a specific method, would reduce the "cyclomatic complexity" of the method ( 😄 ) and simplify testing it, removing the need of "mocks".
(In general terms, lot of time mocks are always a smell of something not perfectly encapsulated).
Am I clear ? Does this make sense ?
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DecisionServiceCompiler.java:
##########
@@ -216,115 +219,166 @@ private void reportReferenceError(DecisionServiceNodeImpl ni, DMNModelImpl model
ni.getName());
}
- private void checkFnConsistency(DMNModelImpl model, DecisionServiceNodeImpl ni, DMNType type, List<DecisionNode> outputDecisions) {
- SimpleFnTypeImpl fnType = ((SimpleFnTypeImpl) type);
- FunctionItem fi = fnType.getFunctionItem();
- if (fi.getParameters().size() != ni.getInputParameters().size()) {
+ private void validateDecisionServiceFunctionSignature(DMNModelImpl model, DecisionServiceNodeImpl decisionServiceNode, DMNType decisionServiceFunctionType, List<DecisionNode> outputDecisions) {
+ SimpleFnTypeImpl functionType = ((SimpleFnTypeImpl) decisionServiceFunctionType);
+ FunctionItem functionItem = functionType.getFunctionItem();
+ if (functionItem.getParameters().size() != decisionServiceNode.getInputParameters().size()) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_COUNT_MISMATCH_COMPILING,
- ni.getName(),
- fi.getParameters().size(),
- ni.getInputParameters().size());
+ decisionServiceNode.getName(),
+ functionItem.getParameters().size(),
+ decisionServiceNode.getInputParameters().size());
return;
}
- for (int i = 0; i < fi.getParameters().size(); i++) {
- InformationItem fiII = fi.getParameters().get(i);
- String fpName = ni.getInputParameters().keySet().stream().skip(i).findFirst().orElse(null);
- if (!fiII.getName().equals(fpName)) {
- List<String> fiParamNames = fi.getParameters().stream().map(InformationItem::getName).collect(Collectors.toList());
- List<String> funcDefParamNames = ni.getInputParameters().keySet().stream().collect(Collectors.toList());
+ for (int i = 0; i < functionItem.getParameters().size(); i++) {
+ InformationItem functionParameter = functionItem.getParameters().get(i);
+ String functionParameterName = decisionServiceNode.getInputParameters().keySet().stream().skip(i).findFirst().orElse(null);
+ if (!functionParameter.getName().equals(functionParameterName)) {
+ List<String> functionItemParamNames = functionItem.getParameters().stream().map(InformationItem::getName).collect(Collectors.toList());
+ List<String> decisionServiceParamNames = decisionServiceNode.getInputParameters().keySet().stream().collect(Collectors.toList());
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_NAMES_MISMATCH_COMPILING,
- ni.getName(),
- fiParamNames,
- funcDefParamNames);
+ decisionServiceNode.getName(),
+ functionItemParamNames,
+ decisionServiceParamNames);
return;
}
- QName fiQname = fiII.getTypeRef();
- QName fdQname = null;
- DMNNode fpDMNNode = ni.getInputParameters().get(fpName);
- if (fpDMNNode instanceof InputDataNodeImpl) {
- fdQname = ((InputDataNodeImpl) fpDMNNode).getInputData().getVariable().getTypeRef();
- } else if (fpDMNNode instanceof DecisionNodeImpl) {
- fdQname = ((DecisionNodeImpl) fpDMNNode).getDecision().getVariable().getTypeRef();
+ QName functionParameterTypeRef = functionParameter.getTypeRef();
+ QName decisionServiceParameterTypeRef = null;
+ DMNNode inputParameterNode = decisionServiceNode.getInputParameters().get(functionParameterName);
+ if (inputParameterNode instanceof InputDataNodeImpl) {
+ decisionServiceParameterTypeRef = ((InputDataNodeImpl) inputParameterNode).getInputData().getVariable().getTypeRef();
+ } else if (inputParameterNode instanceof DecisionNodeImpl) {
+ decisionServiceParameterTypeRef = ((DecisionNodeImpl) inputParameterNode).getDecision().getVariable().getTypeRef();
}
- if (fiQname != null && fdQname != null && !fiQname.equals(fdQname)) {
+ if (functionParameterTypeRef != null && decisionServiceParameterTypeRef != null && !functionParameterTypeRef.equals(decisionServiceParameterTypeRef)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.PARAMETER_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiII.getName(),
- fiQname,
- fdQname);
+ decisionServiceNode.getName(),
+ functionParameter.getName(),
+ functionParameterTypeRef,
+ decisionServiceParameterTypeRef);
}
}
- QName fiReturnType = fi.getOutputTypeRef();
- if (ni.getDecisionService().getOutputDecision().size() == 1) {
- QName fdReturnType = outputDecisions.get(0).getDecision().getVariable().getTypeRef();
- if (fiReturnType != null && fdReturnType != null && !fiReturnType.equals(fdReturnType)) {
+ QName functionReturnTypeRef = functionItem.getOutputTypeRef();
+ if (decisionServiceNode.getDecisionService().getOutputDecision().size() == 1) {
+ QName outputDecisionReturnTypeRef = outputDecisions.get(0).getDecision().getVariable().getTypeRef();
+ if (functionReturnTypeRef != null && outputDecisionReturnTypeRef != null && !functionReturnTypeRef.equals(outputDecisionReturnTypeRef) && !isReturnTypeCollectionCompatible(functionReturnTypeRef, outputDecisionReturnTypeRef, model)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiReturnType,
- fdReturnType);
+ decisionServiceNode.getName(),
+ functionReturnTypeRef,
+ outputDecisionReturnTypeRef);
}
- } else if (ni.getDecisionService().getOutputDecision().size() > 1) {
- final Function<QName, QName> lookupFn = (in) -> NamespaceUtil.getNamespaceAndName(ni.getDecisionService(), model.getImportAliasesForNS(), in, model.getNamespace());
- LinkedHashMap<String, QName> fdComposite = new LinkedHashMap<>();
- for (DecisionNode dn : outputDecisions) {
- fdComposite.put(dn.getName(), lookupFn.apply(dn.getDecision().getVariable().getTypeRef()));
+ } else if (decisionServiceNode.getDecisionService().getOutputDecision().size() > 1) {
+ final Function<QName, QName> namespaceQNameLookup = (qname) -> NamespaceUtil.getNamespaceAndName(decisionServiceNode.getDecisionService(), model.getImportAliasesForNS(), qname, model.getNamespace());
+ LinkedHashMap<String, QName> decisionServiceCompositeType = new LinkedHashMap<>();
+ for (DecisionNode decisionNode : outputDecisions) {
+ decisionServiceCompositeType.put(decisionNode.getName(), namespaceQNameLookup.apply(decisionNode.getDecision().getVariable().getTypeRef()));
}
- final QName lookup = lookupFn.apply(fiReturnType);
- Optional<ItemDefNodeImpl> composite = model.getItemDefinitions().stream().filter(id -> id.getModelNamespace().equals(lookup.getNamespaceURI()) && id.getName().equals(lookup.getLocalPart())).map(ItemDefNodeImpl.class::cast).findFirst();
- if (composite.isEmpty()) {
+ final QName resolvedFunctionReturnTypeRef = namespaceQNameLookup.apply(functionReturnTypeRef);
+ Optional<ItemDefNodeImpl> matchedItemDefNode = model.getItemDefinitions().stream().filter(id -> id.getModelNamespace().equals(resolvedFunctionReturnTypeRef.getNamespaceURI()) && id.getName().equals(resolvedFunctionReturnTypeRef.getLocalPart())).map(ItemDefNodeImpl.class::cast).findFirst();
+ if (matchedItemDefNode.isEmpty()) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- lookup,
- fdComposite);
+ decisionServiceNode.getName(),
+ resolvedFunctionReturnTypeRef,
+ decisionServiceCompositeType);
return;
}
- LinkedHashMap<String, QName> fiComposite = new LinkedHashMap<>();
- for (ItemDefinition ic : composite.get().getItemDef().getItemComponent()) {
- fiComposite.put(ic.getName(), lookupFn.apply(ic.getTypeRef()));
+ LinkedHashMap<String, QName> functionCompositeType = new LinkedHashMap<>();
+ for (ItemDefinition itemDefinition : matchedItemDefNode.get().getItemDef().getItemComponent()) {
+ functionCompositeType.put(itemDefinition.getName(), namespaceQNameLookup.apply(itemDefinition.getTypeRef()));
}
- if (!fiComposite.equals(fdComposite)) {
+ if (!functionCompositeType.equals(decisionServiceCompositeType)) {
MsgUtil.reportMessage(LOG,
DMNMessage.Severity.ERROR,
- ni.getDecisionService(),
+ decisionServiceNode.getDecisionService(),
model,
null,
null,
Msg.RETURNTYPE_TYPEREF_MISMATCH_COMPILING,
- ni.getName(),
- fiComposite,
- fdComposite);
+ decisionServiceNode.getName(),
+ functionCompositeType,
+ decisionServiceCompositeType);
}
}
}
+ static boolean isReturnTypeCollectionCompatible(QName functionReturnTypeRef, QName outputDecisionReturnTypeRef, DMNModelImpl model) {
+ DMNType decisionServiceOutputType = resolveDMNType(functionReturnTypeRef, model);
+ DMNType decisionOutputType = resolveDMNType(outputDecisionReturnTypeRef, model);
+
+ if (!decisionServiceOutputType.isCollection() && decisionOutputType.isCollection()) {
+ DMNType outputDecisionElementType = decisionOutputType.getBaseType();
+ return outputDecisionElementType == null || DMNTypeUtils.getFEELBuiltInType(outputDecisionElementType)
+ == DMNTypeUtils.getFEELBuiltInType(decisionServiceOutputType);
+ }
+ if (decisionServiceOutputType.isCollection() && !decisionOutputType.isCollection()) {
+ DMNType decisionServiceElementType = decisionServiceOutputType.getBaseType();
+ return decisionServiceElementType != null && DMNTypeUtils.getFEELBuiltInType(decisionServiceElementType)
+ == DMNTypeUtils.getFEELBuiltInType(decisionOutputType);
+ }
+ return decisionServiceOutputType instanceof SimpleTypeImpl decisionServiceSimpleType && decisionServiceSimpleType.getFeelType() == BuiltInType.DATE_TIME &&
+ decisionOutputType instanceof SimpleTypeImpl decisionOutputSimpleType && decisionOutputSimpleType.getFeelType() == BuiltInType.DATE;
+ }
+
+ static DMNType resolveDMNType(QName typeRef, DMNModelImpl model) {
+ DMNType type = model.getTypeRegistry().resolveType(model.getNamespace(), typeRef.getLocalPart());
+ if (type == null) {
+ BuiltInType builtInType = resolveBuiltInType(typeRef.getLocalPart());
+ if (builtInType != null) {
+ boolean isCollection = (builtInType == BuiltInType.LIST);
+ type = new SimpleTypeImpl(
+ model.getNamespace(),
+ builtInType.getName(),
+ null,
+ isCollection,
+ null,
+ null,
+ null,
+ builtInType
+ );
+ }
+ }
+ return type;
+ }
+
+ static BuiltInType resolveBuiltInType(String name) {
Review Comment:
See comment above. I've the impression that this functionality is already implemented somewhere, but I can't recall where 🤔 (I may be wrong, of course)
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+ when(registry.resolveType("ns", "string"))
+ .thenReturn(null);
+
+ QName qName = new QName("", "string");
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(qName, model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveDMNTypeDateAndTime() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("", "date and time"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.DATE_TIME);
+ assertThat(result.isCollection()).isFalse();
+ }
+
+ @Test
+ void resolveDMNType_listBuiltInIsMarkedAsCollection() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("", "list"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.LIST);
+ assertThat(result.isCollection()).isTrue();
+ }
+
+ @Test
+ void resolveDMNType_unknownNameReturnsNull() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.resolveDMNType(new QName("", "not-a-type"), model)).isNull();
+ }
+
+ // fi=scalar "string", fd=collection "tDateList" (base=date) — bases differ → false
+ @Test
+ void isReturnTypeCollectionCompatible_incompatibleType() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false, null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null, true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv -> "tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "string"), new QName(ns, "tDateList"), model)).isFalse();
+ }
+
+ // fi=scalar "date", fd=collection "tDateList" (base=date) — same base → true
+ @Test
+ void isReturnTypeCollectionCompatible_compatibleType() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false, null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null, true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv -> "tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "date"), new QName(ns, "tDateList"), model)).isTrue();
+ }
+
+
+ // fi=collection "tDateList" (base=date), fd=scalar "date" — compatible → true
+ @Test
+ void isReturnTypeCollectionCompatible_collectionFi_scalarFd_compatibleBase() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false, null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null, true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv -> "tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "tDateList"), new QName(ns, "date"), model)).isTrue();
+ }
+
+
+ // fi="date and time", fd="date" — date-to-dateTime coercion pattern → true
+ @Test
+ void isReturnTypeCollectionCompatible_dateTimeFi_dateFd_compatible() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
Review Comment:
Same comment as above
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+ when(registry.resolveType("ns", "string"))
+ .thenReturn(null);
+
+ QName qName = new QName("", "string");
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(qName, model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveDMNTypeDateAndTime() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("", "date and time"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.DATE_TIME);
+ assertThat(result.isCollection()).isFalse();
+ }
+
+ @Test
+ void resolveDMNType_listBuiltInIsMarkedAsCollection() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("", "list"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.LIST);
+ assertThat(result.isCollection()).isTrue();
+ }
+
+ @Test
+ void resolveDMNType_unknownNameReturnsNull() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
Review Comment:
Same comment as above
##########
kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/decisionservices/DecisionServiceImplicitConversions.dmn:
##########
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
Review Comment:
HI @AthiraHari77
Plkease, do not add new dmn models outside `kie-dmn-test-resources`.
Our approach is to have all testing DMN inside `kie-dmn-test-resources` and then refer to them properly.
Thanks!
##########
kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java:
##########
@@ -144,4 +148,179 @@ void inputQualifiedNamePrefixWithEmptyImportAlias() {
}
+ @Test
+ void resolveBuiltInType_nullReturnsNull() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType(null)).isNull();
+ }
+
+ @Test
+ void resolveBuiltInType_stringCaseInsensitive() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("STRING")).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveBuiltInType_date() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date")).isEqualTo(BuiltInType.DATE);
+ }
+
+ @Test
+ void resolveBuiltInType_dateAndTime() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("date and time")).isEqualTo(BuiltInType.DATE_TIME);
+ }
+
+ @Test
+ void resolveBuiltInType_number() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("number")).isEqualTo(BuiltInType.NUMBER);
+ }
+
+ @Test
+ void resolveBuiltInType_boolean() {
+ assertThat(DecisionServiceCompiler.resolveBuiltInType("boolean")).isEqualTo(BuiltInType.BOOLEAN);
+ }
+
+
+ @Test
+ void resolveDMNTypeString() {
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+ when(registry.resolveType("ns", "string"))
+ .thenReturn(null);
+
+ QName qName = new QName("", "string");
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(qName, model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.STRING);
+ }
+
+ @Test
+ void resolveDMNTypeDateAndTime() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("", "date and time"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.DATE_TIME);
+ assertThat(result.isCollection()).isFalse();
+ }
+
+ @Test
+ void resolveDMNType_listBuiltInIsMarkedAsCollection() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ DMNType result = DecisionServiceCompiler.resolveDMNType(new QName("", "list"), model);
+ assertThat(result).isInstanceOf(SimpleTypeImpl.class);
+ assertThat(((SimpleTypeImpl) result).getFeelType()).isEqualTo(BuiltInType.LIST);
+ assertThat(result.isCollection()).isTrue();
+ }
+
+ @Test
+ void resolveDMNType_unknownNameReturnsNull() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.resolveDMNType(new QName("", "not-a-type"), model)).isNull();
+ }
+
+ // fi=scalar "string", fd=collection "tDateList" (base=date) — bases differ → false
+ @Test
+ void isReturnTypeCollectionCompatible_incompatibleType() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false, null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null, true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv -> "tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "string"), new QName(ns, "tDateList"), model)).isFalse();
+ }
+
+ // fi=scalar "date", fd=collection "tDateList" (base=date) — same base → true
+ @Test
+ void isReturnTypeCollectionCompatible_compatibleType() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false, null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null, true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv -> "tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "date"), new QName(ns, "tDateList"), model)).isTrue();
+ }
+
+
+ // fi=collection "tDateList" (base=date), fd=scalar "date" — compatible → true
+ @Test
+ void isReturnTypeCollectionCompatible_collectionFi_scalarFd_compatibleBase() {
+ final String ns = "ns";
+ SimpleTypeImpl dateType = new SimpleTypeImpl(ns, "date", null, false, null, null, null, BuiltInType.DATE);
+ SimpleTypeImpl tDateList = new SimpleTypeImpl(ns, "tDateList", null, true, null, null, dateType, BuiltInType.DATE);
+
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenAnswer(inv -> "tDateList".equals(inv.getArgument(1)) ? tDateList : null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn(ns);
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName(ns, "tDateList"), new QName(ns, "date"), model)).isTrue();
+ }
+
+
+ // fi="date and time", fd="date" — date-to-dateTime coercion pattern → true
+ @Test
+ void isReturnTypeCollectionCompatible_dateTimeFi_dateFd_compatible() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
+ when(registry.resolveType(any(), any())).thenReturn(null);
+
+ DMNModelImpl model = mock(DMNModelImpl.class);
+ when(model.getNamespace()).thenReturn("ns");
+ when(model.getTypeRegistry()).thenReturn(registry);
+
+ assertThat(DecisionServiceCompiler.isReturnTypeCollectionCompatible(
+ new QName("", "date and time"), new QName("", "date"), model)).isTrue();
+ }
+
+ // fi="date", fd="date and time" — order matters → false
+ @Test
+ void isReturnTypeCollectionCompatible_dateFi_dateTimeFd_incompatible() {
+ DMNTypeRegistry registry = mock(DMNTypeRegistry.class);
Review Comment:
Same comment as above
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org
Re: [PR] [Incubator kie issues#2188] Fix the compilation failure on DecisionService–Decision output type mismatch [incubator-kie-drools]
Posted by "AthiraHari77 (via GitHub)" <gi...@apache.org>.
AthiraHari77 commented on PR #6776:
URL: https://github.com/apache/incubator-kie-drools/pull/6776#issuecomment-4855241134
> Does this PR handle also a situation when the decision service output data type is structure? Like **Person(name, age)**, then decision service upper part may contain two decision nodes: **name** and **age** and it should be valid scenario.
@jomarko The DMN v1.6 specification explicitly defines implicit conversions only for primitive and list types (singleton list wrapping/unwrapping, date → dateTime, decimal → integer). It does not explicitly specify any additional implicit conversion semantics for custom or structured types such as Person(name, age).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org
Re: [PR] [Incubator kie issues#2188] Fix the compilation failure on DecisionService–Decision output type mismatch [incubator-kie-drools]
Posted by "yesamer (via GitHub)" <gi...@apache.org>.
yesamer commented on code in PR #6776:
URL: https://github.com/apache/incubator-kie-drools/pull/6776#discussion_r3519920864
##########
kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDecisionServiceEvaluator.java:
##########
@@ -84,8 +93,9 @@ public EvaluatorResult evaluate(DMNRuntimeEventManager eventManager, DMNResult r
}
}
boolean typeCheck = ((DMNRuntimeImpl) eventManager.getRuntime()).performRuntimeTypeCheck(result.getModel());
+ Object finalResult = decisionIDs.size() == 1 ? ctx.values().iterator().next() : ctx;
if (typeCheck) {
- Object c = DMNRuntimeUtils.coerceUsingType(decisionIDs.size() == 1 ? ctx.values().iterator().next() : ctx,
+ Object c = DMNRuntimeUtils.coerceUsingType(finalResult,
Review Comment:
@AthiraHari77 Why this change, please?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org
Re: [PR] [Incubator kie issues#2188] Fix the compilation failure on DecisionService–Decision output type mismatch [incubator-kie-drools]
Posted by "jomarko (via GitHub)" <gi...@apache.org>.
jomarko commented on PR #6776:
URL: https://github.com/apache/incubator-kie-drools/pull/6776#issuecomment-4851055577
Does this PR handle also a situation when the decision service output data type is structure? Like **Person(name, age)**, then decision service upper part may contain two decision nodes: **name** and **age** and it should be valid scenario.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org
Re: [PR] [Incubator kie issues#2188] Fix the compilation failure on DecisionService–Decision output type mismatch [incubator-kie-drools]
Posted by "gitgabrio (via GitHub)" <gi...@apache.org>.
gitgabrio merged PR #6776:
URL: https://github.com/apache/incubator-kie-drools/pull/6776
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org