Repository: primefaces/primefaces (java)

Issue:
InputNumber: `Number` identified as non-decimal
### Describe the bug

a PRO reported an issue related to InputNumberRenderer.isIntegral method. Will we add decimal type checks for Number type?

```java
// InputNumberRenderer.java
private boolean isIntegral(FacesContext context, InputNumber inputNumber, Object value) {
        if (value != null) {
            return value instanceof Long
                    || value instanceof Integer
                    || value instanceof Short
                    || value instanceof BigInteger
                    || value instanceof Byte;
        }

        Class<?> type = getTypeFromValueExpression(context, inputNumber);
        if (type == null) {
            return false;
        }

        return type.isAssignableFrom(Long.class)
                || type.isAssignableFrom(Integer.class)
                || type.isAssignableFrom(Short.class)
                || type.isAssignableFrom(BigInteger.class)
                || type.isAssignableFrom(Byte.class);
    }
```

As you know, java.lang.Number is a superclass of Integer, Long, Short, [...].
Since the upgrade from 11.0.7 to 13.0.8 we face the issue that p:inputNumber defaults to 0 decimalPlaces when using a java.lang.Number (initial value null) as value.
This seems to happen because the check for integral, with a null value, tests for "isAssignableFrom(Integer.class)" etc.
Thus, it returns true, even though java.lang.Number can have decimalPlaces.

### Reproducer

```java
private Number number;
```

```xml
<p:inputNumber value="#{testView.number}" />
```

### Expected behavior

_No response_

### PrimeFaces edition

Community

### PrimeFaces version

13.0.8

### Theme

_No response_

### JSF implementation

Mojarra

### JSF version

2.3

### Java version

11

### Browser(s)

_No response_

Pull request:
Fix #11791: 13.0.9 InputNumber allow Number.class to be decimal
Fix #11791: 13.0.9 InputNumber all Number.class to be decimal

Patch:
diff --git a/primefaces/src/main/java/org/primefaces/component/inputnumber/InputNumberRenderer.java b/primefaces/src/main/java/org/primefaces/component/inputnumber/InputNumberRenderer.java
index de3046ba8d..fec0637774 100644
--- a/primefaces/src/main/java/org/primefaces/component/inputnumber/InputNumberRenderer.java
+++ b/primefaces/src/main/java/org/primefaces/component/inputnumber/InputNumberRenderer.java
@@ -392,7 +392,7 @@ public class InputNumberRenderer extends InputRenderer {
         return formatForPlugin(maximum);
     }
 
-    private boolean isIntegral(FacesContext context, InputNumber inputNumber, Object value) {
+    protected boolean isIntegral(FacesContext context, InputNumber inputNumber, Object value) {
         if (value != null) {
             return value instanceof Long
                     || value instanceof Integer
@@ -402,7 +402,9 @@ public class InputNumberRenderer extends InputRenderer {
         }
 
         Class<?> type = getTypeFromValueExpression(context, inputNumber);
-        if (type == null) {
+
+        // #11791 Number is the superclass for all the types so it could be a decimal
+        if (type == null || type == Number.class) {
             return false;
         }
 


Test patch:
diff --git a/primefaces/src/test/java/org/primefaces/component/inputnumber/InputNumberTest.java b/primefaces/src/test/java/org/primefaces/component/inputnumber/InputNumberTest.java
index 9713f14b59..681f8a17d3 100644
--- a/primefaces/src/test/java/org/primefaces/component/inputnumber/InputNumberTest.java
+++ b/primefaces/src/test/java/org/primefaces/component/inputnumber/InputNumberTest.java
@@ -24,11 +24,17 @@
 package org.primefaces.component.inputnumber;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -43,7 +49,7 @@ import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-public class InputNumberTest {
+class InputNumberTest {
 
     private InputNumberRenderer renderer;
     private FacesContext context;
@@ -53,8 +59,8 @@ public class InputNumberTest {
     private ValueExpression valueExpression;
 
     @BeforeEach
-    public void setup() {
-        renderer = new InputNumberRenderer();
+    void setup() {
+        renderer = spy(new InputNumberRenderer());
         context = mock(FacesContext.class);
         externalContext = mock(ExternalContext.class);
         elContext = mock(ELContext.class);
@@ -68,7 +74,7 @@ public class InputNumberTest {
     }
 
     @AfterEach
-    public void teardown() {
+    void teardown() {
         valueExpression = null;
         inputNumber = null;
         elContext = null;
@@ -197,4 +203,32 @@ public class InputNumberTest {
         Assertions.assertEquals(null, inputNumber.getSubmittedValue());
     }
 
+    @Test
+    void isIntegral() {
+        // values
+        doReturn(BigDecimal.class).when(renderer).getTypeFromValueExpression(context, inputNumber);
+        assertFalse(renderer.isIntegral(context, inputNumber, BigDecimal.valueOf(5.5)));
+        doReturn(Number.class).when(renderer).getTypeFromValueExpression(context, inputNumber);
+        assertFalse(renderer.isIntegral(context, inputNumber, BigDecimal.valueOf(5.5)));
+        doReturn(Number.class).when(renderer).getTypeFromValueExpression(context, inputNumber);
+        assertTrue(renderer.isIntegral(context, inputNumber, Integer.valueOf(3)));
+
+        // nulls
+        doReturn(Integer.class).when(renderer).getTypeFromValueExpression(context, inputNumber);
+        assertTrue(renderer.isIntegral(context, inputNumber, null));
+        doReturn(Short.class).when(renderer).getTypeFromValueExpression(context, inputNumber);
+        assertTrue(renderer.isIntegral(context, inputNumber, null));
+        doReturn(Byte.class).when(renderer).getTypeFromValueExpression(context, inputNumber);
+        assertTrue(renderer.isIntegral(context, inputNumber, null));
+        doReturn(BigInteger.class).when(renderer).getTypeFromValueExpression(context, inputNumber);
+        assertTrue(renderer.isIntegral(context, inputNumber, null));
+        doReturn(Long.class).when(renderer).getTypeFromValueExpression(context, inputNumber);
+        assertTrue(renderer.isIntegral(context, inputNumber, null));
+        doReturn(BigDecimal.class).when(renderer).getTypeFromValueExpression(context, inputNumber);
+        assertFalse(renderer.isIntegral(context, inputNumber, null));
+        // GitHub #11791
+        doReturn(Number.class).when(renderer).getTypeFromValueExpression(context, inputNumber);
+        assertFalse(renderer.isIntegral(context, inputNumber, null));
+    }
+
 }