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 2c8ec647f4 [incubator-kie-issues#1911] DMN 1.6: Add a type conversion 
from decimal to integer with Test cases (#6299)
2c8ec647f4 is described below

commit 2c8ec647f49dbbe36d7cd899413d43b76e19bffd
Author: ChinchuAjith <[email protected]>
AuthorDate: Wed Apr 30 16:01:40 2025 +0530

    [incubator-kie-issues#1911] DMN 1.6: Add a type conversion from decimal to 
integer with Test cases (#6299)
---
 .../feel/runtime/functions/CeilingFunction.java    | 25 +++---
 .../runtime/functions/DateAndTimeFunction.java     | 98 ++++++++++------------
 .../dmn/feel/runtime/functions/DateFunction.java   | 45 +++++-----
 .../feel/runtime/functions/DecimalFunction.java    | 28 ++++---
 .../dmn/feel/runtime/functions/FloorFunction.java  | 27 +++---
 .../runtime/functions/InsertBeforeFunction.java    | 44 +++++-----
 .../runtime/functions/ListReplaceFunction.java     | 34 ++++----
 .../dmn/feel/runtime/functions/RemoveFunction.java | 44 +++++-----
 .../feel/runtime/functions/RoundDownFunction.java  | 26 +++---
 .../runtime/functions/RoundHalfDownFunction.java   | 26 +++---
 .../runtime/functions/RoundHalfUpFunction.java     | 26 +++---
 .../feel/runtime/functions/RoundUpFunction.java    | 26 +++---
 .../feel/runtime/functions/SublistFunction.java    | 57 +++++++------
 .../dmn/feel/runtime/functions/TimeFunction.java   | 23 +++--
 .../org/kie/dmn/feel/util/NumberEvalHelper.java    | 25 +++++-
 .../kie/dmn/feel/util/NumberEvalHelperTest.java    | 63 ++++++++++++++
 16 files changed, 369 insertions(+), 248 deletions(-)

diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CeilingFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CeilingFunction.java
index ad2e9c193a..d96297c9a3 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CeilingFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CeilingFunction.java
@@ -20,11 +20,14 @@ package org.kie.dmn.feel.runtime.functions;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.util.NoSuchElementException;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELNumberFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class CeilingFunction
         extends BaseFEELFunction implements FEELNumberFunction {
 
@@ -39,17 +42,17 @@ public class CeilingFunction
     }
 
     public FEELFnResult<BigDecimal> invoke(@ParameterName( "n" ) BigDecimal n, 
@ParameterName( "scale" ) BigDecimal scale) {
-        if ( n == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "n", "cannot be null"));
-        }
-        if ( scale == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "cannot be null"));
+        try {
+            if (n == null) {
+                throw new NoSuchElementException("n");
+            }
+            int coercedScale = coerceIntegerNumber(scale).orElseThrow(() -> 
new NoSuchElementException("scale"));
+            if (coercedScale < -6111 || coercedScale > 6176) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+            }
+            return FEELFnResult.ofResult( n.setScale( coercedScale, 
RoundingMode.CEILING ) );
+        }catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         }
-        // Based on Table 76: Semantics of numeric functions, the scale is in 
range −6111 .. 6176
-        if (scale.compareTo(BigDecimal.valueOf(-6111)) < 0 || 
scale.compareTo(BigDecimal.valueOf(6176)) > 0) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
-        }
-
-        return FEELFnResult.ofResult( n.setScale( scale.intValue(), 
RoundingMode.CEILING ) );
     }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunction.java
index c7ffcb0398..a18d6aa8a6 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunction.java
@@ -30,12 +30,16 @@ import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
 import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalQueries;
+import java.util.NoSuchElementException;
+import java.util.Optional;
 import java.util.TimeZone;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELDateTimeFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class DateAndTimeFunction
         extends BaseFEELFunction implements FEELDateTimeFunction {
 
@@ -119,71 +123,57 @@ public class DateAndTimeFunction
         return invoke( year, month, day, hour, minute, second, (Number) null );
     }
 
