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

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


The following commit(s) were added to refs/heads/main by this push:
     new 76ea593a95 [KIE-748] drools executable-model fails with BigDecimal 
coercion for … (#5618)
76ea593a95 is described below

commit 76ea593a955d44c0b4e7c12156f54041b2969edf
Author: Toshiya Kobayashi <[email protected]>
AuthorDate: Mon Dec 11 22:08:11 2023 +0900

    [KIE-748] drools executable-model fails with BigDecimal coercion for … 
(#5618)
    
    * [KIE-748] drools executable-model fails with BigDecimal coercion for 
method arguments
    
    * refactor
---
 .../generator/drlxparse/ConstraintParser.java      |  8 +++-
 .../generator/expressiontyper/ExpressionTyper.java | 30 ++++++++++++-
 .../codegen/execmodel/bigdecimaltest/BDFact.java   | 43 ++++++++++++++++++
 .../execmodel/bigdecimaltest/BigDecimalTest.java   | 51 ++++++++++++++++++++++
 .../execmodel/generator/ExpressionTyperTest.java   |  8 ++++
 5 files changed, 137 insertions(+), 3 deletions(-)

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 50f95366c1..2a85da6e2f 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
@@ -657,7 +657,7 @@ public class ConstraintParser {
 
         Expression combo;
 
-        boolean arithmeticExpr = ARITHMETIC_OPERATORS.contains(operator);
+        boolean arithmeticExpr = isArithmeticOperator(operator);
         boolean isBetaConstraint = right.getExpression() != null && 
hasDeclarationFromOtherPattern( expressionTyperContext );
         boolean requiresSplit = operator == BinaryExpr.Operator.AND && 
binaryExpr.getRight() instanceof HalfBinaryExpr && !isBetaConstraint;
 
@@ -981,7 +981,7 @@ public class ConstraintParser {
         List<BinaryExpr> binaryExprList = 
methodCallExpr.findAll(BinaryExpr.class);
         for (BinaryExpr binaryExpr : binaryExprList) {
             Operator operator = binaryExpr.getOperator();
-            boolean arithmeticExpr = ARITHMETIC_OPERATORS.contains(operator);
+            boolean arithmeticExpr = isArithmeticOperator(operator);
             if (arithmeticExpr) {
                 final ExpressionTyperContext expressionTyperContext = new 
ExpressionTyperContext();
                 final ExpressionTyper expressionTyper = new 
ExpressionTyper(context, patternType, bindingId, isPositional, 
expressionTyperContext);
@@ -1008,4 +1008,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/expressiontyper/ExpressionTyper.java
 
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
index 9b5dd94561..328aa5466e 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
@@ -23,6 +23,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;
@@ -90,6 +91,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;
@@ -100,6 +103,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;
@@ -114,6 +118,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;
@@ -801,7 +806,30 @@ 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()));
+        java.lang.reflect.Type binaryType = getBinaryType(leftTypedExpression, 
rightTypedExpression, binaryExpr.getOperator());
+        if 
(shouldConvertArithmeticBinaryToMethodCall(binaryExpr.getOperator(), 
binaryType)) {
+            Expression compiledExpression = 
convertArithmeticBinaryToMethodCall(binaryExpr, 
leftTypedExpression.getOriginalPatternType(), ruleContext);
+            return new TypedExpressionCursor(compiledExpression, binaryType);
+        } else {
+            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
+     */
+    private 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.
+     */
+    private static boolean 
shouldConvertArithmeticBinaryToMethodCall(BinaryExpr.Operator operator, 
java.lang.reflect.Type type) {
+        return isArithmeticOperator(operator) && type.equals(BigDecimal.class);
     }
 
     private java.lang.reflect.Type getBinaryType(TypedExpression 
leftTypedExpression, TypedExpression rightTypedExpression, Operator operator) {
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 bdc842a2d1..0cc90ca317 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
@@ -721,4 +721,55 @@ 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);
+    }
 }
diff --git 
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java
 
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java
index f8ad08e854..29a0e20a66 100644
--- 
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java
+++ 
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java
@@ -266,6 +266,14 @@ public class ExpressionTyperTest {
         
assertThat(typedExpression.getExpression().toString()).isEqualTo(expected);
     }
 
+    @Test
+    public void coercionInMethodArgument() {
+        TypedExpression typedExpression = 
toTypedExpression("identityBigDecimal(money - 1)", Person.class);
+        assertThat(ruleContext.hasCompilationError()).isFalse();
+        String expected = 
"_this.identityBigDecimal(_this.getMoney().subtract(new 
java.math.BigDecimal(1), java.math.MathContext.DECIMAL128))";
+        
assertThat(typedExpression.getExpression().toString()).isEqualTo(expected);
+    }
+
     private TypedExpression toTypedExpression(String inputExpression, Class<?> 
patternType, DeclarationSpec... declarations) {
 
         for(DeclarationSpec d : declarations) {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to