diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunction.java index 46713afe720..a587d4b664c 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunction.java @@ -31,6 +31,8 @@ public class ListReplaceFunction public static final ListReplaceFunction INSTANCE = new ListReplaceFunction(); + private static final String CANNOT_BE_NULL = "cannot be null" + private ListReplaceFunction() { super("list replace"); } @@ -38,19 +40,20 @@ private ListReplaceFunction() { public FEELFnResult invoke(@ParameterName("list") List list, @ParameterName("position") BigDecimal position, @ParameterName("newItem") Object newItem) { if (list == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "list", "cannot be null")); + return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "list", CANNOT_BE_NULL)); } if (position == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "position", "cannot be null")); + return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "position", CANNOT_BE_NULL)); } int intPosition = position.intValue(); - if (intPosition < 1 || intPosition > list.size()) { + if (intPosition == 0 || Math.abs(intPosition) > list.size()) { String paramProblem = String.format("%s outside valid boundaries (1-%s)", intPosition, list.size()); return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "position", paramProblem)); } Object e = EvalHelper.coerceNumber(newItem); List toReturn = new ArrayList(list); - toReturn.set(intPosition - 1, e); + int replacementPosition = intPosition > 0 ? intPosition -1 : list.size() - Math.abs(intPosition); + toReturn.set(replacementPosition, e); return FEELFnResult.ofResult(toReturn); } @@ -58,10 +61,10 @@ public FEELFnResult invoke(@ParameterName("list") List list, @ParameterName("match") AbstractCustomFEELFunction match, @ParameterName("newItem") Object newItem) { if (list == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "list", "cannot be null")); + return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "list", CANNOT_BE_NULL)); } if (match == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "match", "cannot be null")); + return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "match", CANNOT_BE_NULL)); } Object e = EvalHelper.coerceNumber(newItem); List toReturn = new ArrayList(); diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java index 93875f2380e..5478e9a575f 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java @@ -240,6 +240,7 @@ public static Collection data() { {"list replace ( null, 3, 6)", null , FEELEvent.Severity.ERROR}, {"list replace ( [2, 4, 7, 8], null, 6)", null , FEELEvent.Severity.ERROR}, {"list replace ( [2, 4, 7, 8], 3, 6)", Arrays.asList(BigDecimal.valueOf(2), BigDecimal.valueOf(4), BigDecimal.valueOf(6), BigDecimal.valueOf(8)), null}, + {"list replace ( [2, 4, 7, 8], -3, 6)", Arrays.asList(BigDecimal.valueOf(2), BigDecimal.valueOf(6), BigDecimal.valueOf(7), BigDecimal.valueOf(8)), null}, {"list replace ( [2, 4, 7, 8], function(item, newItem) item + newItem, 6)", null , FEELEvent.Severity.ERROR}, {"list replace ( [\"El-1\", \"El-2\", \"El-3\", \"El-4\"], function(item, newItem) item = \"El-2\", null)", Arrays.asList("El-1", null, "El-3", "El-4"), null}, {"list replace ( [2, 4, 7, 8], function(item, newItem) item < newItem, 5)", Arrays.asList(BigDecimal.valueOf(5), BigDecimal.valueOf(5), BigDecimal.valueOf(7), BigDecimal.valueOf(8)), null} diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunctionTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunctionTest.java index da07a192473..ff85207cb06 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunctionTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunctionTest.java @@ -67,6 +67,22 @@ public void invokeReplaceByPositionWithNull() { FunctionTestUtil.assertResult(listReplaceFunction.invoke(list, BigDecimal.valueOf(2), null), expected); } + @Test + public void invokeReplaceByNegativePositionWithNotNull() { + List list = getList(); + List expected = new ArrayList<>(list); + expected.set(2, "test"); + FunctionTestUtil.assertResult(listReplaceFunction.invoke(list, BigDecimal.valueOf(-1), "test"), expected); + } + + @Test + public void invokeReplaceByNegativePositionWithNull() { + List list = getList(); + List expected = new ArrayList<>(list); + expected.set(2, null); + FunctionTestUtil.assertResult(listReplaceFunction.invoke(list, BigDecimal.valueOf(-1), null), expected); + } + @Test public void invokeReplaceByPositionWithNotNull() { List list = getList(); @@ -75,6 +91,7 @@ public void invokeReplaceByPositionWithNotNull() { FunctionTestUtil.assertResult(listReplaceFunction.invoke(list, BigDecimal.valueOf(2), "test"), expected); } + @Test public void invokeMatchNull() { FunctionTestUtil.assertResultError(listReplaceFunction.invoke(new ArrayList(), (AbstractCustomFEELFunction) null, ""), InvalidParametersEvent.class);