-    public FEELFnResult<TemporalAccessor> invoke(@ParameterName( "year" ) 
Number year, @ParameterName( "month" ) Number month, @ParameterName( "day" ) 
Number day,
-                                                 @ParameterName( "hour" ) 
Number hour, @ParameterName( "minute" ) Number minute, @ParameterName( "second" 
) Number second,
-                                                 @ParameterName( "hour offset" 
) Number hourOffset ) {
-        if ( year == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "year", "cannot be null"));
-        }
-        if ( month == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "month", "cannot be null"));
-        }
-        if ( day == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "day", "cannot be null"));
-        }
-        if ( hour == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "hour", "cannot be null"));
-        }
-        if ( minute == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "minute", "cannot be null"));
-        }
-        if ( second == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "second", "cannot be null"));
-        }
-
+    public FEELFnResult<TemporalAccessor> invoke(@ParameterName("year") Number 
year, @ParameterName("month") Number month, @ParameterName("day") Number day,
+                                                 @ParameterName("hour") Number 
hour, @ParameterName("minute") Number minute, @ParameterName("second") Number 
second,
+                                                 @ParameterName("hour offset") 
Number hourOffset) {
         try {
-            if( hourOffset != null ) {
-                return FEELFnResult.ofResult( OffsetDateTime.of( 
year.intValue(), month.intValue(), day.intValue(),
-                                                                
hour.intValue(), minute.intValue(), second.intValue(),
-                                                     0, ZoneOffset.ofHours( 
hourOffset.intValue() ) ) );
+            int coercedYear = coerceIntegerNumber(year).orElseThrow(() -> new 
NoSuchElementException("year"));
+            int coercedMonth = coerceIntegerNumber(month).orElseThrow(() -> 
new NoSuchElementException("month"));
+            int coercedDay = coerceIntegerNumber(day).orElseThrow(() -> new 
NoSuchElementException("day"));
+            int coercedHour = coerceIntegerNumber(hour).orElseThrow(() -> new 
NoSuchElementException("hour"));
+            int coercedMinute = coerceIntegerNumber(minute).orElseThrow(() -> 
new NoSuchElementException("minute"));
+            int coercedSecond = coerceIntegerNumber(second).orElseThrow(() -> 
new NoSuchElementException("second"));
+
+            if (hourOffset != null) {
+                Optional<Integer> coercedHourOffset = 
coerceIntegerNumber(hourOffset);
+                return 
coercedHourOffset.<FEELFnResult<TemporalAccessor>>map(integer -> 
FEELFnResult.ofResult(
+                        OffsetDateTime.of(
+                                coercedYear, coercedMonth, coercedDay,
+                                coercedHour, coercedMinute, coercedSecond,
+                                0, ZoneOffset.ofHours(integer)))).orElseGet(() 
-> FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "hour 
offset", "could not be coerced to Integer")));
+
             } else {
-                return FEELFnResult.ofResult( LocalDateTime.of( 
year.intValue(), month.intValue(), day.intValue(),
-                                                                
hour.intValue(), minute.intValue(), second.intValue() ) );
+                return FEELFnResult.ofResult(
+                        LocalDateTime.of(
+                                coercedYear, coercedMonth, coercedDay,
+                                coercedHour, coercedMinute, coercedSecond
+                        )
+                );
             }
+        } catch (NoSuchElementException e) { // thrown by 
Optional.orElseThrow()
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         } catch (DateTimeException e) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "input parameters date-parsing 
exception", e));
         }
     }
 
-    public FEELFnResult<TemporalAccessor> invoke(@ParameterName( "year" ) 
Number year, @ParameterName( "month" ) Number month, @ParameterName( "day" ) 
Number day,
-                                                 @ParameterName( "hour" ) 
Number hour, @ParameterName( "minute" ) Number minute, @ParameterName( "second" 
) Number second,
-                                                 @ParameterName( "timezone" ) 
String timezone ) {
-        if (year == null) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "year", "cannot be null"));
-        }
-        if (month == null) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "month", "cannot be null"));
-        }
-        if (day == null) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "day", "cannot be null"));
-        }
-        if (hour == null) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "hour", "cannot be null"));
-        }
-        if (minute == null) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "minute", "cannot be null"));
-        }
-        if (second == null) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "second", "cannot be null"));
-        }
-
+    public FEELFnResult<TemporalAccessor> invoke(@ParameterName("year") Number 
year, @ParameterName("month") Number month, @ParameterName("day") Number day,
+                                                 @ParameterName("hour") Number 
hour, @ParameterName("minute") Number minute, @ParameterName("second") Number 
second,
+                                                 @ParameterName("timezone") 
String timezone) {
         try {
-            return FEELFnResult.ofResult(ZonedDateTime.of(year.intValue(), 
month.intValue(), day.intValue(),
-                    hour.intValue(), minute.intValue(), second.intValue(), 0, 
TimeZone.getTimeZone(timezone).toZoneId()));
+            int coercedYear = coerceIntegerNumber(year).orElseThrow(() -> new 
NoSuchElementException("year"));
+            int coercedMonth = coerceIntegerNumber(month).orElseThrow(() -> 
new NoSuchElementException("month"));
+            int coercedDay = coerceIntegerNumber(day).orElseThrow(() -> new 
NoSuchElementException("day"));
+            int coercedHour = coerceIntegerNumber(hour).orElseThrow(() -> new 
NoSuchElementException("hour"));
+            int coercedMinute = coerceIntegerNumber(minute).orElseThrow(() -> 
new NoSuchElementException("minute"));
+            int coercedSecond = coerceIntegerNumber(second).orElseThrow(() -> 
new NoSuchElementException("second"));
+            return FEELFnResult.ofResult(ZonedDateTime.of(coercedYear, 
coercedMonth, coercedDay,
+                    coercedHour, coercedMinute, coercedSecond, 0, 
TimeZone.getTimeZone(timezone).toZoneId()));
+        } catch (NoSuchElementException e) { // thrown by 
Optional.orElseThrow()
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         } catch (DateTimeException e) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "input parameters date-parsing 
exception", e));
         }
-    }
-
 
+    }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java
index a9245f2e54..be690dd2e6 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java
@@ -25,6 +25,7 @@ import java.time.format.DateTimeFormatterBuilder;
 import java.time.format.ResolverStyle;
 import java.time.format.SignStyle;
 import java.time.temporal.TemporalAccessor;
