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]

Reply via email to