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]