+import java.util.NoSuchElementException;
 import java.util.regex.Pattern;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
@@ -34,6 +35,7 @@ import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
 import static java.time.temporal.ChronoField.YEAR;
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
 
 public class DateFunction
         extends BaseFEELFunction implements FEELDateFunction {
@@ -42,22 +44,23 @@ public class DateFunction
 
     public static final Pattern BEGIN_YEAR = 
Pattern.compile("^-?(([1-9]\\d\\d\\d+)|(0\\d\\d\\d))-"); // FEEL spec, 
"specified by XML Schema Part 2 Datatypes", hence: yearFrag ::= '-'? (([1-9] 
digit digit digit+)) | ('0' digit digit digit))
     public static final DateTimeFormatter FEEL_DATE;
+
     static {
         FEEL_DATE = new DateTimeFormatterBuilder().appendValue(YEAR, 4, 9, 
SignStyle.NORMAL)
-                                                  .appendLiteral('-')
-                                                  .appendValue(MONTH_OF_YEAR, 
2)
-                                                  .appendLiteral('-')
-                                                  .appendValue(DAY_OF_MONTH, 2)
-                                                  .toFormatter()
-                                                  
.withResolverStyle(ResolverStyle.STRICT);
+                .appendLiteral('-')
+                .appendValue(MONTH_OF_YEAR, 2)
+                .appendLiteral('-')
+                .appendValue(DAY_OF_MONTH, 2)
+                .toFormatter()
+                .withResolverStyle(ResolverStyle.STRICT);
     }
 
     protected DateFunction() {
         super(FEELConversionFunctionNames.DATE);
     }
 
-    public FEELFnResult<TemporalAccessor> invoke(@ParameterName( "from" ) 
String val) {
-        if ( val == null ) {
+    public FEELFnResult<TemporalAccessor> invoke(@ParameterName("from") String 
val) {
+        if (val == null) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "from", "cannot be null"));
         }
         if (!BEGIN_YEAR.matcher(val).find()) { // please notice the regex 
strictly requires the beginning, so we can use find.
@@ -71,31 +74,26 @@ public class DateFunction
         }
     }
 
-    public FEELFnResult<TemporalAccessor> invoke(@ParameterName( "year" ) 
Number year, @ParameterName( "month" ) Number month, @ParameterName( "day" ) 
Number day) {
-        if ( year == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "year", "cannot be null"));
-        }
-        if ( month == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "month", "cannot be null"));
-        }
-        if ( day == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "day", "cannot be null"));
-        }
-
+    public FEELFnResult<TemporalAccessor> invoke(@ParameterName("year") Number 
year, @ParameterName("month") Number month, @ParameterName("day") Number day) {
         try {
-            return FEELFnResult.ofResult( LocalDate.of( year.intValue(), 
month.intValue(), day.intValue() ) );
+            int coercedYear = coerceIntegerNumber(year).orElseThrow(() -> new 
NoSuchElementException("year"));
+            int coercedMonth = coerceIntegerNumber(month).orElseThrow(() -> 
new NoSuchElementException("month"));
+            int coercedDay = coerceIntegerNumber(day).orElseThrow(() -> new 
NoSuchElementException("day"));
+            return FEELFnResult.ofResult(LocalDate.of(coercedYear, 
coercedMonth, coercedDay));
+        } catch (NoSuchElementException e) { // thrown by 
Optional.orElseThrow()
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         } catch (DateTimeException e) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "input parameters date-parsing 
exception", e));
         }
     }
 
-    public FEELFnResult<TemporalAccessor> invoke(@ParameterName( "from" ) 
TemporalAccessor date) {
-        if ( date == null ) {
+    public FEELFnResult<TemporalAccessor> invoke(@ParameterName("from") 
TemporalAccessor date) {
+        if (date == null) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "from", "cannot be null"));
         }
 
         try {
-            return FEELFnResult.ofResult( LocalDate.from( date ) );
+            return FEELFnResult.ofResult(LocalDate.from(date));
         } catch (DateTimeException e) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "from", "date-parsing exception", e));
         }
@@ -104,4 +102,5 @@ public class DateFunction
     protected FEELFnResult<TemporalAccessor> 
manageDateTimeException(DateTimeException e, String val) {
         return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, 
"date", e));
     }
+
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecimalFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecimalFunction.java
index 270271962f..15606af1b9 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecimalFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecimalFunction.java
@@ -20,11 +20,14 @@ package org.kie.dmn.feel.runtime.functions;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.util.NoSuchElementException;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELNumberFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class DecimalFunction
         extends BaseFEELFunction implements FEELNumberFunction {
 
@@ -34,18 +37,19 @@ public class DecimalFunction
         super( "decimal" );
     }
 
