This is an automated email from the ASF dual-hosted git repository.
tzimanyi pushed a commit to branch 8.40.x
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git
The following commit(s) were added to refs/heads/8.40.x by this push:
new 8de49a3058 [8.40.x][kie-issues#941] Fix executable model generation
for binding enclosed in parentheses (#5753)
8de49a3058 is described below
commit 8de49a305825c8746ebc9015bff8e0b57ca2b370
Author: Tibor Zimányi <[email protected]>
AuthorDate: Mon Mar 4 10:06:25 2024 +0100
[8.40.x][kie-issues#941] Fix executable model generation for binding
enclosed in parentheses (#5753)
---
.../drlxparse/ArithmeticCoercedExpression.java | 4 +
.../generator/drlxparse/ConstraintParser.java | 61 +++++++++++---
.../drlxparse/SingleDrlxParseSuccess.java | 20 ++++-
.../expression/AbstractExpressionBuilder.java | 13 ++-
.../generator/expressiontyper/ExpressionTyper.java | 50 +++++++++++-
.../model/codegen/execmodel/BindingTest.java | 65 +++++++++++++++
.../codegen/execmodel/bigdecimaltest/BDFact.java | 43 ++++++++++
.../execmodel/bigdecimaltest/BigDecimalTest.java | 92 ++++++++++++++++++++++
8 files changed, 333 insertions(+), 15 deletions(-)
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ArithmeticCoercedExpression.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ArithmeticCoercedExpression.java
index 89d7d77b9c..dfd241615f 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ArithmeticCoercedExpression.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ArithmeticCoercedExpression.java
@@ -51,6 +51,10 @@ public class ArithmeticCoercedExpression {
this.operator = operator;
}
+ /*
+ * This coercion only deals with String vs Numeric types.
+ * BigDecimal arithmetic operation is handled by
ExpressionTyper.convertArithmeticBinaryToMethodCall()
+ */
public ArithmeticCoercedExpressionResult coerce() {
if (!requiresCoercion()) {
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java
index 0dfe9a472f..a0064a4c02 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java
@@ -94,6 +94,9 @@ import static
org.drools.model.codegen.execmodel.generator.ConstraintUtil.GREATE
import static
org.drools.model.codegen.execmodel.generator.ConstraintUtil.GREATER_THAN_PREFIX;
import static
org.drools.model.codegen.execmodel.generator.ConstraintUtil.LESS_OR_EQUAL_PREFIX;
import static
org.drools.model.codegen.execmodel.generator.ConstraintUtil.LESS_THAN_PREFIX;
+import static
org.drools.model.codegen.execmodel.generator.expressiontyper.ExpressionTyper.convertArithmeticBinaryToMethodCall;
+import static
org.drools.model.codegen.execmodel.generator.expressiontyper.ExpressionTyper.getBinaryTypeAfterConversion;
+import static
org.drools.model.codegen.execmodel.generator.expressiontyper.ExpressionTyper.shouldConvertArithmeticBinaryToMethodCall;
import static org.drools.util.StringUtils.lcFirstForBean;
import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.THIS_PLACEHOLDER;
import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.createConstraintCompiler;
@@ -196,11 +199,28 @@ public class ConstraintParser {
}
private void addDeclaration(DrlxExpression drlx, SingleDrlxParseSuccess
singleResult, String bindId) {
- DeclarationSpec decl = context.addDeclaration( bindId,
singleResult.getLeftExprTypeBeforeCoercion() );
+ DeclarationSpec decl = context.addDeclaration(bindId,
getDeclarationType(drlx, singleResult));
if (drlx.getExpr() instanceof NameExpr) {
- decl.setBoundVariable( PrintUtil.printNode(drlx.getExpr()) );
+ decl.setBoundVariable(PrintUtil.printNode(drlx.getExpr()));
+ } else if (drlx.getExpr() instanceof EnclosedExpr && drlx.getBind() !=
null) {
+ ExpressionTyperContext expressionTyperContext = new
ExpressionTyperContext();
+ ExpressionTyper expressionTyper = new ExpressionTyper(context,
singleResult.getPatternType(), bindId, false, expressionTyperContext);
+ TypedExpressionResult typedExpressionResult =
expressionTyper.toTypedExpression(drlx.getExpr());
+
singleResult.setBoundExpr(typedExpressionResult.typedExpressionOrException());
} else if (drlx.getExpr() instanceof BinaryExpr) {
-
decl.setBoundVariable(PrintUtil.printNode(drlx.getExpr().asBinaryExpr().getLeft()));
+ Expression leftMostExpression =
getLeftMostExpression(drlx.getExpr().asBinaryExpr());
+ decl.setBoundVariable(PrintUtil.printNode(leftMostExpression));
+ if (singleResult.getExpr() instanceof MethodCallExpr) {
+ // BinaryExpr was converted to MethodCallExpr. Create a
TypedExpression for the leftmost expression of the BinaryExpr
+ ExpressionTyperContext expressionTyperContext = new
ExpressionTyperContext();
+ ExpressionTyper expressionTyper = new ExpressionTyper(context,
singleResult.getPatternType(), bindId, false, expressionTyperContext);
+ TypedExpressionResult leftTypedExpressionResult =
expressionTyper.toTypedExpression(leftMostExpression);
+ Optional<TypedExpression> optLeft =
leftTypedExpressionResult.getTypedExpression();
+ if (optLeft.isEmpty()) {
+ throw new IllegalStateException("Cannot create
TypedExpression for " + drlx.getExpr().asBinaryExpr().getLeft());
+ }
+ singleResult.setBoundExpr(optLeft.get());
+ }
}
decl.setBelongingPatternDescr(context.getCurrentPatternDescr());
singleResult.setExprBinding( bindId );
@@ -210,6 +230,24 @@ public class ConstraintParser {
}
}
+ private static Class<?> getDeclarationType(DrlxExpression drlx,
SingleDrlxParseSuccess singleResult) {
+ if (drlx.getBind() != null && drlx.getExpr() instanceof EnclosedExpr) {
+ // in case of enclosed, bind type should be the calculation result
type
+ // If drlx.getBind() == null, a bind variable is inside the
enclosed expression, leave it to the default behavior
+ return (Class<?>)singleResult.getExprType();
+ } else {
+ return singleResult.getLeftExprTypeBeforeCoercion();
+ }
+ }
+
+ private Expression getLeftMostExpression(BinaryExpr binaryExpr) {
+ Expression left = binaryExpr.getLeft();
+ if (left instanceof BinaryExpr) {
+ return getLeftMostExpression((BinaryExpr) left);
+ }
+ return left;
+ }
+
/*
This is the entry point for Constraint Transformation from a parsed
MVEL constraint
to a Java Expression
@@ -656,17 +694,16 @@ public class ConstraintParser {
Expression combo;
- boolean arithmeticExpr = ARITHMETIC_OPERATORS.contains(operator);
boolean isBetaConstraint = right.getExpression() != null &&
hasDeclarationFromOtherPattern( expressionTyperContext );
boolean requiresSplit = operator == BinaryExpr.Operator.AND &&
binaryExpr.getRight() instanceof HalfBinaryExpr && !isBetaConstraint;
+ Type exprType = isBooleanOperator( operator ) ? boolean.class :
left.getType();
+
if (equalityExpr) {
combo = getEqualityExpression( left, right, operator ).expression;
- } else if (arithmeticExpr && (left.isBigDecimal())) {
- ConstraintCompiler constraintCompiler =
createConstraintCompiler(this.context, of(patternType));
- CompiledExpressionResult compiledExpressionResult =
constraintCompiler.compileExpression(binaryExpr);
-
- combo = compiledExpressionResult.getExpression();
+ } else if (shouldConvertArithmeticBinaryToMethodCall(operator,
left.getType(), right.getType())) {
+ combo = convertArithmeticBinaryToMethodCall(binaryExpr,
of(patternType), this.context);
+ exprType = getBinaryTypeAfterConversion(left.getType(),
right.getType());
} else {
if (left.getExpression() == null || right.getExpression() == null)
{
return new DrlxParseFail(new
ParseExpressionErrorResult(drlxExpr));
@@ -694,7 +731,7 @@ public class ConstraintParser {
constraintType = Index.ConstraintType.FORALL_SELF_JOIN;
}
- return new SingleDrlxParseSuccess(patternType, bindingId, combo,
isBooleanOperator( operator ) ? boolean.class : left.getType())
+ return new SingleDrlxParseSuccess(patternType, bindingId, combo,
exprType)
.setDecodeConstraintType( constraintType )
.setUsedDeclarations(
expressionTyperContext.getUsedDeclarations() )
.setUsedDeclarationsOnLeft( usedDeclarationsOnLeft )
@@ -1007,4 +1044,8 @@ public class ConstraintParser {
}
return Optional.empty();
}
+
+ public static boolean isArithmeticOperator(BinaryExpr.Operator operator) {
+ return ARITHMETIC_OPERATORS.contains(operator);
+ }
}
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/SingleDrlxParseSuccess.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/SingleDrlxParseSuccess.java
index 4e428bc6fa..4c3c0e49d3 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/SingleDrlxParseSuccess.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/SingleDrlxParseSuccess.java
@@ -355,8 +355,26 @@ public class SingleDrlxParseSuccess extends
AbstractDrlxParseSuccess {
return this.isPredicate;
}
+ /*
+ * This method finds out, if the parse result is a predicate enclosed in
parentheses, bound to a variable.
+ * Example: Person($booleanVariable: (name != null))
+ * This shouldn't apply to any other form of predicate. So e.g.
+ * Person($booleanVariable: (name != null) == "someName") should be
properly generated as a constraint.
+ * After discussions, to align the executable model behaviour with the old
non-executable model,
+ * such predicate is not generated as a rule constraint, and just bound to
a variable. This behaviour needs more
+ * discussions to revisit this behaviour.
+ */
+ private boolean isEnclosedPredicateBoundToVariable() {
+ final TypedExpression boundExpr = getBoundExpr();
+ return boundExpr != null
+ && boundExpr.getExpression() instanceof EnclosedExpr
+ && getExprBinding() != null
+ && !getLeft().getExpression().equals(boundExpr.getExpression())
+ &&
!getRight().getExpression().equals(boundExpr.getExpression());
+ }
+
public SingleDrlxParseSuccess setIsPredicate(boolean predicate) {
- this.isPredicate = predicate;
+ this.isPredicate = predicate && !isEnclosedPredicateBoundToVariable();
return this;
}
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expression/AbstractExpressionBuilder.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expression/AbstractExpressionBuilder.java
index c24ce42fec..14e893a16a 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expression/AbstractExpressionBuilder.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expression/AbstractExpressionBuilder.java
@@ -113,8 +113,17 @@ public abstract class AbstractExpressionBuilder {
} else {
final TypedExpression boundExpr = drlxParseResult.getBoundExpr();
// Can we unify it? Sometimes expression is in the left sometimes
in expression
- final Expression e = boundExpr != null ?
findLeftmostExpression(boundExpr.getExpression()) : drlxParseResult.getExpr();
- return buildConstraintExpression(drlxParseResult,
drlxParseResult.getUsedDeclarationsOnLeft(), e);
+ final Expression expression;
+ if (boundExpr != null) {
+ if (boundExpr.getExpression() instanceof EnclosedExpr) {
+ expression = boundExpr.getExpression();
+ } else {
+ expression =
findLeftmostExpression(boundExpr.getExpression());
+ }
+ } else {
+ expression = drlxParseResult.getExpr();
+ }
+ return buildConstraintExpression(drlxParseResult,
drlxParseResult.getUsedDeclarationsOnLeft(), expression);
}
}
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
index eb101f499c..e616ac1c5e 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
@@ -22,6 +22,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.TypeVariable;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -89,6 +90,8 @@ import org.drools.mvel.parser.ast.expr.OOPathChunk;
import org.drools.mvel.parser.ast.expr.OOPathExpr;
import org.drools.mvel.parser.ast.expr.PointFreeExpr;
import org.drools.mvel.parser.printer.PrintUtil;
+import org.drools.mvelcompiler.CompiledExpressionResult;
+import org.drools.mvelcompiler.ConstraintCompiler;
import org.drools.mvelcompiler.util.BigDecimalArgumentCoercion;
import org.drools.util.MethodUtils;
import org.drools.util.TypeResolver;
@@ -99,6 +102,7 @@ import static com.github.javaparser.ast.NodeList.nodeList;
import static java.util.Optional.empty;
import static java.util.Optional.of;
import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.THIS_PLACEHOLDER;
+import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.createConstraintCompiler;
import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.findRootNodeViaParent;
import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.getClassFromContext;
import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.getClassFromType;
@@ -113,6 +117,7 @@ import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toClass
import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toStringLiteral;
import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.transformDrlNameExprToNameExpr;
import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.trasformHalfBinaryToBinary;
+import static
org.drools.model.codegen.execmodel.generator.drlxparse.ConstraintParser.isArithmeticOperator;
import static
org.drools.model.codegen.execmodel.generator.expressiontyper.FlattenScope.flattenScope;
import static
org.drools.model.codegen.execmodel.generator.expressiontyper.FlattenScope.transformFullyQualifiedInlineCastExpr;
import static org.drools.mvel.parser.MvelParser.parseType;
@@ -229,7 +234,14 @@ public class ExpressionTyper {
right = coerced.getCoercedRight();
final BinaryExpr combo = new BinaryExpr(left.getExpression(),
right.getExpression(), operator);
- return of(new TypedExpression(combo, left.getType()));
+
+ if (shouldConvertArithmeticBinaryToMethodCall(operator,
left.getType(), right.getType())) {
+ Expression expression =
convertArithmeticBinaryToMethodCall(combo, of(typeCursor), ruleContext);
+ java.lang.reflect.Type binaryType =
getBinaryTypeAfterConversion(left.getType(), right.getType());
+ return of(new TypedExpression(expression, binaryType));
+ } else {
+ return of(new TypedExpression(combo, left.getType()));
+ }
}
if (drlxExpr instanceof HalfBinaryExpr) {
@@ -800,7 +812,38 @@ public class ExpressionTyper {
TypedExpression rightTypedExpression = right.getTypedExpression()
.orElseThrow(() -> new
NoSuchElementException("TypedExpressionResult doesn't contain
TypedExpression!"));
binaryExpr.setRight(rightTypedExpression.getExpression());
- return new TypedExpressionCursor(binaryExpr,
getBinaryType(leftTypedExpression, rightTypedExpression,
binaryExpr.getOperator()));
+ if
(shouldConvertArithmeticBinaryToMethodCall(binaryExpr.getOperator(),
leftTypedExpression.getType(), rightTypedExpression.getType())) {
+ Expression compiledExpression =
convertArithmeticBinaryToMethodCall(binaryExpr,
leftTypedExpression.getOriginalPatternType(), ruleContext);
+ java.lang.reflect.Type binaryType =
getBinaryTypeAfterConversion(leftTypedExpression.getType(),
rightTypedExpression.getType());
+ return new TypedExpressionCursor(compiledExpression, binaryType);
+ } else {
+ java.lang.reflect.Type binaryType =
getBinaryType(leftTypedExpression, rightTypedExpression,
binaryExpr.getOperator());
+ return new TypedExpressionCursor(binaryExpr, binaryType);
+ }
+ }
+
+ /*
+ * Converts arithmetic binary expression (including coercion) to method
call using ConstraintCompiler.
+ * This method can be generic, so we may centralize the calls in
drools-model
+ */
+ public static Expression convertArithmeticBinaryToMethodCall(BinaryExpr
binaryExpr, Optional<Class<?>> originalPatternType, RuleContext ruleContext) {
+ ConstraintCompiler constraintCompiler =
createConstraintCompiler(ruleContext, originalPatternType);
+ CompiledExpressionResult compiledExpressionResult =
constraintCompiler.compileExpression(printNode(binaryExpr));
+ return compiledExpressionResult.getExpression();
+ }
+
+ /*
+ * BigDecimal arithmetic operations should be converted to method calls.
We may also apply this to BigInteger.
+ */
+ public static boolean
shouldConvertArithmeticBinaryToMethodCall(BinaryExpr.Operator operator,
java.lang.reflect.Type leftType, java.lang.reflect.Type rightType) {
+ return isArithmeticOperator(operator) &&
(leftType.equals(BigDecimal.class) || rightType.equals(BigDecimal.class));
+ }
+
+ /*
+ * After arithmetic to method call conversion, BigDecimal should take
precedence regardless of left or right. We may also apply this to BigInteger.
+ */
+ public static java.lang.reflect.Type
getBinaryTypeAfterConversion(java.lang.reflect.Type leftType,
java.lang.reflect.Type rightType) {
+ return (leftType.equals(BigDecimal.class) ||
rightType.equals(BigDecimal.class)) ? BigDecimal.class : leftType;
}
private java.lang.reflect.Type getBinaryType(TypedExpression
leftTypedExpression, TypedExpression rightTypedExpression, Operator operator) {
@@ -907,6 +950,9 @@ public class ExpressionTyper {
Expression argumentExpression = methodCallExpr.getArgument(i);
if (argumentType != actualArgumentType) {
+ // unbind the original argumentExpression first, otherwise
setArgument() will remove the argumentExpression from
coercedExpression.childrenNodes
+ // It will result in failing to find DrlNameExpr in AST at
DrlsParseUtil.transformDrlNameExprToNameExpr()
+ methodCallExpr.replace(argumentExpression, new
NameExpr("placeholder"));
Expression coercedExpression = new
BigDecimalArgumentCoercion().coercedArgument(argumentType, actualArgumentType,
argumentExpression);
methodCallExpr.setArgument(i, coercedExpression);
}
diff --git
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/BindingTest.java
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/BindingTest.java
index 0477ec5c43..1480953466 100644
---
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/BindingTest.java
+++
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/BindingTest.java
@@ -471,4 +471,69 @@ public class BindingTest extends BaseModelTest {
ksession.fireAllRules();
assertThat(result).isEmpty();
}
+
+ @Test
+ public void testConstraintExpression() {
+ String str = "package constraintexpression\n" +
+ "\n" +
+ "import " + Person.class.getCanonicalName() + "\n" +
+ "import java.util.List; \n" +
+ "global List<Boolean> booleanListGlobal; \n" +
+ "rule \"r1\"\n" +
+ "when \n" +
+ " $p : Person($booleanVariable: (name != null))\n" +
+ "then \n" +
+ " System.out.println($booleanVariable); \n" +
+ " System.out.println($p); \n" +
+ " booleanListGlobal.add($booleanVariable); \n " +
+ "end \n";
+
+ KieSession ksession = getKieSession(str);
+ try {
+ final List<Boolean> booleanListGlobal = new ArrayList<>();
+ ksession.setGlobal("booleanListGlobal", booleanListGlobal);
+ Person person = new Person("someName");
+ ksession.insert(person);
+ int rulesFired = ksession.fireAllRules();
+ assertThat(rulesFired).isEqualTo(1);
+
assertThat(booleanListGlobal).isNotEmpty().containsExactly(Boolean.TRUE);
+ } finally {
+ ksession.dispose();
+ }
+ }
+
+ /**
+ * This test checks that a rule is not fired, when a binding is
+ * enclosed in parentheses. This is intentional behaviour, agreed in
discussions,
+ * which may be revised in the future.
+ */
+ @Test
+ public void testIgnoreConstraintInParentheses() {
+ String str = "package constraintexpression\n" +
+ "\n" +
+ "import " + Person.class.getCanonicalName() + "\n" +
+ "import java.util.List; \n" +
+ "global List<Boolean> booleanListGlobal; \n" +
+ "rule \"r1\"\n" +
+ "when \n" +
+ " $p : Person($booleanVariable: (name == null))\n" +
+ "then \n" +
+ " System.out.println($booleanVariable); \n" +
+ " System.out.println($p); \n" +
+ " booleanListGlobal.add($booleanVariable); \n " +
+ "end \n";
+
+ KieSession ksession = getKieSession(str);
+ try {
+ final List<Boolean> booleanListGlobal = new ArrayList<>();
+ ksession.setGlobal("booleanListGlobal", booleanListGlobal);
+ Person person = new Person("someName");
+ ksession.insert(person);
+ int rulesFired = ksession.fireAllRules();
+ assertThat(rulesFired).isEqualTo(1);
+
assertThat(booleanListGlobal).isNotEmpty().containsExactly(Boolean.FALSE);
+ } finally {
+ ksession.dispose();
+ }
+ }
}
diff --git
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/bigdecimaltest/BDFact.java
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/bigdecimaltest/BDFact.java
new file mode 100644
index 0000000000..de9721e8bc
--- /dev/null
+++
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/bigdecimaltest/BDFact.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.drools.model.codegen.execmodel.bigdecimaltest;
+
+import java.math.BigDecimal;
+
+public class BDFact {
+
+ private BigDecimal value1;
+ private BigDecimal value2;
+
+ public BigDecimal getValue1() {
+ return value1;
+ }
+
+ public void setValue1(BigDecimal value1) {
+ this.value1 = value1;
+ }
+
+ public BigDecimal getValue2() {
+ return value2;
+ }
+
+ public void setValue2(BigDecimal value2) {
+ this.value2 = value2;
+ }
+}
diff --git
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/bigdecimaltest/BigDecimalTest.java
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/bigdecimaltest/BigDecimalTest.java
index 50655e281c..5ff7510398 100644
---
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/bigdecimaltest/BigDecimalTest.java
+++
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/bigdecimaltest/BigDecimalTest.java
@@ -720,4 +720,96 @@ public class BigDecimalTest extends BaseModelTest {
// BigDecimal("1.0") and BigDecimal("1.00") are considered as equal
because exec-model uses EvaluationUtil.equals() which is based on compareTo()
assertThat(result).contains(new BigDecimal("1.00"));
}
+
+ @Test
+ public void bigDecimalCoercionInMethodArgument_shouldNotFailToBuild() {
+ // KIE-748
+ String str =
+ "package org.drools.modelcompiler.bigdecimals\n" +
+ "import " + BDFact.class.getCanonicalName() + ";\n" +
+ "import static " +
BigDecimalTest.class.getCanonicalName() + ".intToString;\n" +
+ "rule \"Rule 1a\"\n" +
+ " when\n" +
+ " BDFact( intToString(value2 - 1) == \"2\" )\n"
+
+ " then\n" +
+ "end";
+
+ KieSession ksession = getKieSession(str);
+
+ BDFact bdFact = new BDFact();
+ bdFact.setValue2(new BigDecimal("3"));
+
+ ksession.insert(bdFact);
+
+ assertThat(ksession.fireAllRules()).isEqualTo(1);
+ }
+
+ @Test
+ public void
bigDecimalCoercionInNestedMethodArgument_shouldNotFailToBuild() {
+ // KIE-748
+ String str =
+ "package org.drools.modelcompiler.bigdecimals\n" +
+ "import " + BDFact.class.getCanonicalName() + ";\n" +
+ "import static " +
BigDecimalTest.class.getCanonicalName() + ".intToString;\n" +
+ "rule \"Rule 1a\"\n" +
+ " when\n" +
+ " BDFact( intToString(value1 * (value2 - 1)) ==
\"20\" )\n" +
+ " then\n" +
+ "end";
+
+ KieSession ksession = getKieSession(str);
+
+ BDFact bdFact = new BDFact();
+ bdFact.setValue1(new BigDecimal("10"));
+ bdFact.setValue2(new BigDecimal("3"));
+
+ ksession.insert(bdFact);
+
+ assertThat(ksession.fireAllRules()).isEqualTo(1);
+ }
+
+ public static String intToString(int value) {
+ return Integer.toString(value);
+ }
+
+ @Test
+ public void
bindVariableToBigDecimalCoercion2Operands_shouldBindCorrectResult() {
+ bindVariableToBigDecimalCoercion("$var : (1000 * value1)");
+ }
+
+ @Test
+ public void
bindVariableToBigDecimalCoercion3Operands_shouldBindCorrectResult() {
+ bindVariableToBigDecimalCoercion("$var : (100000 * value1 / 100)");
+ }
+
+ @Test
+ public void
bindVariableToBigDecimalCoercion3OperandsWithParentheses_shouldBindCorrectResult()
{
+ bindVariableToBigDecimalCoercion("$var : ((100000 * value1) / 100)");
+ }
+
+ private void bindVariableToBigDecimalCoercion(String binding) {
+ // KIE-775
+ String str =
+ "package org.drools.modelcompiler.bigdecimals\n" +
+ "import " + BDFact.class.getCanonicalName() + ";\n" +
+ "global java.util.List result;\n" +
+ "rule R1\n" +
+ " when\n" +
+ " BDFact( " + binding + " )\n" +
+ " then\n" +
+ " result.add($var);\n" +
+ "end";
+
+ KieSession ksession = getKieSession(str);
+ List<BigDecimal> result = new ArrayList<>();
+ ksession.setGlobal("result", result);
+
+ BDFact bdFact = new BDFact();
+ bdFact.setValue1(new BigDecimal("80"));
+
+ ksession.insert(bdFact);
+ ksession.fireAllRules();
+
+ assertThat(result).contains(new BigDecimal("80000"));
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]