This is an automated email from the ASF dual-hosted git repository.
tzimanyi 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 30b4961cab [kie-issues#745] Handle lists and maps in method calls and
constructors in drools-mvel-compiler (#5617)
30b4961cab is described below
commit 30b4961cabc8549426c54df8be9e9e96df69bdcb
Author: Tibor Zimányi <[email protected]>
AuthorDate: Fri Dec 15 15:05:17 2023 +0100
[kie-issues#745] Handle lists and maps in method calls and constructors in
drools-mvel-compiler (#5617)
---
.../drools/mvelcompiler/MethodCallExprVisitor.java | 92 +++----
.../java/org/drools/mvelcompiler/RHSPhase.java | 116 ++++----
.../org/drools/mvelcompiler/ast/ListExprT.java | 47 ++++
.../java/org/drools/mvelcompiler/ast/MapExprT.java | 53 ++++
.../drools/mvelcompiler/ast/MethodCallExprT.java | 2 +-
.../mvelcompiler/util/MethodResolutionUtils.java | 224 +++++++++++++++
.../drools/mvelcompiler/util/VisitorContext.java | 24 ++
.../src/test/java/org/drools/Person.java | 21 ++
.../util/MethodResolutionUtilsTest.java | 303 +++++++++++++++++++++
.../mvel/parser/ast/visitor/DrlGenericVisitor.java | 8 +-
.../integrationtests/MVELEmptyCollectionsTest.java | 167 ++++++++++++
.../org/drools/mvel/integrationtests/MVELTest.java | 2 +
.../mvel/integrationtests/facts/FactWithList.java | 4 +
.../facts/{FactWithList.java => FactWithMap.java} | 26 +-
.../{FactWithList.java => FactWithObject.java} | 21 +-
15 files changed, 972 insertions(+), 138 deletions(-)
diff --git
a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/MethodCallExprVisitor.java
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/MethodCallExprVisitor.java
index 4d0b38ed08..ab007da941 100644
---
a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/MethodCallExprVisitor.java
+++
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/MethodCallExprVisitor.java
@@ -18,28 +18,32 @@
*/
package org.drools.mvelcompiler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.MethodCallExpr;
-import org.drools.util.MethodUtils;
+import com.github.javaparser.utils.Pair;
+import org.drools.mvel.parser.ast.expr.ListCreationLiteralExpression;
+import org.drools.mvel.parser.ast.expr.MapCreationLiteralExpression;
import org.drools.mvel.parser.ast.visitor.DrlGenericVisitor;
import org.drools.mvelcompiler.ast.MethodCallExprT;
import org.drools.mvelcompiler.ast.TypedExpression;
import org.drools.mvelcompiler.context.DeclaredFunction;
import org.drools.mvelcompiler.context.MvelCompilerContext;
-import org.drools.util.ClassUtils;
+import org.drools.mvelcompiler.util.MethodResolutionUtils;
+import org.drools.mvelcompiler.util.VisitorContext;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
import static org.drools.util.StreamUtils.optionalToStream;
-public class MethodCallExprVisitor implements
DrlGenericVisitor<TypedExpression, RHSPhase.Context> {
+public class MethodCallExprVisitor implements
DrlGenericVisitor<TypedExpression, VisitorContext> {
final RHSPhase parentVisitor;
final MvelCompilerContext mvelCompilerContext;
@@ -50,24 +54,18 @@ public class MethodCallExprVisitor implements
DrlGenericVisitor<TypedExpression,
}
@Override
- public TypedExpression defaultMethod(Node n, RHSPhase.Context context) {
+ public TypedExpression defaultMethod(Node n, VisitorContext context) {
return n.accept(parentVisitor, context);
}
@Override
- public TypedExpression visit(MethodCallExpr n, RHSPhase.Context arg) {
- Optional<TypedExpression> scope = n.getScope().map(s -> s.accept(this,
arg));
- TypedExpression name = n.getName().accept(this, new
RHSPhase.Context(scope.orElse(null)));
- final List<TypedExpression> arguments = new
ArrayList<>(n.getArguments().size());
- for (Expression child : n.getArguments()) {
- TypedExpression a = child.accept(this, arg);
- arguments.add(a);
- }
-
- Class<?>[] argumentsTypes = parametersType(arguments);
-
- return parseMethodFromDeclaredFunction(n, arguments)
- .orElseGet(() -> parseMethod(n, scope, name, arguments,
argumentsTypes));
+ public TypedExpression visit(final MethodCallExpr n, final VisitorContext
arg) {
+ final Optional<TypedExpression> scope = n.getScope().map(s ->
s.accept(this, arg));
+ final TypedExpression name = n.getName().accept(this, new
VisitorContext(scope.orElse(null)));
+ final Pair<List<TypedExpression>, List<Integer>> typedArgumentsResult =
+
MethodResolutionUtils.getTypedArgumentsWithEmptyCollectionArgumentDetection(n.getArguments(),
this, arg);
+ return parseMethodFromDeclaredFunction(n, typedArgumentsResult.a)
+ .orElseGet(() -> parseMethod(n, scope, name,
typedArgumentsResult.a, typedArgumentsResult.b));
}
private Optional<TypedExpression>
parseMethodFromDeclaredFunction(MethodCallExpr n, List<TypedExpression>
arguments) {
@@ -89,43 +87,21 @@ public class MethodCallExprVisitor implements
DrlGenericVisitor<TypedExpression,
Optional<TypedExpression> scope,
TypedExpression name,
List<TypedExpression> arguments,
- Class<?>[] argumentsType) {
- Optional<Method> method = scope.flatMap(TypedExpression::getType)
- .<Class<?>>map(ClassUtils::classFromType)
- .map(scopeClazz -> MethodUtils.findMethod(scopeClazz,
n.getNameAsString(), argumentsType));
-
- if (method.isEmpty()) {
- method = mvelCompilerContext.getRootPattern()
- .map(scopeClazz -> MethodUtils.findMethod(scopeClazz,
n.getNameAsString(), argumentsType));
- if(method.isPresent()) {
- scope = mvelCompilerContext.createRootTypePrefix();
- }
+ List<Integer>
emptyCollectionArgumentIndexes) {
+ Pair<Optional<Method>, Optional<TypedExpression>> resolveMethodResult =
+ MethodResolutionUtils.resolveMethod(n, mvelCompilerContext,
scope, arguments);
+ // This is a workaround for mvel empty list and map ambiguity, please
see the description in getTypedArguments() method.
+ if (resolveMethodResult.a.isEmpty() &&
!emptyCollectionArgumentIndexes.isEmpty()) {
+ resolveMethodResult =
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(n,
mvelCompilerContext, resolveMethodResult.b, arguments,
emptyCollectionArgumentIndexes);
}
-
- if (method.isEmpty()) {
- method = mvelCompilerContext.findStaticMethod(n.getNameAsString());
- }
-
- Optional<Method> finalMethod = method;
- Optional<Type> methodReturnType =
- name.getType()
- .map(Optional::of)
- .orElseGet(() ->
finalMethod.map(Method::getReturnType));
-
- List<Class<?>> actualArgumentType = optionalToStream(method)
+ final Optional<Method> finalMethod = resolveMethodResult.a;
+ final Optional<TypedExpression> finalScope = resolveMethodResult.b;
+ final Optional<Type> methodReturnType = name.getType().or(() ->
finalMethod.map(Method::getReturnType));
+ final List<Class<?>> actualArgumentType = optionalToStream(finalMethod)
.flatMap((Method m) -> Arrays.stream(m.getParameterTypes()))
.collect(Collectors.toList());
- return new MethodCallExprT(n.getName().asString(), scope, arguments,
+ return new MethodCallExprT(n.getName().asString(), finalScope,
arguments,
actualArgumentType, methodReturnType);
}
-
- private Class<?>[] parametersType(List<TypedExpression> arguments) {
- return arguments.stream()
- .map(TypedExpression::getType)
- .filter(Optional::isPresent)
- .map(Optional::get)
- .map(ClassUtils::classFromType)
- .toArray(Class[]::new);
- }
}
diff --git
a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/RHSPhase.java
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/RHSPhase.java
index d85917abc3..533fab5680 100644
---
a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/RHSPhase.java
+++
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/RHSPhase.java
@@ -52,9 +52,13 @@ import com.github.javaparser.ast.expr.UnaryExpr;
import com.github.javaparser.ast.expr.VariableDeclarationExpr;
import com.github.javaparser.ast.stmt.ExpressionStmt;
import com.github.javaparser.ast.stmt.YieldStmt;
+import com.github.javaparser.utils.Pair;
import org.drools.mvel.parser.ast.expr.BigDecimalLiteralExpr;
import org.drools.mvel.parser.ast.expr.BigIntegerLiteralExpr;
import org.drools.mvel.parser.ast.expr.DrlNameExpr;
+import org.drools.mvel.parser.ast.expr.ListCreationLiteralExpression;
+import org.drools.mvel.parser.ast.expr.ListCreationLiteralExpressionElement;
+import org.drools.mvel.parser.ast.expr.MapCreationLiteralExpression;
import org.drools.mvel.parser.ast.visitor.DrlGenericVisitor;
import org.drools.mvelcompiler.ast.BigDecimalArithmeticExprT;
import org.drools.mvelcompiler.ast.BigDecimalConvertedExprT;
@@ -69,7 +73,9 @@ import org.drools.mvelcompiler.ast.FieldAccessTExpr;
import org.drools.mvelcompiler.ast.FieldToAccessorTExpr;
import org.drools.mvelcompiler.ast.IntegerLiteralExpressionT;
import org.drools.mvelcompiler.ast.ListAccessExprT;
+import org.drools.mvelcompiler.ast.ListExprT;
import org.drools.mvelcompiler.ast.LongLiteralExpressionT;
+import org.drools.mvelcompiler.ast.MapExprT;
import org.drools.mvelcompiler.ast.ObjectCreationExpressionT;
import org.drools.mvelcompiler.ast.SimpleNameTExpr;
import org.drools.mvelcompiler.ast.StringLiteralExpressionT;
@@ -77,6 +83,8 @@ import org.drools.mvelcompiler.ast.TypedExpression;
import org.drools.mvelcompiler.ast.UnalteredTypedExpression;
import org.drools.mvelcompiler.context.Declaration;
import org.drools.mvelcompiler.context.MvelCompilerContext;
+import org.drools.mvelcompiler.util.MethodResolutionUtils;
+import org.drools.mvelcompiler.util.VisitorContext;
import org.drools.util.ClassUtils;
import org.drools.util.MethodUtils.NullType;
@@ -100,7 +108,7 @@ import static org.drools.util.ClassUtils.getAccessor;
* might need to create new variables accordingly.
*
*/
-public class RHSPhase implements DrlGenericVisitor<TypedExpression,
RHSPhase.Context> {
+public class RHSPhase implements DrlGenericVisitor<TypedExpression,
VisitorContext> {
private static final Set<BinaryExpr.Operator> arithmeticOperators = Set.of(
BinaryExpr.Operator.PLUS,
@@ -121,18 +129,6 @@ public class RHSPhase implements
DrlGenericVisitor<TypedExpression, RHSPhase.Con
private final MethodCallExprVisitor methodCallExprVisitor;
- static class Context {
- final Optional<TypedExpression> scope;
-
- Context(TypedExpression scope) {
- this.scope = ofNullable(scope);
- }
-
- Optional<Type> getScopeType() {
- return scope.flatMap(TypedExpression::getType);
- }
- }
-
private final MvelCompilerContext mvelCompilerContext;
RHSPhase(MvelCompilerContext mvelCompilerContext) {
@@ -141,19 +137,19 @@ public class RHSPhase implements
DrlGenericVisitor<TypedExpression, RHSPhase.Con
}
public TypedExpression invoke(Node statement) {
- Context ctx = new Context(null);
+ VisitorContext ctx = new VisitorContext(null);
return statement.accept(this, ctx);
}
@Override
- public TypedExpression visit(DrlNameExpr n, Context arg) {
+ public TypedExpression visit(DrlNameExpr n, VisitorContext arg) {
return n.getName().accept(this, arg);
}
@Override
- public TypedExpression visit(SimpleName n, Context arg) {
- if (arg.scope.isEmpty()) { // first node
+ public TypedExpression visit(SimpleName n, VisitorContext arg) {
+ if (arg.getScope().isEmpty()) { // first node
return simpleNameAsFirstNode(n);
} else {
return simpleNameAsField(n, arg);
@@ -161,17 +157,17 @@ public class RHSPhase implements
DrlGenericVisitor<TypedExpression, RHSPhase.Con
}
@Override
- public TypedExpression visit(YieldStmt n, Context arg) {
+ public TypedExpression visit(YieldStmt n, VisitorContext arg) {
return null;
}
@Override
- public TypedExpression visit(TextBlockLiteralExpr n, Context arg) {
+ public TypedExpression visit(TextBlockLiteralExpr n, VisitorContext arg) {
return new UnalteredTypedExpression(n, String.class);
}
@Override
- public TypedExpression visit(PatternExpr n, Context arg) {
+ public TypedExpression visit(PatternExpr n, VisitorContext arg) {
return null;
}
@@ -184,15 +180,15 @@ public class RHSPhase implements
DrlGenericVisitor<TypedExpression, RHSPhase.Con
.orElseGet(() -> new UnalteredTypedExpression(n));
}
- private TypedExpression simpleNameAsField(SimpleName n, Context arg) {
+ private TypedExpression simpleNameAsField(SimpleName n, VisitorContext
arg) {
return asPropertyAccessor(n, arg)
.map(Optional::of)
.orElseGet(() -> asFieldAccessTExpr(n, arg))
.orElseGet(() -> new UnalteredTypedExpression(n));
}
- private Optional<TypedExpression> asFieldAccessTExpr(SimpleName n, Context
arg) {
- Optional<TypedExpression> lastTypedExpression = arg.scope;
+ private Optional<TypedExpression> asFieldAccessTExpr(SimpleName n,
VisitorContext arg) {
+ Optional<TypedExpression> lastTypedExpression = arg.getScope();
Optional<Type> scopeType = arg.getScopeType();
Optional<Field> fieldType = scopeType.flatMap(te -> {
@@ -217,8 +213,8 @@ public class RHSPhase implements
DrlGenericVisitor<TypedExpression, RHSPhase.Con
return enumType.map(clazz -> new SimpleNameTExpr(n.asString(), clazz));
}
- private Optional<TypedExpression> asPropertyAccessor(SimpleName n, Context
arg) {
- Optional<TypedExpression> lastTypedExpression = arg.scope;
+ private Optional<TypedExpression> asPropertyAccessor(SimpleName n,
VisitorContext arg) {
+ Optional<TypedExpression> lastTypedExpression = arg.getScope();
Optional<Type> scopeType =
lastTypedExpression.filter(ListAccessExprT.class::isInstance)
.map(ListAccessExprT.class::cast)
@@ -238,18 +234,18 @@ public class RHSPhase implements
DrlGenericVisitor<TypedExpression, RHSPhase.Con
}
@Override
- public TypedExpression visit(FieldAccessExpr n, Context arg) {
+ public TypedExpression visit(FieldAccessExpr n, VisitorContext arg) {
TypedExpression scope = n.getScope().accept(this, arg);
- return n.getName().accept(this, new Context(scope));
+ return n.getName().accept(this, new VisitorContext(scope));
}
@Override
- public TypedExpression visit(MethodCallExpr n, Context arg) {
+ public TypedExpression visit(MethodCallExpr n, VisitorContext arg) {
return n.accept(methodCallExprVisitor, arg);
}
@Override
- public TypedExpression visit(BinaryExpr n, Context arg) {
+ public TypedExpression visit(BinaryExpr n, VisitorContext arg) {
TypedExpression left = n.getLeft().accept(this, arg);
TypedExpression right = n.getRight().accept(this, arg);
return withPossiblyBigDecimalConversion(left, right, n.getOperator());
@@ -303,78 +299,82 @@ public class RHSPhase implements
DrlGenericVisitor<TypedExpression, RHSPhase.Con
}
@Override
- public TypedExpression visit(ExpressionStmt n, Context arg) {
+ public TypedExpression visit(ExpressionStmt n, VisitorContext arg) {
return n.getExpression().accept(this, arg);
}
@Override
- public TypedExpression visit(VariableDeclarationExpr n, Context arg) {
+ public TypedExpression visit(VariableDeclarationExpr n, VisitorContext
arg) {
return n.getVariables().iterator().next().accept(this, arg);
}
@Override
- public TypedExpression visit(VariableDeclarator n, Context arg) {
+ public TypedExpression visit(VariableDeclarator n, VisitorContext arg) {
Optional<TypedExpression> initExpression = n.getInitializer().map(i ->
i.accept(this, arg));
return initExpression.orElse(null);
}
@Override
- public TypedExpression visit(AssignExpr n, Context arg) {
+ public TypedExpression visit(AssignExpr n, VisitorContext arg) {
return n.getValue().accept(this, arg);
}
@Override
- public TypedExpression visit(StringLiteralExpr n, Context arg) {
+ public TypedExpression visit(StringLiteralExpr n, VisitorContext arg) {
return new StringLiteralExpressionT(n);
}
@Override
- public TypedExpression visit(IntegerLiteralExpr n, Context arg) {
+ public TypedExpression visit(IntegerLiteralExpr n, VisitorContext arg) {
return new IntegerLiteralExpressionT(n);
}
@Override
- public TypedExpression visit(DoubleLiteralExpr n, Context arg) {
+ public TypedExpression visit(DoubleLiteralExpr n, VisitorContext arg) {
return new DoubleLiteralExpressionT(n);
}
@Override
- public TypedExpression visit(CharLiteralExpr n, Context arg) {
+ public TypedExpression visit(CharLiteralExpr n, VisitorContext arg) {
return new CharacterLiteralExpressionT(n);
}
@Override
- public TypedExpression visit(LongLiteralExpr n, Context arg) {
+ public TypedExpression visit(LongLiteralExpr n, VisitorContext arg) {
return new LongLiteralExpressionT(n);
}
@Override
- public TypedExpression visit(BooleanLiteralExpr n, Context arg) {
+ public TypedExpression visit(BooleanLiteralExpr n, VisitorContext arg) {
return new BooleanLiteralExpressionT(n);
}
@Override
- public TypedExpression defaultMethod(Node n, Context context) {
+ public TypedExpression defaultMethod(Node n, VisitorContext context) {
return new UnalteredTypedExpression(n);
}
@Override
- public TypedExpression visit(ObjectCreationExpr n, Context arg) {
- List<TypedExpression> constructorArguments = new ArrayList<>();
- for(Expression e : n.getArguments()) {
- TypedExpression compiledArgument = e.accept(this, arg);
- constructorArguments.add(compiledArgument);
+ public TypedExpression visit(ObjectCreationExpr n, VisitorContext arg) {
+ final Class<?> type = resolveType(n.getType());
+ final Pair<List<TypedExpression>, List<Integer>> typedArgumentsResult =
+
MethodResolutionUtils.getTypedArgumentsWithEmptyCollectionArgumentDetection(n.getArguments(),
this, arg);
+ if (!typedArgumentsResult.b.isEmpty()) {
+ return new ObjectCreationExpressionT(
+
MethodResolutionUtils.coerceCorrectConstructorArguments(type,
typedArgumentsResult.a, typedArgumentsResult.b),
+ type);
+ } else {
+ return new ObjectCreationExpressionT(typedArgumentsResult.a, type);
}
- return new ObjectCreationExpressionT(constructorArguments,
resolveType(n.getType()));
}
@Override
- public TypedExpression visit(NullLiteralExpr n, Context arg) {
+ public TypedExpression visit(NullLiteralExpr n, VisitorContext arg) {
return new UnalteredTypedExpression(n, NullType.class);
}
@Override
- public TypedExpression visit(ArrayAccessExpr n, Context arg) {
+ public TypedExpression visit(ArrayAccessExpr n, VisitorContext arg) {
TypedExpression name = n.getName().accept(this, arg);
Optional<Type> type = name.getType();
@@ -385,28 +385,28 @@ public class RHSPhase implements
DrlGenericVisitor<TypedExpression, RHSPhase.Con
}
@Override
- public TypedExpression visit(EnclosedExpr n, Context arg) {
+ public TypedExpression visit(EnclosedExpr n, VisitorContext arg) {
return n.getInner().accept(this, arg);
}
@Override
- public TypedExpression visit(CastExpr n, Context arg) {
+ public TypedExpression visit(CastExpr n, VisitorContext arg) {
TypedExpression innerExpr = n.getExpression().accept(this, arg);
return new CastExprT(innerExpr, resolveType(n.getType()));
}
@Override
- public TypedExpression visit(BigDecimalLiteralExpr n, Context arg) {
+ public TypedExpression visit(BigDecimalLiteralExpr n, VisitorContext arg) {
return new BigDecimalConvertedExprT(new StringLiteralExpressionT(new
StringLiteralExpr(n.getValue())));
}
@Override
- public TypedExpression visit(BigIntegerLiteralExpr n, Context arg) {
+ public TypedExpression visit(BigIntegerLiteralExpr n, VisitorContext arg) {
return new BigIntegerConvertedExprT(new StringLiteralExpressionT(new
StringLiteralExpr(n.getValue())));
}
@Override
- public TypedExpression visit(UnaryExpr n, Context arg) {
+ public TypedExpression visit(UnaryExpr n, VisitorContext arg) {
Expression innerExpr = n.getExpression();
UnaryExpr.Operator operator = n.getOperator();
if (innerExpr instanceof BigDecimalLiteralExpr && operator ==
UnaryExpr.Operator.MINUS) {
@@ -418,6 +418,16 @@ public class RHSPhase implements
DrlGenericVisitor<TypedExpression, RHSPhase.Con
}
}
+ @Override
+ public TypedExpression visit(ListCreationLiteralExpression n,
VisitorContext arg) {
+ return new ListExprT(n);
+ }
+
+ @Override
+ public TypedExpression visit(MapCreationLiteralExpression n,
VisitorContext arg) {
+ return new MapExprT(n);
+ }
+
private Class<?> resolveType(com.github.javaparser.ast.type.Type type) {
return mvelCompilerContext.resolveType(type.asString());
}
diff --git
a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/ListExprT.java
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/ListExprT.java
new file mode 100644
index 0000000000..3b9d8a56f3
--- /dev/null
+++
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/ListExprT.java
@@ -0,0 +1,47 @@
+package org.drools.mvelcompiler.ast;
+
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.NameExpr;
+import org.drools.mvel.parser.ast.expr.ListCreationLiteralExpression;
+import org.drools.mvel.parser.ast.expr.ListCreationLiteralExpressionElement;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import static com.github.javaparser.ast.NodeList.toNodeList;
+
+public class ListExprT implements TypedExpression {
+
+ private final ListCreationLiteralExpression listExpression;
+
+ public ListExprT(final ListCreationLiteralExpression listExpression) {
+ this.listExpression = listExpression;
+ }
+
+ @Override
+ public Optional<Type> getType() {
+ return Optional.of(List.class);
+ }
+
+ @Override
+ public Node toJavaExpression() {
+ if (listExpression.getExpressions() == null ||
listExpression.getExpressions().isEmpty()) {
+ return new MethodCallExpr(new
NameExpr(Collections.class.getCanonicalName()), "emptyList");
+ } else {
+ return new MethodCallExpr(new
NameExpr(List.class.getCanonicalName()), "of",
getValueExpressionsFromListElements(listExpression.getExpressions()));
+ }
+ }
+
+ private NodeList<Expression> getValueExpressionsFromListElements(final
NodeList<Expression> listItems) {
+ return listItems.stream()
+ .filter(listItem -> listItem instanceof
ListCreationLiteralExpressionElement)
+ .map(listItem -> ((ListCreationLiteralExpressionElement)
listItem).getValue())
+ .collect(toNodeList());
+ }
+}
diff --git
a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapExprT.java
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapExprT.java
new file mode 100644
index 0000000000..8291905fab
--- /dev/null
+++
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapExprT.java
@@ -0,0 +1,53 @@
+package org.drools.mvelcompiler.ast;
+
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.NameExpr;
+import org.drools.mvel.parser.ast.expr.ListCreationLiteralExpressionElement;
+import org.drools.mvel.parser.ast.expr.MapCreationLiteralExpression;
+import
org.drools.mvel.parser.ast.expr.MapCreationLiteralExpressionKeyValuePair;
+
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import static com.github.javaparser.ast.NodeList.toNodeList;
+
+public class MapExprT implements TypedExpression {
+
+ private final MapCreationLiteralExpression mapExpression;
+
+ public MapExprT(final MapCreationLiteralExpression mapExpression) {
+ this.mapExpression = mapExpression;
+ }
+
+ @Override
+ public Optional<Type> getType() {
+ return Optional.of(Map.class);
+ }
+
+ @Override
+ public Node toJavaExpression() {
+ if (mapExpression.getExpressions() == null ||
mapExpression.getExpressions().isEmpty()) {
+ return new MethodCallExpr(new
NameExpr(Collections.class.getCanonicalName()), "emptyMap");
+ } else {
+ return new MethodCallExpr(new
NameExpr(Map.class.getCanonicalName()), "ofEntries",
getMapEntryExpressions(mapExpression.getExpressions()));
+ }
+ }
+
+ private NodeList<Expression> getMapEntryExpressions(final
NodeList<Expression> mapEntries) {
+ return mapEntries.stream()
+ .filter(mapEntry -> mapEntry instanceof
MapCreationLiteralExpressionKeyValuePair)
+ .map(mapEntry ->
+ new MethodCallExpr(
+ new NameExpr(Map.class.getCanonicalName()),
+ "entry",
+
NodeList.nodeList(((MapCreationLiteralExpressionKeyValuePair)
mapEntry).getKey(),
+
((MapCreationLiteralExpressionKeyValuePair) mapEntry).getValue()))
+ ).collect(toNodeList());
+ }
+}
diff --git
a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MethodCallExprT.java
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MethodCallExprT.java
index 688b031621..5d3337edc5 100644
---
a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MethodCallExprT.java
+++
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MethodCallExprT.java
@@ -63,7 +63,7 @@ public class MethodCallExprT implements TypedExpression {
List<Expression> methodArguments;
// MVEL forces a to string on each String value in map
- if(PUT_CALL.equals(name) && arguments.size() == 2) {
+ if (PUT_CALL.equals(name) && arguments.size() == 2) {
methodArguments = coercedMapArguments();
} else {
methodArguments = toJavaExpressionArgument();
diff --git
a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/util/MethodResolutionUtils.java
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/util/MethodResolutionUtils.java
new file mode 100644
index 0000000000..7c648db28c
--- /dev/null
+++
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/util/MethodResolutionUtils.java
@@ -0,0 +1,224 @@
+package org.drools.mvelcompiler.util;
+
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.utils.Pair;
+import org.drools.mvel.parser.ast.expr.ListCreationLiteralExpression;
+import org.drools.mvel.parser.ast.expr.MapCreationLiteralExpression;
+import org.drools.mvel.parser.ast.visitor.DrlGenericVisitor;
+import org.drools.mvelcompiler.ast.ListExprT;
+import org.drools.mvelcompiler.ast.MapExprT;
+import org.drools.mvelcompiler.ast.TypedExpression;
+import org.drools.mvelcompiler.context.MvelCompilerContext;
+import org.drools.util.ClassUtils;
+import org.drools.util.MethodUtils;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+public final class MethodResolutionUtils {
+
+ private MethodResolutionUtils() {
+ // It is forbidden to create instances of util classes.
+ }
+
+ /**
+ * [] is ambiguous in mvel - it can represent an empty list or an empty
map.
+ * It cannot be distinguished on a language level, so this is a
workaround:
+ * - When there [] written in a rule, mvel parser parses it as an empty
list.
+ * - The only possible way with constructors, when there is such
parameter, is try to guess the correct parameter type when trying to read the
constructor from a class.
+ * - This uses all indexes of empty lists or empty maps in the
constructor parameters.
+ * - When not possible to resolve the constructor with a list or map
parameter, it will try to resolve a constructor with the other collection
parameter.
+ * - This happens for all empty list and map parameters resolved by the
parser, until a proper constructor is found.
+ */
+ public static List<TypedExpression> coerceCorrectConstructorArguments(
+ final Class<?> type,
+ List<TypedExpression> arguments,
+ List<Integer> emptyCollectionArgumentsIndexes) {
+ Objects.requireNonNull(type, "Type parameter cannot be null as the
method searches constructors from that class!");
+ Objects.requireNonNull(arguments, "Arguments parameter cannot be null!
Use an empty list instance if needed instead.");
+ Objects.requireNonNull(emptyCollectionArgumentsIndexes,
"EmptyListArgumentIndexes parameter cannot be null! Use an empty list instance
if needed instead.");
+ if (emptyCollectionArgumentsIndexes.size() > arguments.size()) {
+ throw new IllegalArgumentException("There cannot be more empty
collection arguments than all arguments! emptyCollectionArgumentsIndexes
parameter has more items than arguments parameter. "
+ + "(" + emptyCollectionArgumentsIndexes.size() + " > " +
arguments.size() + ")");
+ }
+ // Rather work only with the argumentsType and when a method is
resolved, flip the arguments list based on it.
+ final List<TypedExpression> coercedArgumentsTypesList = new
ArrayList<>(arguments);
+ Constructor<?> constructor = resolveConstructor(type,
coercedArgumentsTypesList);
+ if (constructor != null) {
+ return coercedArgumentsTypesList;
+ } else {
+ // This needs to go through all possible combinations.
+ final int indexesListSize = emptyCollectionArgumentsIndexes.size();
+ for (int numberOfProcessedIndexes = 0; numberOfProcessedIndexes <
indexesListSize; numberOfProcessedIndexes++) {
+ for (int indexOfEmptyListIndex = numberOfProcessedIndexes;
indexOfEmptyListIndex < indexesListSize; indexOfEmptyListIndex++) {
+
switchCollectionClassInArgumentsByIndex(coercedArgumentsTypesList,
emptyCollectionArgumentsIndexes.get(indexOfEmptyListIndex));
+ constructor = resolveConstructor(type,
coercedArgumentsTypesList);
+ if (constructor != null) {
+ return coercedArgumentsTypesList;
+ }
+
switchCollectionClassInArgumentsByIndex(coercedArgumentsTypesList,
emptyCollectionArgumentsIndexes.get(indexOfEmptyListIndex));
+ }
+
switchCollectionClassInArgumentsByIndex(coercedArgumentsTypesList,
emptyCollectionArgumentsIndexes.get(numberOfProcessedIndexes));
+ }
+ // No constructor found, return the original arguments.
+ return arguments;
+ }
+ }
+
+ private static Constructor<?> resolveConstructor(final Class<?> type,
List<TypedExpression> arguments) {
+ Constructor<?> constructor;
+ try {
+ constructor = type.getConstructor(parametersType(arguments));
+ } catch (NoSuchMethodException ex) {
+ constructor = null;
+ }
+ return constructor;
+ }
+
+ /**
+ * [] is ambiguous in mvel - it can represent an empty list or an empty
map.
+ * It cannot be distinguished on a language level, so this is a
workaround:
+ * - When there [] written in a rule, mvel parser parses it as an empty
list.
+ * - The only possible way with methods, when there is such parameter,
is try to guess the correct parameter type when trying to read the method from
a class.
+ * - This uses all indexes of empty lists or empty maps in the method
parameters.
+ * - When not possible to resolve the method with a list or map
parameter, it will try to resolve a method with the other collection parameter.
+ * - This happens for all empty list and map parameters resolved by the
parser, until a proper method is found.
+ */
+ public static Pair<Optional<Method>, Optional<TypedExpression>>
resolveMethodWithEmptyCollectionArguments(
+ final MethodCallExpr methodExpression,
+ final MvelCompilerContext mvelCompilerContext,
+ final Optional<TypedExpression> scope,
+ List<TypedExpression> arguments,
+ List<Integer> emptyCollectionArgumentsIndexes) {
+ Objects.requireNonNull(methodExpression, "MethodExpression parameter
cannot be null as the method searches methods based on this expression!");
+ Objects.requireNonNull(mvelCompilerContext, "MvelCompilerContext
parameter cannot be null!");
+ Objects.requireNonNull(arguments, "Arguments parameter cannot be null!
Use an empty list instance if needed instead.");
+ Objects.requireNonNull(emptyCollectionArgumentsIndexes,
"EmptyListArgumentIndexes parameter cannot be null! Use an empty list instance
if needed instead.");
+ if (emptyCollectionArgumentsIndexes.size() > arguments.size()) {
+ throw new IllegalArgumentException("There cannot be more empty
collection arguments than all arguments! emptyCollectionArgumentsIndexes
parameter has more items than arguments parameter. "
+ + "(" + emptyCollectionArgumentsIndexes.size() + " > " +
arguments.size() + ")");
+ } else {
+ final List<TypedExpression> coercedArgumentsTypesList = new
ArrayList<>(arguments);
+ Pair<Optional<Method>, Optional<TypedExpression>>
resolveMethodResult =
+ MethodResolutionUtils.resolveMethod(methodExpression,
mvelCompilerContext, scope, coercedArgumentsTypesList);
+ if (resolveMethodResult.a.isPresent()) {
+ return resolveMethodResult;
+ } else {
+ // Rather work only with the argumentsType and when a method
is resolved, flip the arguments list based on it.
+ // This needs to go through all possible combinations.
+ final int indexesListSize =
emptyCollectionArgumentsIndexes.size();
+ for (int numberOfProcessedIndexes = 0;
numberOfProcessedIndexes < indexesListSize; numberOfProcessedIndexes++) {
+ for (int indexOfEmptyListIndex = numberOfProcessedIndexes;
indexOfEmptyListIndex < indexesListSize; indexOfEmptyListIndex++) {
+
switchCollectionClassInArgumentsByIndex(coercedArgumentsTypesList,
emptyCollectionArgumentsIndexes.get(indexOfEmptyListIndex));
+ resolveMethodResult =
+
MethodResolutionUtils.resolveMethod(methodExpression, mvelCompilerContext,
scope, coercedArgumentsTypesList);
+ if (resolveMethodResult.a.isPresent()) {
+
modifyArgumentsBasedOnCoercedCollectionArguments(arguments,
coercedArgumentsTypesList);
+ return resolveMethodResult;
+ }
+
switchCollectionClassInArgumentsByIndex(coercedArgumentsTypesList,
emptyCollectionArgumentsIndexes.get(indexOfEmptyListIndex));
+ }
+
switchCollectionClassInArgumentsByIndex(coercedArgumentsTypesList,
emptyCollectionArgumentsIndexes.get(numberOfProcessedIndexes));
+ }
+ // No method found, return empty.
+ return new Pair<>(Optional.empty(), scope);
+ }
+ }
+ }
+
+ public static Pair<Optional<Method>, Optional<TypedExpression>>
resolveMethod(
+ final MethodCallExpr methodExpression,
+ final MvelCompilerContext mvelCompilerContext,
+ final Optional<TypedExpression> scope,
+ final List<TypedExpression> arguments) {
+ Objects.requireNonNull(methodExpression, "MethodExpression parameter
cannot be null as the method searches methods based on this expression!");
+ Objects.requireNonNull(mvelCompilerContext, "MvelCompilerContext
parameter cannot be null!");
+ Objects.requireNonNull(arguments, "Arguments parameter cannot be null!
Use an empty list instance if needed instead.");
+ final Class<?>[] argumentsTypesClasses = parametersType(arguments);
+ Optional<TypedExpression> finalScope = scope;
+ Optional<Method> resolvedMethod;
+ resolvedMethod = finalScope.flatMap(TypedExpression::getType)
+ .<Class<?>>map(ClassUtils::classFromType)
+ .map(scopeClazz -> MethodUtils.findMethod(scopeClazz,
methodExpression.getNameAsString(), argumentsTypesClasses));
+
+ if (resolvedMethod.isEmpty()) {
+ resolvedMethod = mvelCompilerContext.getRootPattern()
+ .map(scopeClazz -> MethodUtils.findMethod(scopeClazz,
methodExpression.getNameAsString(), argumentsTypesClasses));
+ if (resolvedMethod.isPresent()) {
+ finalScope = mvelCompilerContext.createRootTypePrefix();
+ }
+ }
+
+ if (resolvedMethod.isEmpty()) {
+ resolvedMethod =
mvelCompilerContext.findStaticMethod(methodExpression.getNameAsString());
+ }
+ return new Pair<>(resolvedMethod, finalScope);
+ }
+
+ public static Pair<List<TypedExpression>, List<Integer>>
getTypedArgumentsWithEmptyCollectionArgumentDetection(
+ final NodeList<Expression> arguments,
+ final DrlGenericVisitor<TypedExpression, VisitorContext>
drlGenericVisitor,
+ final VisitorContext arg) {
+ final List<TypedExpression> typedArguments = new ArrayList<>();
+ final List<Integer> emptyCollectionArgumentIndexes = new ArrayList<>();
+ int argumentIndex = 0;
+ for (Expression child : arguments) {
+ TypedExpression a = child.accept(drlGenericVisitor, arg);
+ typedArguments.add(a);
+ if (child instanceof ListCreationLiteralExpression
+ && (((ListCreationLiteralExpression)
child).getExpressions() == null
+ || ((ListCreationLiteralExpression)
child).getExpressions().isEmpty())) {
+ emptyCollectionArgumentIndexes.add(argumentIndex);
+ } else if (child instanceof MapCreationLiteralExpression
+ && (((MapCreationLiteralExpression)
child).getExpressions() == null
+ || ((MapCreationLiteralExpression)
child).getExpressions().isEmpty())) {
+ emptyCollectionArgumentIndexes.add(argumentIndex);
+ }
+ argumentIndex++;
+ }
+ return new Pair<>(typedArguments, emptyCollectionArgumentIndexes);
+ }
+
+ private static Class<?>[] parametersType(List<TypedExpression> arguments) {
+ return arguments.stream()
+ .map(TypedExpression::getType)
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .map(ClassUtils::classFromType)
+ .toArray(Class[]::new);
+ }
+
+ private static void switchCollectionClassInArgumentsByIndex(final
List<TypedExpression> argumentsTypesList, final int index) {
+ final Class<?> argumentTypeClass =
argumentsTypesList.get(index).getClass();
+ if (argumentTypeClass.equals(ListExprT.class) ||
argumentTypeClass.equals(MapExprT.class)) {
+ if (argumentTypeClass.equals(ListExprT.class)) {
+ argumentsTypesList.set(index, new MapExprT(new
MapCreationLiteralExpression(null, NodeList.nodeList())));
+ } else {
+ argumentsTypesList.set(index, new ListExprT(new
ListCreationLiteralExpression(null, NodeList.nodeList())));
+ }
+ } else {
+ throw new IllegalArgumentException("Argument at index " + index +
" from the list of arguments (argumentsTypesList) is not a collection type, but
" + argumentTypeClass.getCanonicalName() + " type!");
+ }
+ }
+
+ private static void modifyArgumentsBasedOnCoercedCollectionArguments(final
List<TypedExpression> arguments, final List<TypedExpression>
coercedCollectionArguments) {
+ int index = 0;
+ for (TypedExpression coercedArgument : coercedCollectionArguments) {
+ if
(!coercedArgument.getClass().equals(arguments.get(index).getClass())) {
+ // Originally the resolved type was a List, so if it is
different, it is a Map.
+ if (coercedArgument.getClass().equals(MapExprT.class)) {
+ arguments.set(index, new MapExprT(new
MapCreationLiteralExpression(null, NodeList.nodeList())));
+ } else {
+ arguments.set(index, new ListExprT(new
ListCreationLiteralExpression(null, NodeList.nodeList())));
+ }
+ }
+ index++;
+ }
+ }
+}
diff --git
a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/util/VisitorContext.java
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/util/VisitorContext.java
new file mode 100644
index 0000000000..4945e669d1
--- /dev/null
+++
b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/util/VisitorContext.java
@@ -0,0 +1,24 @@
+package org.drools.mvelcompiler.util;
+
+import org.drools.mvelcompiler.ast.TypedExpression;
+
+import java.lang.reflect.Type;
+import java.util.Optional;
+
+import static java.util.Optional.ofNullable;
+
+public class VisitorContext {
+ private final Optional<TypedExpression> scope;
+
+ public VisitorContext(final TypedExpression scope) {
+ this.scope = ofNullable(scope);
+ }
+
+ public Optional<Type> getScopeType() {
+ return scope.flatMap(TypedExpression::getType);
+ }
+
+ public Optional<TypedExpression> getScope() {
+ return scope;
+ }
+}
diff --git
a/drools-model/drools-mvel-compiler/src/test/java/org/drools/Person.java
b/drools-model/drools-mvel-compiler/src/test/java/org/drools/Person.java
index e99d6887c1..00b60f8877 100644
--- a/drools-model/drools-mvel-compiler/src/test/java/org/drools/Person.java
+++ b/drools-model/drools-mvel-compiler/src/test/java/org/drools/Person.java
@@ -53,6 +53,9 @@ public class Person {
private Integer ageAsInteger;
+ public Person() {
+ }
+
public Person(String name) {
this(name, null);
}
@@ -67,6 +70,19 @@ public class Person {
this.gender = gender;
}
+ public Person(List<Address> addresses) {
+ this.addresses = addresses;
+ }
+
+ public Person(Map<String, String> items) {
+ this.items = items;
+ }
+
+ public Person(List<Address> addresses, Map<String, String> items) {
+ this.addresses = addresses;
+ this.items = items;
+ }
+
public String getName() {
return name;
}
@@ -204,4 +220,9 @@ public class Person {
public void setFloatBoxed(Float floatBoxed) {
this.floatBoxed = floatBoxed;
}
+
+ public void setAddressesAndItems(List<Address> addresses, Map<String,
String> items) {
+ this.addresses = addresses;
+ this.items = items;
+ }
}
diff --git
a/drools-model/drools-mvel-compiler/src/test/java/org/drools/mvelcompiler/util/MethodResolutionUtilsTest.java
b/drools-model/drools-mvel-compiler/src/test/java/org/drools/mvelcompiler/util/MethodResolutionUtilsTest.java
new file mode 100644
index 0000000000..c449cfe5c1
--- /dev/null
+++
b/drools-model/drools-mvel-compiler/src/test/java/org/drools/mvelcompiler/util/MethodResolutionUtilsTest.java
@@ -0,0 +1,303 @@
+package org.drools.mvelcompiler.util;
+
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.IntegerLiteralExpr;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
+import com.github.javaparser.utils.Pair;
+import org.assertj.core.api.Assertions;
+import org.drools.Person;
+import org.drools.mvel.parser.ast.expr.ListCreationLiteralExpression;
+import org.drools.mvel.parser.ast.expr.MapCreationLiteralExpression;
+import org.drools.mvelcompiler.ast.IntegerLiteralExpressionT;
+import org.drools.mvelcompiler.ast.ListExprT;
+import org.drools.mvelcompiler.ast.MapExprT;
+import org.drools.mvelcompiler.ast.ObjectCreationExpressionT;
+import org.drools.mvelcompiler.ast.StringLiteralExpressionT;
+import org.drools.mvelcompiler.ast.TypedExpression;
+import org.drools.mvelcompiler.context.MvelCompilerContext;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class MethodResolutionUtilsTest {
+
+ @Test
+ public void coerceCorrectConstructorArgumentsTypeIsNull() {
+ Assertions.assertThatThrownBy(
+ () ->
MethodResolutionUtils.coerceCorrectConstructorArguments(
+ null,
+ null,
+ null))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void coerceCorrectConstructorArgumentsArgumentsAreNull() {
+ Assertions.assertThatThrownBy(
+ () ->
MethodResolutionUtils.coerceCorrectConstructorArguments(
+ Person.class,
+ null,
+ null))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void
coerceCorrectConstructorArgumentsEmptyCollectionIndexesAreNull() {
+ Assertions.assertThatThrownBy(
+ () ->
MethodResolutionUtils.coerceCorrectConstructorArguments(
+ Person.class,
+ Collections.emptyList(),
+ null))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void
coerceCorrectConstructorArgumentsEmptyCollectionIndexesBiggerThanArguments() {
+ Assertions.assertThatThrownBy(
+ () ->
MethodResolutionUtils.coerceCorrectConstructorArguments(
+ Person.class,
+ Collections.emptyList(),
+ List.of(1, 2, 4)))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void coerceCorrectConstructorArgumentsNoCollectionArguments() {
+ final List<TypedExpression> arguments = List.of(new
IntegerLiteralExpressionT(new IntegerLiteralExpr("12")));
+ final List<TypedExpression> coercedArguments =
MethodResolutionUtils.coerceCorrectConstructorArguments(
+ Person.class, arguments, Collections.emptyList());
+
Assertions.assertThat(coercedArguments).containsExactlyElementsOf(arguments);
+ }
+
+ @Test
+ public void coerceCorrectConstructorArgumentsIsNotCollectionAtIndex() {
+ final List<TypedExpression> arguments = List.of(new
IntegerLiteralExpressionT(new IntegerLiteralExpr("12")));
+ Assertions.assertThatThrownBy(
+ () ->
MethodResolutionUtils.coerceCorrectConstructorArguments(
+ Person.class,
+ arguments,
+ List.of(0)))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void coerceCorrectConstructorArgumentsList() {
+ final List<TypedExpression> arguments = List.of(new ListExprT(new
ListCreationLiteralExpression(null, NodeList.nodeList())));
+ final List<TypedExpression> coercedArguments =
MethodResolutionUtils.coerceCorrectConstructorArguments(
+ Person.class, arguments, List.of(0));
+
Assertions.assertThat(coercedArguments).containsExactlyElementsOf(arguments);
+ }
+
+ @Test
+ public void coerceCorrectConstructorArgumentsCoerceMap() {
+ final List<TypedExpression> arguments =
+ List.of(
+ new ListExprT(new ListCreationLiteralExpression(null,
NodeList.nodeList())),
+ new ListExprT(new ListCreationLiteralExpression(null,
NodeList.nodeList())));
+ final List<Class<?>> expectedArgumentClasses =
List.of(ListExprT.class, MapExprT.class);
+ final List<TypedExpression> coercedArguments =
MethodResolutionUtils.coerceCorrectConstructorArguments(
+ Person.class, arguments, List.of(1));
+ Assertions.assertThat(getTypedExpressionsClasses(coercedArguments))
+ .containsExactlyElementsOf(expectedArgumentClasses);
+ }
+
+ @Test
+ public void coerceCorrectConstructorArgumentsCoerceList() {
+ final List<TypedExpression> arguments =
+ List.of(
+ new MapExprT(new MapCreationLiteralExpression(null,
NodeList.nodeList())),
+ new MapExprT(new MapCreationLiteralExpression(null,
NodeList.nodeList())));
+ final List<Class<?>> expectedArgumentClasses =
List.of(ListExprT.class, MapExprT.class);
+ final List<TypedExpression> coercedArguments =
MethodResolutionUtils.coerceCorrectConstructorArguments(
+ Person.class, arguments, List.of(0));
+ Assertions.assertThat(getTypedExpressionsClasses(coercedArguments))
+ .containsExactlyElementsOf(expectedArgumentClasses);
+ }
+
+ @Test
+ public void coerceCorrectConstructorArgumentsCoerceListAndMap() {
+ final List<TypedExpression> arguments =
+ List.of(
+ new MapExprT(new MapCreationLiteralExpression(null,
NodeList.nodeList())),
+ new ListExprT(new ListCreationLiteralExpression(null,
NodeList.nodeList())));
+ final List<Class<?>> expectedArgumentClasses =
List.of(ListExprT.class, MapExprT.class);
+ final List<TypedExpression> coercedArguments =
MethodResolutionUtils.coerceCorrectConstructorArguments(
+ Person.class, arguments, List.of(0, 1));
+ Assertions.assertThat(getTypedExpressionsClasses(coercedArguments))
+ .containsExactlyElementsOf(expectedArgumentClasses);
+ }
+
+ @Test
+ public void
resolveMethodWithEmptyCollectionArgumentsMethodExpressionIsNull() {
+ Assertions.assertThatThrownBy(
+ () ->
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(
+ null,
+ null,
+ Optional.empty(),
+ null,
+ null))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void
resolveMethodWithEmptyCollectionArgumentsMvelCompilerContextIsNull() {
+ Assertions.assertThatThrownBy(
+ () ->
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(
+ new MethodCallExpr(),
+ null,
+ Optional.empty(),
+ null,
+ null))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void resolveMethodWithEmptyCollectionArgumentsArgumentsAreNull() {
+ Assertions.assertThatThrownBy(
+ () ->
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(
+ new MethodCallExpr(),
+ new MvelCompilerContext(null),
+ Optional.empty(),
+ null,
+ null))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void
resolveMethodWithEmptyCollectionArgumentsEmptyCollectionIndexesAreNull() {
+ Assertions.assertThatThrownBy(
+ () ->
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(
+ new MethodCallExpr(),
+ new MvelCompilerContext(null),
+ Optional.empty(),
+ Collections.emptyList(),
+ null))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void
resolveMethodWithEmptyCollectionArgumentsEmptyCollectionIndexesBiggerThanArguments()
{
+ Assertions.assertThatThrownBy(
+ () ->
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(
+ new MethodCallExpr(),
+ new MvelCompilerContext(null),
+ Optional.empty(),
+ Collections.emptyList(),
+ List.of(1, 2, 4)))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void
resolveMethodWithEmptyCollectionArgumentsNoCollectionArguments() {
+ final MethodCallExpr methodExpression = new
MethodCallExpr("setIntegerBoxed", new IntegerLiteralExpr("12"));
+ final List<TypedExpression> arguments = List.of(new
IntegerLiteralExpressionT(new IntegerLiteralExpr("12")));
+ final List<TypedExpression> expectedArguments = new
ArrayList<>(arguments);
+ final TypedExpression scope = new ObjectCreationExpressionT(arguments,
Person.class);
+ final Pair<Optional<Method>, Optional<TypedExpression>>
resolvedMethodResult =
+
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(
+ methodExpression,
+ new MvelCompilerContext(null),
+ Optional.of(scope),
+ arguments,
+ Collections.emptyList());
+ Assertions.assertThat(resolvedMethodResult.a).isPresent();
+
Assertions.assertThat(arguments).containsExactlyElementsOf(expectedArguments);
+ }
+
+ @Test
+ public void
resolveMethodWithEmptyCollectionArgumentsIsNotCollectionAtIndex() {
+ final MethodCallExpr methodExpression = new
MethodCallExpr("setIntegerBoxed", new IntegerLiteralExpr("12"));
+ final List<TypedExpression> arguments = List.of(new
StringLiteralExpressionT(new StringLiteralExpr("12")));
+ final TypedExpression scope = new ObjectCreationExpressionT(arguments,
Person.class);
+ Assertions.assertThatThrownBy(
+ () ->
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(
+ methodExpression,
+ new MvelCompilerContext(null),
+ Optional.of(scope),
+ arguments,
+ List.of(0)))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void resolveMethodWithEmptyCollectionArguments() {
+ final MethodCallExpr methodExpression = new
MethodCallExpr("setAddresses", new ListCreationLiteralExpression(null,
NodeList.nodeList()));
+ final List<TypedExpression> arguments = List.of(new ListExprT(new
ListCreationLiteralExpression(null, NodeList.nodeList())));
+ final TypedExpression scope = new ObjectCreationExpressionT(arguments,
Person.class);
+ final Pair<Optional<Method>, Optional<TypedExpression>>
resolvedMethodResult =
+
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(
+ methodExpression,
+ new MvelCompilerContext(null),
+ Optional.of(scope),
+ arguments,
+ List.of(0));
+ Assertions.assertThat(resolvedMethodResult.a).isPresent();
+ Assertions.assertThat(getTypedExpressionsClasses(arguments))
+ .containsExactlyElementsOf(List.of(ListExprT.class));
+ }
+
+ @Test
+ public void resolveMethodWithEmptyCollectionArgumentsCoerceMap() {
+ final MethodCallExpr methodExpression = new MethodCallExpr("setItems",
new MapCreationLiteralExpression(null, NodeList.nodeList()));
+ final List<TypedExpression> arguments = new ArrayList<>();
+ arguments.add(new ListExprT(new ListCreationLiteralExpression(null,
NodeList.nodeList())));
+ final TypedExpression scope = new
ObjectCreationExpressionT(Collections.emptyList(), Person.class);
+ final Pair<Optional<Method>, Optional<TypedExpression>>
resolvedMethodResult =
+
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(
+ methodExpression,
+ new MvelCompilerContext(null),
+ Optional.of(scope),
+ arguments,
+ List.of(0));
+ Assertions.assertThat(resolvedMethodResult.a).isPresent();
+ Assertions.assertThat(getTypedExpressionsClasses(arguments))
+ .containsExactlyElementsOf(List.of(MapExprT.class));
+ }
+
+ @Test
+ public void resolveMethodWithEmptyCollectionArgumentsCoerceList() {
+ final MethodCallExpr methodExpression = new
MethodCallExpr("setAddresses", new MapCreationLiteralExpression(null,
NodeList.nodeList()));
+ final List<TypedExpression> arguments = new ArrayList<>();
+ arguments.add(new MapExprT(new MapCreationLiteralExpression(null,
NodeList.nodeList())));
+ final TypedExpression scope = new
ObjectCreationExpressionT(Collections.emptyList(), Person.class);
+ final Pair<Optional<Method>, Optional<TypedExpression>>
resolvedMethodResult =
+
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(
+ methodExpression,
+ new MvelCompilerContext(null),
+ Optional.of(scope),
+ arguments,
+ List.of(0));
+ Assertions.assertThat(resolvedMethodResult.a).isPresent();
+ Assertions.assertThat(getTypedExpressionsClasses(arguments))
+ .containsExactlyElementsOf(List.of(ListExprT.class));
+ }
+
+ @Test
+ public void resolveMethodWithEmptyCollectionArgumentsCoerceListAndMap() {
+ final MethodCallExpr methodExpression = new
MethodCallExpr("setAddressesAndItems", new MapCreationLiteralExpression(null,
NodeList.nodeList()));
+ final List<TypedExpression> arguments = new ArrayList<>();
+ arguments.add(new MapExprT(new MapCreationLiteralExpression(null,
NodeList.nodeList())));
+ arguments.add(new ListExprT(new ListCreationLiteralExpression(null,
NodeList.nodeList())));
+ final TypedExpression scope = new
ObjectCreationExpressionT(Collections.emptyList(), Person.class);
+ final Pair<Optional<Method>, Optional<TypedExpression>>
resolvedMethodResult =
+
MethodResolutionUtils.resolveMethodWithEmptyCollectionArguments(
+ methodExpression,
+ new MvelCompilerContext(null),
+ Optional.of(scope),
+ arguments,
+ List.of(0, 1));
+ Assertions.assertThat(resolvedMethodResult.a).isPresent();
+ Assertions.assertThat(getTypedExpressionsClasses(arguments))
+ .containsExactlyElementsOf(List.of(ListExprT.class,
MapExprT.class));
+ }
+
+ private List<Class<?>> getTypedExpressionsClasses(List<TypedExpression>
typedExpressions) {
+ return
typedExpressions.stream().map(TypedExpression::getClass).collect(Collectors.toList());
+ }
+}
\ No newline at end of file
diff --git
a/drools-model/drools-mvel-parser/src/main/java/org/drools/mvel/parser/ast/visitor/DrlGenericVisitor.java
b/drools-model/drools-mvel-parser/src/main/java/org/drools/mvel/parser/ast/visitor/DrlGenericVisitor.java
index 8bfa2fa91e..e22961cf30 100644
---
a/drools-model/drools-mvel-parser/src/main/java/org/drools/mvel/parser/ast/visitor/DrlGenericVisitor.java
+++
b/drools-model/drools-mvel-parser/src/main/java/org/drools/mvel/parser/ast/visitor/DrlGenericVisitor.java
@@ -639,11 +639,15 @@ public interface DrlGenericVisitor<R, A> extends
GenericVisitor<R,A> {
return defaultMethod(n, arg);
}
- default R visit(MapCreationLiteralExpression n, A arg) { return null; }
+ default R visit(MapCreationLiteralExpression n, A arg) {
+ return defaultMethod(n, arg);
+ }
default R visit(MapCreationLiteralExpressionKeyValuePair n, A arg) {
return null; }
- default R visit(ListCreationLiteralExpression n, A arg) { return null; }
+ default R visit(ListCreationLiteralExpression n, A arg) {
+ return defaultMethod(n, arg);
+ }
default R visit(ListCreationLiteralExpressionElement n, A arg) { return
null; }
diff --git
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/MVELEmptyCollectionsTest.java
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/MVELEmptyCollectionsTest.java
new file mode 100644
index 0000000000..aa884f989b
--- /dev/null
+++
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/MVELEmptyCollectionsTest.java
@@ -0,0 +1,167 @@
+/**
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.mvel.integrationtests;
+
+import org.drools.base.base.ClassObjectType;
+import org.drools.base.rule.constraint.AlphaNodeFieldConstraint;
+import org.drools.core.reteoo.AlphaNode;
+import org.drools.core.reteoo.ObjectTypeNode;
+import org.drools.kiesession.rulebase.InternalKnowledgeBase;
+import org.drools.mvel.MVELConstraint;
+import org.drools.mvel.accessors.ClassFieldReader;
+import org.drools.mvel.compiler.Address;
+import org.drools.mvel.compiler.Cheese;
+import org.drools.mvel.compiler.Cheesery;
+import org.drools.mvel.compiler.FactA;
+import org.drools.mvel.compiler.Person;
+import org.drools.mvel.compiler.TestEnum;
+import org.drools.mvel.expr.MVELDebugHandler;
+import org.drools.mvel.extractors.MVELObjectClassFieldReader;
+import org.drools.mvel.integrationtests.facts.FactWithList;
+import org.drools.mvel.integrationtests.facts.FactWithMap;
+import org.drools.mvel.integrationtests.facts.FactWithObject;
+import org.drools.testcoverage.common.util.KieBaseTestConfiguration;
+import org.drools.testcoverage.common.util.KieBaseUtil;
+import org.drools.testcoverage.common.util.KieUtil;
+import org.drools.testcoverage.common.util.TestParametersUtil;
+import org.drools.util.DateUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.kie.api.KieBase;
+import org.kie.api.builder.KieBuilder;
+import org.kie.api.builder.Message;
+import org.kie.api.definition.type.FactType;
+import org.kie.api.runtime.KieSession;
+import org.kie.api.runtime.StatelessKieSession;
+import org.mvel2.MVEL;
+import org.mvel2.ParserContext;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
+
+@RunWith(Parameterized.class)
+public class MVELEmptyCollectionsTest {
+
+ private final KieBaseTestConfiguration kieBaseTestConfiguration;
+
+ public MVELEmptyCollectionsTest(final KieBaseTestConfiguration
kieBaseTestConfiguration) {
+ this.kieBaseTestConfiguration = kieBaseTestConfiguration;
+ }
+
+ @Parameterized.Parameters(name = "KieBase type={0}")
+ public static Collection<Object[]> getParameters() {
+ // Some of these fail without executable model, so test only
executable model.
+ return TestParametersUtil.getKieBaseCloudOnlyExecModelConfiguration();
+ }
+
+ @Test
+ public void testEmptyListAsMethodParameter() {
+ final String drl =
+ "import " + FactWithList.class.getCanonicalName() + "; \n" +
+ "rule \"test\"\n" +
+ "dialect \"mvel\" \n" +
+ "when\n" +
+ " $p: FactWithList()\n" +
+ "then\n" +
+ " $p.setItems([]); \n" +
+ "end";
+
+ KieBase kbase = KieBaseUtil.getKieBaseFromKieModuleFromDrl("test",
kieBaseTestConfiguration, drl);
+ KieSession ksession = kbase.newKieSession();
+ final FactWithList f = new FactWithList("testString");
+ ksession.insert(f);
+ assertThat(ksession.fireAllRules()).isEqualTo(1);
+ assertThat(f.getItems()).hasSize(0);
+ }
+
+ @Test
+ public void testEmptyListAsConstructorParameter() {
+ final String drl =
+ "import " + FactWithList.class.getCanonicalName() + "; \n" +
+ "import " + FactWithObject.class.getCanonicalName() +
"; \n" +
+ "rule \"test\"\n" +
+ "dialect \"mvel\" \n" +
+ "when\n" +
+ " $p: FactWithObject()\n" +
+ "then\n" +
+ " $p.setObjectValue(new FactWithList([])); \n" +
+ "end";
+
+ KieBase kbase = KieBaseUtil.getKieBaseFromKieModuleFromDrl("test",
kieBaseTestConfiguration, drl);
+ KieSession ksession = kbase.newKieSession();
+ final FactWithObject f = new FactWithObject(null);
+ ksession.insert(f);
+ assertThat(ksession.fireAllRules()).isEqualTo(1);
+ assertThat(f.getObjectValue()).isInstanceOf(FactWithList.class);
+ }
+
+ @Test
+ public void testEmptyMapAsMethodParameter() {
+ final String drl =
+ "import " + FactWithMap.class.getCanonicalName() + "; \n" +
+ "rule \"test\"\n" +
+ "dialect \"mvel\" \n" +
+ "when\n" +
+ " $p: FactWithMap()\n" +
+ "then\n" +
+ " $p.setItemsMap([]); \n" +
+ "end";
+
+ KieBase kbase = KieBaseUtil.getKieBaseFromKieModuleFromDrl("test",
kieBaseTestConfiguration, drl);
+ KieSession ksession = kbase.newKieSession();
+ final FactWithMap f = new FactWithMap(1, "testString");
+ ksession.insert(f);
+ assertThat(ksession.fireAllRules()).isEqualTo(1);
+ assertThat(f.getItemsMap()).hasSize(0);
+ }
+
+ @Test
+ public void testEmptyMapAsConstructorParameter() {
+ final String drl =
+ "import " + FactWithMap.class.getCanonicalName() + "; \n" +
+ "import " + FactWithObject.class.getCanonicalName() +
"; \n" +
+ "rule \"test\"\n" +
+ "dialect \"mvel\" \n" +
+ "when\n" +
+ " $p: FactWithObject()\n" +
+ "then\n" +
+ " $p.setObjectValue(new FactWithMap([])); \n" +
+ "end";
+
+ KieBase kbase = KieBaseUtil.getKieBaseFromKieModuleFromDrl("test",
kieBaseTestConfiguration, drl);
+ KieSession ksession = kbase.newKieSession();
+ final FactWithObject f = new FactWithObject(null);
+ ksession.insert(f);
+ assertThat(ksession.fireAllRules()).isEqualTo(1);
+
assertThat(f.getObjectValue()).isNotNull().isInstanceOf(FactWithMap.class);
+ }
+}
diff --git
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/MVELTest.java
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/MVELTest.java
index e878e4c65a..a7c5565919 100644
---
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/MVELTest.java
+++
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/MVELTest.java
@@ -36,6 +36,8 @@ import org.drools.base.base.ClassObjectType;
import org.drools.core.reteoo.AlphaNode;
import org.drools.core.reteoo.ObjectTypeNode;
import org.drools.base.rule.constraint.AlphaNodeFieldConstraint;
+import org.drools.mvel.compiler.PersonHolder;
+import org.drools.mvel.integrationtests.facts.FactWithList;
import org.drools.util.DateUtils;
import org.drools.mvel.MVELConstraint;
import org.drools.mvel.compiler.Address;
diff --git
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithList.java
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithList.java
index a4ab4c647a..eff913cc64 100644
---
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithList.java
+++
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithList.java
@@ -31,6 +31,10 @@ public class FactWithList {
this.items.add(factString);
}
+ public FactWithList(final List<String> items) {
+ this.items = items;
+ }
+
public List<String> getItems() {
return items;
}
diff --git
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithList.java
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithMap.java
similarity index 62%
copy from
drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithList.java
copy to
drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithMap.java
index a4ab4c647a..e92423e8b2 100644
---
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithList.java
+++
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithMap.java
@@ -18,24 +18,28 @@
*/
package org.drools.mvel.integrationtests.facts;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
-public class FactWithList {
+public class FactWithMap {
- private List<String> items = new ArrayList<>();
+ private Map<Integer, String> itemsMap = new HashMap<>();
- public FactWithList() { }
+ public FactWithMap() { }
- public FactWithList(final String factString) {
- this.items.add(factString);
+ public FactWithMap(final Integer key, final String value) {
+ this.itemsMap.put(key, value);
}
- public List<String> getItems() {
- return items;
+ public FactWithMap(final Map<Integer, String> itemsMap) {
+ this.itemsMap = itemsMap;
}
- public void setItems(List<String> items) {
- this.items = items;
+ public Map<Integer, String> getItemsMap() {
+ return itemsMap;
+ }
+
+ public void setItemsMap(Map<Integer, String> itemsMap) {
+ this.itemsMap = itemsMap;
}
}
diff --git
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithList.java
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithObject.java
similarity index 69%
copy from
drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithList.java
copy to
drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithObject.java
index a4ab4c647a..7a468e1662 100644
---
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithList.java
+++
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/facts/FactWithObject.java
@@ -18,24 +18,19 @@
*/
package org.drools.mvel.integrationtests.facts;
-import java.util.ArrayList;
-import java.util.List;
+public class FactWithObject {
-public class FactWithList {
+ private Object objectValue;
- private List<String> items = new ArrayList<>();
-
- public FactWithList() { }
-
- public FactWithList(final String factString) {
- this.items.add(factString);
+ public FactWithObject(final Object objectValue) {
+ this.objectValue = objectValue;
}
- public List<String> getItems() {
- return items;
+ public Object getObjectValue() {
+ return objectValue;
}
- public void setItems(List<String> items) {
- this.items = items;
+ public void setObjectValue(final Object objectValue) {
+ this.objectValue = objectValue;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]