-    public FEELFnResult<BigDecimal> invoke(@ParameterName( "n" ) BigDecimal n, 
@ParameterName( "scale" ) BigDecimal scale) {
-        if ( n == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "n", "cannot be null"));
-        }
-        if ( scale == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "cannot be null"));
+    public FEELFnResult<BigDecimal> invoke(@ParameterName("n") BigDecimal n, 
@ParameterName("scale") BigDecimal scale) {
+        try {
+            if (n == null) {
+                throw new NoSuchElementException("n");
+            }
+            int coercedScale = coerceIntegerNumber(scale).orElseThrow(() -> 
new NoSuchElementException("scale"));
+            if (coercedScale < -6111 || coercedScale > 6176) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+            }
+            return FEELFnResult.ofResult( n.setScale( coercedScale, 
RoundingMode.HALF_EVEN ) );
+        } catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         }
-        // Based on Table 76: Semantics of numeric functions, the scale is in 
range −6111 .. 6176
-        if (scale.compareTo(BigDecimal.valueOf(-6111)) < 0 || 
scale.compareTo(BigDecimal.valueOf(6176)) > 0) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
-        }
-        
-        return FEELFnResult.ofResult( n.setScale( scale.intValue(), 
RoundingMode.HALF_EVEN ) );
+
     }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/FloorFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/FloorFunction.java
index b012ad7f3a..3d297b4488 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/FloorFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/FloorFunction.java
@@ -20,11 +20,14 @@ package org.kie.dmn.feel.runtime.functions;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.util.NoSuchElementException;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELNumberFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class FloorFunction
         extends BaseFEELFunction implements FEELNumberFunction {
 
@@ -38,18 +41,18 @@ public class FloorFunction
         return invoke(n, BigDecimal.ZERO);
     }
 
-    public FEELFnResult<BigDecimal> invoke(@ParameterName( "n" ) BigDecimal n, 
@ParameterName( "scale" ) BigDecimal scale) {
-        if ( n == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "n", "cannot be null"));
-        }
-        if ( scale == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "cannot be null"));
+    public FEELFnResult<BigDecimal> invoke(@ParameterName("n") BigDecimal n, 
@ParameterName("scale") BigDecimal scale) {
+        try {
+            if (n == null) {
+                throw new NoSuchElementException("n");
+            }
+            int coercedScale = coerceIntegerNumber(scale).orElseThrow(() -> 
new NoSuchElementException("scale"));
+            if (coercedScale < -6111 || coercedScale > 6176) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+            }
+            return FEELFnResult.ofResult( n.setScale( coercedScale, 
RoundingMode.FLOOR ) );
+        } catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         }
-        // Based on Table 76: Semantics of numeric functions, the scale is in 
range −6111 .. 6176
-        if (scale.compareTo(BigDecimal.valueOf(-6111)) < 0 || 
scale.compareTo(BigDecimal.valueOf(6176)) > 0) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
-        }
-
-        return FEELFnResult.ofResult( n.setScale( scale.intValue(), 
RoundingMode.FLOOR ) );
     }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/InsertBeforeFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/InsertBeforeFunction.java
index 0c89422b9e..3640b739cb 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/InsertBeforeFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/InsertBeforeFunction.java
@@ -21,11 +21,14 @@ package org.kie.dmn.feel.runtime.functions;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.NoSuchElementException;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELCollectionFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class InsertBeforeFunction
         extends BaseFEELFunction implements FEELCollectionFunction {
 
@@ -36,26 +39,29 @@ public class InsertBeforeFunction
     }
 
     public FEELFnResult<List> 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"));
-        }
-        if ( position == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "position", "cannot be null"));
-        }
-        if ( position.intValue() == 0 ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "position", "cannot be zero (parameter 
'position' is 1-based)"));
-        }
-        if ( position.abs().intValue() > list.size() ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "position", "inconsistent with 'list' 
size"));
-        }
+        try {
+            if ( list == null ) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "list", "cannot be null"));
+            }
+            int coercedPosition = coerceIntegerNumber(position).orElseThrow(() 
-> new NoSuchElementException("position"));
 
-        // spec requires us to return a new list
-        final List<Object> result = new ArrayList<>( list );
-        if( position.intValue() > 0 ) {
-            result.add( position.intValue() - 1, newItem );
-        } else {
-            result.add( list.size() + position.intValue(), newItem );
+            if ( coercedPosition == 0 ) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "position", "cannot be zero (parameter 
'position' is 1-based)"));
+            }
+            if ( Math.abs(coercedPosition) > list.size() ) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "position", "inconsistent with 'list' 
size"));
+            }
+            // spec requires us to return a new list
+            final List<Object> result = new ArrayList<>( list );
+            if( coercedPosition > 0 ) {
+                result.add( coercedPosition - 1, newItem );
+            } else {
+                result.add( list.size() + coercedPosition, newItem );
+            }
+            return FEELFnResult.ofResult( result );
+        } catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "cannot be coerced to 
Integer: either null or not a valid Number."));
         }
-        return FEELFnResult.ofResult( result );
+
     }
 }
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 12f0c827d3..bd67869115 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
@@ -21,12 +21,15 @@ package org.kie.dmn.feel.runtime.functions;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.NoSuchElementException;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELCollectionFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 import org.kie.dmn.feel.util.NumberEvalHelper;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class ListReplaceFunction
         extends BaseFEELFunction implements FEELCollectionFunction {
 
@@ -40,22 +43,23 @@ public class ListReplaceFunction
 
     public FEELFnResult<List> 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));
-        }
-        if (position == null) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "position", CANNOT_BE_NULL));
-        }
-        int intPosition = position.intValue();
-        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));
+        try {
+            if (list == null) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "list", CANNOT_BE_NULL));
+            }
+            int coercedPosition = coerceIntegerNumber(position).orElseThrow(() 
-> new NoSuchElementException("position"));
+            if (coercedPosition == 0 || Math.abs(coercedPosition) > 
list.size()) {
+                String paramProblem = String.format("%s outside valid 
boundaries (1-%s)", coercedPosition, list.size());
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "position", paramProblem));
+            }
+            Object e = NumberEvalHelper.coerceNumber(newItem);
+            List toReturn = new ArrayList(list);
+            int replacementPosition = coercedPosition > 0 ? coercedPosition - 
1 : list.size() - Math.abs(coercedPosition);
+            toReturn.set(replacementPosition, e);
+            return FEELFnResult.ofResult(toReturn);
+        } catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         }
-        Object e = NumberEvalHelper.coerceNumber(newItem);
-        List toReturn = new ArrayList(list);
-        int replacementPosition = intPosition > 0 ? intPosition -1 : 
list.size() - Math.abs(intPosition);
-        toReturn.set(replacementPosition, e);
-        return FEELFnResult.ofResult(toReturn);
     }
 
     public FEELFnResult<List> invoke(@ParameterName("list") List list,
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RemoveFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RemoveFunction.java
index 85561f5fc6..f732c7c84c 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RemoveFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RemoveFunction.java
@@ -21,11 +21,14 @@ package org.kie.dmn.feel.runtime.functions;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.NoSuchElementException;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELCollectionFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class RemoveFunction
         extends BaseFEELFunction implements FEELCollectionFunction {
 
@@ -36,25 +39,28 @@ public class RemoveFunction
     }
 
     public FEELFnResult<List<Object>> invoke(@ParameterName( "list" ) List 
list, @ParameterName( "position" ) BigDecimal position) {
-        if ( list == 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"));
-        }
-        if ( position.intValue() == 0 ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "position", "cannot be zero (parameter 
'position' is 1-based)"));
-        }
-        if ( position.abs().intValue() > list.size() ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "position", "inconsistent with 'list' 
size"));
-        }
-        // spec requires us to return a new list
-        List<Object> result = new ArrayList<>( list );
-        if( position.intValue() > 0 ) {
-            result.remove( position.intValue()-1 );
-        } else {
-            result.remove( list.size()+position.intValue() );
+        try {
+            if (list == null) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "list", "cannot be null"));
+            }
+            int coercedPosition = coerceIntegerNumber(position).orElseThrow(() 
-> new NoSuchElementException("position"));
+            if (coercedPosition == 0) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "position", "cannot be zero (parameter 
'position' is 1-based)"));
+            }
+            if (Math.abs(coercedPosition) > list.size()) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "position", "inconsistent with 'list' 
size"));
+            }
+
+            // spec requires us to return a new list
+            List<Object> result = new ArrayList<>(list);
+            if (coercedPosition > 0) {
+                result.remove(coercedPosition - 1);
+            } else {
+                result.remove(list.size() + coercedPosition);
+            }
+            return FEELFnResult.ofResult(result);
+        } catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         }
-        return FEELFnResult.ofResult( result );
     }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundDownFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundDownFunction.java
index ca37b4ef1c..35d5642938 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundDownFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundDownFunction.java
@@ -20,11 +20,14 @@ package org.kie.dmn.feel.runtime.functions;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.util.NoSuchElementException;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELNumberFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class RoundDownFunction
         extends BaseFEELFunction implements FEELNumberFunction {
 
@@ -38,17 +41,18 @@ public class RoundDownFunction
         return invoke(n, BigDecimal.ZERO);
     }
 
-    public FEELFnResult<BigDecimal> invoke(@ParameterName( "n" ) BigDecimal n, 
@ParameterName( "scale" ) BigDecimal scale) {
-        if ( n == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "n", "cannot be null"));
-        }
-        if ( scale == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "cannot be null"));
-        }
-        // Based on Table 76: Semantics of numeric functions, the scale is in 
range −6111 .. 6176
-        if (scale.compareTo(BigDecimal.valueOf(-6111)) < 0 || 
scale.compareTo(BigDecimal.valueOf(6176)) > 0) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+    public FEELFnResult<BigDecimal> invoke(@ParameterName("n") BigDecimal n, 
@ParameterName("scale") BigDecimal scale) {
+        try {
+            if (n == null) {
+                throw new NoSuchElementException("n");
+            }
+            int coercedScale = coerceIntegerNumber(scale).orElseThrow(() -> 
new NoSuchElementException("scale"));
+            if (coercedScale < -6111 || coercedScale > 6176) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+            }
+            return FEELFnResult.ofResult( n.setScale( coercedScale, 
RoundingMode.DOWN ) );
+        } catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         }
-        return FEELFnResult.ofResult( n.setScale( scale.intValue(), 
RoundingMode.DOWN ) );
     }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundHalfDownFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundHalfDownFunction.java
index 25def1a706..df0ac33a94 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundHalfDownFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundHalfDownFunction.java
@@ -20,11 +20,14 @@ package org.kie.dmn.feel.runtime.functions;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.util.NoSuchElementException;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELNumberFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class RoundHalfDownFunction
         extends BaseFEELFunction implements FEELNumberFunction {
 
@@ -38,17 +41,18 @@ public class RoundHalfDownFunction
         return invoke(n, BigDecimal.ZERO);
     }
 
-    public FEELFnResult<BigDecimal> invoke(@ParameterName( "n" ) BigDecimal n, 
@ParameterName( "scale" ) BigDecimal scale) {
-        if ( n == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "n", "cannot be null"));
-        }
-        if ( scale == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "cannot be null"));
-        }
-        // Based on Table 76: Semantics of numeric functions, the scale is in 
range −6111 .. 6176
-        if (scale.compareTo(BigDecimal.valueOf(-6111)) < 0 || 
scale.compareTo(BigDecimal.valueOf(6176)) > 0) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+    public FEELFnResult<BigDecimal> invoke(@ParameterName("n") BigDecimal n, 
@ParameterName("scale") BigDecimal scale) {
+        try {
+            if (n == null) {
+                throw new NoSuchElementException("n");
+            }
+            int coercedScale = coerceIntegerNumber(scale).orElseThrow(() -> 
new NoSuchElementException("scale"));
+            if (coercedScale < -6111 || coercedScale > 6176) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+            }
+            return FEELFnResult.ofResult( n.setScale( coercedScale, 
RoundingMode.HALF_DOWN ) );
+        } catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         }
-        return FEELFnResult.ofResult( n.setScale( scale.intValue(), 
RoundingMode.HALF_DOWN ) );
     }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundHalfUpFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundHalfUpFunction.java
index 5ce58bf8bf..4d1907c203 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundHalfUpFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundHalfUpFunction.java
@@ -20,11 +20,14 @@ package org.kie.dmn.feel.runtime.functions;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.util.NoSuchElementException;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELNumberFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class RoundHalfUpFunction
         extends BaseFEELFunction implements FEELNumberFunction {
 
@@ -38,17 +41,18 @@ public class RoundHalfUpFunction
         return invoke(n, BigDecimal.ZERO);
     }
 
-    public FEELFnResult<BigDecimal> invoke(@ParameterName( "n" ) BigDecimal n, 
@ParameterName( "scale" ) BigDecimal scale) {
-        if ( n == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "n", "cannot be null"));
-        }
-        if ( scale == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "cannot be null"));
-        }
-        // Based on Table 76: Semantics of numeric functions, the scale is in 
range −6111 .. 6176
-        if (scale.compareTo(BigDecimal.valueOf(-6111)) < 0 || 
scale.compareTo(BigDecimal.valueOf(6176)) > 0) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+    public FEELFnResult<BigDecimal> invoke(@ParameterName("n") BigDecimal n, 
@ParameterName("scale") BigDecimal scale) {
+        try {
+            if (n == null) {
+                throw new NoSuchElementException("n");
+            }
+            int coercedScale = coerceIntegerNumber(scale).orElseThrow(() -> 
new NoSuchElementException("scale"));
+            if (coercedScale < -6111 || coercedScale > 6176) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+            }
+            return FEELFnResult.ofResult( n.setScale( coercedScale, 
RoundingMode.HALF_UP ) );
+        } catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         }
-        return FEELFnResult.ofResult( n.setScale( scale.intValue(), 
RoundingMode.HALF_UP ) );
     }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundUpFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundUpFunction.java
index 794a76aeb6..770edef0a8 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundUpFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RoundUpFunction.java
@@ -20,11 +20,14 @@ package org.kie.dmn.feel.runtime.functions;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.util.NoSuchElementException;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELNumberFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class RoundUpFunction
         extends BaseFEELFunction implements FEELNumberFunction {
 
@@ -38,17 +41,18 @@ public class RoundUpFunction
         return invoke(n, BigDecimal.ZERO);
     }
 
-    public FEELFnResult<BigDecimal> invoke(@ParameterName( "n" ) BigDecimal n, 
@ParameterName( "scale" ) BigDecimal scale) {
-        if ( n == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "n", "cannot be null"));
-        }
-        if ( scale == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "cannot be null"));
-        }
-        // Based on Table 76: Semantics of numeric functions, the scale is in 
range −6111 .. 6176
-        if (scale.compareTo(BigDecimal.valueOf(-6111)) < 0 || 
scale.compareTo(BigDecimal.valueOf(6176)) > 0) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+    public FEELFnResult<BigDecimal> invoke(@ParameterName("n") BigDecimal n, 
@ParameterName("scale") BigDecimal scale) {
+        try {
+            if (n == null) {
+                throw new NoSuchElementException("n");
+            }
+            int coercedScale = coerceIntegerNumber(scale).orElseThrow(() -> 
new NoSuchElementException("scale"));
+            if (coercedScale < -6111 || coercedScale > 6176) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+            }
+            return FEELFnResult.ofResult( n.setScale( coercedScale, 
RoundingMode.UP ) );
+        } catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         }
-        return FEELFnResult.ofResult( n.setScale( scale.intValue(), 
RoundingMode.UP ) );
     }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SublistFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SublistFunction.java
index 263c930008..c36229eb52 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SublistFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SublistFunction.java
@@ -20,10 +20,14 @@ package org.kie.dmn.feel.runtime.functions;
 
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.NoSuchElementException;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELCollectionFunction;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
+import org.kie.dmn.feel.util.NumberEvalHelper;
+
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
 
 public class SublistFunction
         extends BaseFEELFunction implements FEELCollectionFunction {
@@ -39,34 +43,37 @@ public class SublistFunction
     }
 
     public FEELFnResult<List> invoke(@ParameterName("list") List list, 
@ParameterName("start position") BigDecimal start, @ParameterName("length") 
BigDecimal length) {
-        if ( list == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "list", "cannot be null"));
-        }
-        if ( start == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "start", "cannot be null"));
-        }
-        if ( start.equals( BigDecimal.ZERO ) ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "start", "cannot be zero"));
-        }
-        if ( start.abs().intValue() > list.size() ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "start", "is inconsistent with 'list' 
size"));
-        }
-        if ( length != null && length.compareTo(BigDecimal.ZERO) <= 0) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "length", "must be a positive number 
when specified"));
-        }
+        try {
+            if (list == null) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "list", "cannot be null"));
+            }
+            int coercedStart = coerceIntegerNumber(start).orElseThrow(() -> 
new NoSuchElementException("start"));
+            if (coercedStart == 0) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "start", "cannot be zero"));
+            }
+            if (Math.abs(coercedStart) > list.size()) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "start", "is inconsistent with 'list' 
size"));
+            }
 
-        if ( start.intValue() > 0 ) {
-            int end = length != null ? start.intValue() - 1 + 
length.intValue() : list.size();
-            if ( end > list.size() ) {
-                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "attempting to create a sublist bigger 
than the original list"));
+            if (length != null && length.compareTo(BigDecimal.ZERO) <= 0) {
+                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "length", "must be a positive number 
when specified"));
             }
-            return FEELFnResult.ofResult( list.subList( start.intValue() - 1, 
end ) );
-        } else {
-            int end = length != null ? list.size() + start.intValue() + 
length.intValue() : list.size();
-            if ( end > list.size() ) {
-                return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "attempting to create a sublist bigger 
than the original list"));
+            int coercedLength = 
NumberEvalHelper.coerceIntegerNumber(length).orElse(0);
+            if (coercedStart > 0) {
+                int end = length != null ? coercedStart - 1 + coercedLength : 
list.size();
+                if (end > list.size()) {
+                    return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "attempting to create a sublist bigger 
than the original list"));
+                }
+                return FEELFnResult.ofResult(list.subList(coercedStart - 1, 
end));
+            } else {
+                int end = length != null ? list.size() + coercedStart + 
coercedLength : list.size();
+                if (end > list.size()) {
+                    return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "attempting to create a sublist bigger 
than the original list"));
+                }
+                return FEELFnResult.ofResult(list.subList(list.size() + 
coercedStart, end));
             }
-            return FEELFnResult.ofResult( list.subList( list.size() + 
start.intValue(), end ) );
+        } catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
         }
     }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java
index b5c6c39e20..dc1e6813be 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java
@@ -32,6 +32,7 @@ import java.time.format.ResolverStyle;
 import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalQueries;
+import java.util.NoSuchElementException;
 import java.util.regex.Pattern;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent;
@@ -40,6 +41,8 @@ import org.kie.dmn.feel.runtime.FEELTimeFunction;
 import org.kie.dmn.feel.runtime.custom.ZoneTime;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
+import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
+
 public class TimeFunction
         extends BaseFEELFunction implements FEELTimeFunction {
 
@@ -118,17 +121,10 @@ public class TimeFunction
     public FEELFnResult<TemporalAccessor> invoke(
             @ParameterName("hour") Number hour, @ParameterName("minute") 
Number minute,
             @ParameterName("second") Number seconds, @ParameterName("offset") 
Duration offset) {
-        if ( hour == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "hour", "cannot be null"));
-        }
-        if ( minute == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "minute", "cannot be null"));
-        }
-        if ( seconds == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "seconds", "cannot be null"));
-        }
-        
         try {
+            int coercedHour = coerceIntegerNumber(hour).orElseThrow(() -> new 
NoSuchElementException("hour"));
+            int coercedMinute = coerceIntegerNumber(minute).orElseThrow(() -> 
new NoSuchElementException("minute"));
+            int coercedSecond = coerceIntegerNumber(seconds).orElseThrow(() -> 
new NoSuchElementException("seconds"));
             int nanosecs = 0;
             if( seconds instanceof BigDecimal ) {
                 BigDecimal secs = (BigDecimal) seconds;
@@ -136,13 +132,15 @@ public class TimeFunction
             }
 
             if ( offset == null ) {
-                return FEELFnResult.ofResult( LocalTime.of( hour.intValue(), 
minute.intValue(), seconds.intValue(),
+                return FEELFnResult.ofResult( LocalTime.of( coercedHour, 
coercedMinute, coercedSecond,
                                                             nanosecs ) );
             } else {
-                return FEELFnResult.ofResult( OffsetTime.of( hour.intValue(), 
minute.intValue(), seconds.intValue(),
+                return FEELFnResult.ofResult( OffsetTime.of( coercedHour, 
coercedMinute, coercedSecond,
                                                              nanosecs,
                                               ZoneOffset.ofTotalSeconds( (int) 
offset.getSeconds() ) ) );
             }
+        } catch (NoSuchElementException e) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "One or more input 
values could not be coerced to Integer: either null or not a valid Number."));
         } catch (DateTimeException e) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "time-parsing exception", e));
         }
@@ -180,5 +178,4 @@ public class TimeFunction
     protected FEELFnResult<TemporalAccessor> 
manageDateTimeException(DateTimeException e, String val) {
         return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, 
"from", e));
     }
-
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/NumberEvalHelper.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/NumberEvalHelper.java
index f5920416f4..229a456a02 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/NumberEvalHelper.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/NumberEvalHelper.java
@@ -21,6 +21,7 @@ package org.kie.dmn.feel.util;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.MathContext;
+import java.util.Optional;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -69,9 +70,31 @@ public class NumberEvalHelper {
     public static Object coerceNumber(Object value) {
         if ( value instanceof Number && !(value instanceof BigDecimal) ) {
             return getBigDecimalOrNull( value );
-        } else {
+        }  else {
             return value;
         }
     }
 
+    /**
+     * This method checks if the input is an instance of BigDecimal, BigInteger
+     * or any other subclass Number. If so, it returns an Optional containing
+     * the result of calling intValue() on the number. If the input is not a 
recognized number type,
+     * it returns Optional#empty()
+     * @param value : The object to coerce into an Integer
+     * @return : An Optional<Integer> containing the coerced integer value,
+     *           or Optional.empty() if the input is not a supported number 
type
+     */
+    public static Optional<Integer> coerceIntegerNumber(Object value) {
+        if ( value instanceof BigDecimal ) {
+            return  Optional.of(((BigDecimal) value).intValue());
+        }
+        if ( value instanceof BigInteger ) {
+            return  Optional.of(((BigInteger) value).intValue());
+        }
+        if ( value instanceof Number ) {
+            return  Optional.of(((Number) value).intValue());
+        }
+        return Optional.empty();
+    }
+
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/NumberEvalHelperTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/NumberEvalHelperTest.java
index e619069768..31249ce7cf 100644
--- 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/NumberEvalHelperTest.java
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/NumberEvalHelperTest.java
@@ -19,6 +19,8 @@
 package org.kie.dmn.feel.util;
 
 import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Optional;
 
 import org.junit.jupiter.api.Test;
 
@@ -34,4 +36,65 @@ class NumberEvalHelperTest {
         
assertThat(NumberEvalHelper.getBigDecimalOrNull(10000000000.5D)).isEqualTo(new 
BigDecimal("10000000000.5"));
     }
 
+    @Test
+    void coerceIntegerNumber_withBigDecimal() {
+        //Verifies that BigDecimal values are truncated (not rounded) when 
coerced to integers.
+        Optional<Integer> result = NumberEvalHelper.coerceIntegerNumber(new 
BigDecimal("99.99"));
+        assertThat(result).isPresent();
+        assertThat(result.get()).isEqualTo(99);
+
+        Optional<Integer> result1 = NumberEvalHelper.coerceIntegerNumber(new 
BigDecimal("99.00001"));
+        assertThat(result1).isPresent();
+        assertThat(result1.get()).isEqualTo(99);
+    }
+
+    @Test
+    void coerceIntegerNumber_withBigInteger() {
+        Optional<Integer> result = NumberEvalHelper.coerceIntegerNumber(new 
BigInteger("1000"));
+        assertThat(result).isPresent();
+        assertThat(result.get()).isEqualTo(1000);
+    }
+
+    @Test
+    void coerceIntegerNumber_withDouble() {
+        Optional<Integer> result = NumberEvalHelper.coerceIntegerNumber(42.50);
+        assertThat(result).isPresent();
+        assertThat(result.get()).isEqualTo(42);
+
+        Optional<Integer> result1 = 
NumberEvalHelper.coerceIntegerNumber(42.009 );
+        assertThat(result1).isPresent();
+        assertThat(result1.get()).isEqualTo(42);
+
+        Optional<Integer> result2 = 
NumberEvalHelper.coerceIntegerNumber(42.99999 );
+        assertThat(result2).isPresent();
+        assertThat(result2.get()).isEqualTo(42);
+    }
+
+    @Test
+    void coerceIntegerNumber_withString() {
+        // Verifies that a non-numeric input such as a String returns 
Optional.empty()
+        Optional<Integer> result = NumberEvalHelper.coerceIntegerNumber("123");
+        assertThat(result).isEmpty();
+    }
+
+    @Test
+    void coerceIntegerNumber_withInteger() {
+        Optional<Integer> result = NumberEvalHelper.coerceIntegerNumber(42);
+        assertThat(result).isPresent();
+        assertThat(result.get()).isEqualTo(42);
+    }
+
+    @Test
+    void coerceIntegerNumber_withLong() {
+        Optional<Integer> result = NumberEvalHelper.coerceIntegerNumber(423L);
+        assertThat(result).isPresent();
+        assertThat(result.get()).isEqualTo(423);
+    }
+
+    @Test
+    void coerceIntegerNumber_withNull() {
+        Optional<Integer> result = NumberEvalHelper.coerceIntegerNumber(null);
+        assertThat(result).isEmpty();
+    }
+
 }


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

Reply via email to