From e14c345aa0487520909b0bb98716e5a3581cac0f Mon Sep 17 00:00:00 2001
From: Thomas Mortagne <thomas.mortagne@gmail.com>
Date: Thu, 28 Oct 2021 09:01:38 +0200
Subject: [PATCH] XWIKI-19053: NumberProperty should automatically convert
 values

---
 .../com/xpn/xwiki/objects/DoubleProperty.java |   2 +-
 .../com/xpn/xwiki/objects/FloatProperty.java  |   2 +-
 .../xpn/xwiki/objects/IntegerProperty.java    |   2 +-
 .../com/xpn/xwiki/objects/LongProperty.java   |   2 +-
 .../com/xpn/xwiki/objects/NumberProperty.java |  58 +++++++-
 .../xpn/xwiki/objects/NumberPropertyTest.java | 128 +++++++++++-------
 6 files changed, 133 insertions(+), 61 deletions(-)

diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/DoubleProperty.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/DoubleProperty.java
index 6651b358fe6..d84265ca0b9 100644
--- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/DoubleProperty.java
+++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/DoubleProperty.java
@@ -19,7 +19,7 @@
  */
 package com.xpn.xwiki.objects;
 
-public class DoubleProperty extends NumberProperty
+public class DoubleProperty extends NumberProperty<Double>
 {
     private static final long serialVersionUID = 1L;
 }
diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/FloatProperty.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/FloatProperty.java
index 23104e2f3fa..c2f67fd3c47 100644
--- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/FloatProperty.java
+++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/FloatProperty.java
@@ -19,7 +19,7 @@
  */
 package com.xpn.xwiki.objects;
 
-public class FloatProperty extends NumberProperty
+public class FloatProperty extends NumberProperty<Float>
 {
     private static final long serialVersionUID = 1L;
 }
diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/IntegerProperty.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/IntegerProperty.java
index ce695bc4b1e..6557f370c93 100644
--- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/IntegerProperty.java
+++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/IntegerProperty.java
@@ -19,7 +19,7 @@
  */
 package com.xpn.xwiki.objects;
 
-public class IntegerProperty extends NumberProperty
+public class IntegerProperty extends NumberProperty<Integer>
 {
     private static final long serialVersionUID = 1L;
 }
diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/LongProperty.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/LongProperty.java
index b4d6028255a..03551c75c57 100644
--- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/LongProperty.java
+++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/LongProperty.java
@@ -19,7 +19,7 @@
  */
 package com.xpn.xwiki.objects;
 
-public class LongProperty extends NumberProperty
+public class LongProperty extends NumberProperty<Long>
 {
     private static final long serialVersionUID = 1L;
 }
diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/NumberProperty.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/NumberProperty.java
index 1bf1ed20b49..db0b3aa721a 100644
--- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/NumberProperty.java
+++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/NumberProperty.java
@@ -19,17 +19,25 @@
  */
 package com.xpn.xwiki.objects;
 
+import java.lang.reflect.ParameterizedType;
+
 import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.xwiki.component.util.ReflectionUtils;
 
-public abstract class NumberProperty extends BaseProperty
+public abstract class NumberProperty<N extends Number> extends BaseProperty
 {
     private static final long serialVersionUID = 1L;
 
-    private Number value;
+    private N value;
+
+    private Class<N> numberClass;
 
     public NumberProperty()
     {
+        ParameterizedType genericType =
+            (ParameterizedType) ReflectionUtils.resolveType(NumberProperty.class, getClass());
+        this.numberClass = ReflectionUtils.getTypeClass(genericType.getActualTypeArguments()[0]);
     }
 
     @Override
@@ -41,8 +49,49 @@ public Object getValue()
     @Override
     public void setValue(Object value)
     {
+        N number = convert(value);
+
         setValueDirty(value);
-        this.value = (Number) value;
+        this.value = number;
+    }
+
+    private N convert(Object value)
+    {
+        N number = null;
+
+        if (value != null) {
+            if (this.numberClass == value.getClass()) {
+                number = (N) value;
+            } else {
+                if (this.numberClass == Double.class) {
+                    if (value instanceof Number) {
+                        number = (N) (Double) ((Number) value).doubleValue();
+                    } else {
+                        number = (N) Double.valueOf(value.toString());
+                    }
+                } else if (this.numberClass == Float.class) {
+                    if (value instanceof Number) {
+                        number = (N) (Float) ((Number) value).floatValue();
+                    } else {
+                        number = (N) Float.valueOf(value.toString());
+                    }
+                } else if (this.numberClass == Integer.class) {
+                    if (value instanceof Number) {
+                        number = (N) (Integer) ((Number) value).intValue();
+                    } else {
+                        number = (N) Integer.valueOf(value.toString());
+                    }
+                } else if (this.numberClass == Long.class) {
+                    if (value instanceof Number) {
+                        number = (N) (Long) ((Number) value).longValue();
+                    } else {
+                        number = (N) Long.valueOf(value.toString());
+                    }
+                }
+            }
+        }
+
+        return number;
     }
 
     @Override
@@ -59,8 +108,7 @@ public boolean equals(Object obj)
             return false;
         }
 
-        return new EqualsBuilder().appendSuper(super.equals(obj))
-            .append(getValue(), ((NumberProperty) obj).getValue())
+        return new EqualsBuilder().appendSuper(super.equals(obj)).append(getValue(), ((NumberProperty) obj).getValue())
             .isEquals();
     }
 
diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/test/java/com/xpn/xwiki/objects/NumberPropertyTest.java b/xwiki-platform-core/xwiki-platform-oldcore/src/test/java/com/xpn/xwiki/objects/NumberPropertyTest.java
index 6863e617356..65b2ba86a8f 100644
--- a/xwiki-platform-core/xwiki-platform-oldcore/src/test/java/com/xpn/xwiki/objects/NumberPropertyTest.java
+++ b/xwiki-platform-core/xwiki-platform-oldcore/src/test/java/com/xpn/xwiki/objects/NumberPropertyTest.java
@@ -19,51 +19,39 @@
  */
 package com.xpn.xwiki.objects;
 
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.xwiki.model.internal.reference.LocalStringEntityReferenceSerializer;
-import org.xwiki.test.ComponentManagerRule;
-import org.xwiki.test.annotation.ComponentList;
+import org.junit.jupiter.api.Test;
 
-import com.xpn.xwiki.web.Utils;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Unit tests for {@link NumberProperty}.
  *
  * @version $Id$
- * @since 5.2M1
  */
-@ComponentList({LocalStringEntityReferenceSerializer.class})
-public class NumberPropertyTest
+class NumberPropertyTest
 {
-    @Rule
-    public ComponentManagerRule componentManager = new ComponentManagerRule();
-
-    @Before
-    public void setup()
-    {
-        Utils.setComponentManager(this.componentManager);
-    }
-
     /**
      * Verify that we can compare a null valued number property with a non-null valued number property without having a
      * NPE (<a href="https://jira.xwiki.org/browse/XWIKI-9326">XWIKI-9326</a>).
      */
     @Test
-    public void nullValueEqualsWithOtherNumberProperty()
+    void nullValueEqualsWithOtherNumberProperty()
     {
-        NumberProperty nullValueProperty = new IntegerProperty();
+        IntegerProperty nullValueProperty = new IntegerProperty();
         nullValueProperty.setValue(null);
-        Assert.assertNull(nullValueProperty.getValue());
+        assertNull(nullValueProperty.getValue());
 
-        NumberProperty notNullValueProperty = new IntegerProperty();
+        IntegerProperty notNullValueProperty = new IntegerProperty();
         notNullValueProperty.setValue(1);
-        Assert.assertNotNull(notNullValueProperty.getValue());
+        assertNotNull(notNullValueProperty.getValue());
 
         // Should not throw a NPE.
-        Assert.assertFalse(nullValueProperty.equals(notNullValueProperty));
+        assertFalse(nullValueProperty.equals(notNullValueProperty));
     }
 
     /**
@@ -71,80 +59,116 @@ public void nullValueEqualsWithOtherNumberProperty()
      * NPE (<a href="https://jira.xwiki.org/browse/XWIKI-9326">XWIKI-9326</a>).
      */
     @Test
-    public void notNullValueEqualsWithOtherNullNumberProperty()
+    void notNullValueEqualsWithOtherNullNumberProperty()
     {
-        NumberProperty nullValueProperty = new IntegerProperty();
+        IntegerProperty nullValueProperty = new IntegerProperty();
         nullValueProperty.setValue(1);
-        Assert.assertNotNull(nullValueProperty.getValue());
+        assertNotNull(nullValueProperty.getValue());
 
-        NumberProperty notNullValueProperty = new IntegerProperty();
+        IntegerProperty notNullValueProperty = new IntegerProperty();
         notNullValueProperty.setValue(null);
-        Assert.assertNull(notNullValueProperty.getValue());
+        assertNull(notNullValueProperty.getValue());
 
         // Should not throw a NPE.
-        Assert.assertFalse(nullValueProperty.equals(notNullValueProperty));
+        assertFalse(nullValueProperty.equals(notNullValueProperty));
     }
 
     /**
-     * Verify that we can compare two null valued number properties without having a NPE (<a
-     * href="https://jira.xwiki.org/browse/XWIKI-9326">XWIKI-9326</a>).
+     * Verify that we can compare two null valued number properties without having a NPE
+     * (<a href="https://jira.xwiki.org/browse/XWIKI-9326">XWIKI-9326</a>).
      */
     @Test
-    public void equalNullValueEquals()
+    void equalNullValueEquals()
     {
-        NumberProperty nullValueProperty1 = new IntegerProperty();
+        IntegerProperty nullValueProperty1 = new IntegerProperty();
         nullValueProperty1.setValue(null);
-        Assert.assertNull(nullValueProperty1.getValue());
+        assertNull(nullValueProperty1.getValue());
 
-        NumberProperty nullValueProperty2 = new IntegerProperty();
+        IntegerProperty nullValueProperty2 = new IntegerProperty();
         nullValueProperty2.setValue(null);
-        Assert.assertNull(nullValueProperty2.getValue());
+        assertNull(nullValueProperty2.getValue());
 
         // Should not throw a NPE.
-        Assert.assertTrue(nullValueProperty1.equals(nullValueProperty2));
+        assertTrue(nullValueProperty1.equals(nullValueProperty2));
     }
 
     /**
      * Two equal non-null values.
      */
     @Test
-    public void equalNotNullValues()
+    void equalNotNullValues()
     {
-        NumberProperty nullValueProperty = new IntegerProperty();
+        IntegerProperty nullValueProperty = new IntegerProperty();
         nullValueProperty.setValue(1);
 
-        NumberProperty notNullValueProperty = new IntegerProperty();
+        IntegerProperty notNullValueProperty = new IntegerProperty();
         notNullValueProperty.setValue(1);
 
-        Assert.assertTrue(nullValueProperty.equals(notNullValueProperty));
+        assertTrue(nullValueProperty.equals(notNullValueProperty));
     }
 
     /**
      * Two not equal non-null values.
      */
     @Test
-    public void notEqualNonNullValues()
+    void notEqualNonNullValues()
     {
-        NumberProperty nullValueProperty = new IntegerProperty();
+        IntegerProperty nullValueProperty = new IntegerProperty();
         nullValueProperty.setValue(0);
 
-        NumberProperty notNullValueProperty = new IntegerProperty();
+        IntegerProperty notNullValueProperty = new IntegerProperty();
         notNullValueProperty.setValue(1);
 
-        Assert.assertFalse(nullValueProperty.equals(notNullValueProperty));
+        assertFalse(nullValueProperty.equals(notNullValueProperty));
     }
 
     @Test
-    public void testHashCode()
+    void testHashCode()
     {
         final Number value = 101;
 
-        NumberProperty n1 = new IntegerProperty();
-        NumberProperty n2 = new IntegerProperty();
+        IntegerProperty n1 = new IntegerProperty();
+        IntegerProperty n2 = new IntegerProperty();
 
         n1.setValue(value);
         n2.setValue(value);
 
-        Assert.assertEquals(n1.hashCode(), n2.hashCode());
+        assertEquals(n1.hashCode(), n2.hashCode());
+    }
+
+    @Test
+    void convert()
+    {
+        DoubleProperty doubleProperty = new DoubleProperty();
+        doubleProperty.setValue(1);
+        assertInstanceOf(Double.class, doubleProperty.getValue());
+        assertEquals(1D, doubleProperty.getValue());
+        doubleProperty.setValue("2");
+        assertInstanceOf(Double.class, doubleProperty.getValue());
+        assertEquals(2D, doubleProperty.getValue());
+
+        FloatProperty floatProperty = new FloatProperty();
+        floatProperty.setValue(1);
+        assertInstanceOf(Float.class, floatProperty.getValue());
+        assertEquals(1F, floatProperty.getValue());
+        floatProperty.setValue("2");
+        assertInstanceOf(Float.class, floatProperty.getValue());
+        assertEquals(2F, floatProperty.getValue());
+
+        IntegerProperty integerProperty = new IntegerProperty();
+        integerProperty.setValue(1D);
+        assertInstanceOf(Integer.class, integerProperty.getValue());
+        assertEquals(1, integerProperty.getValue());
+        integerProperty.setValue("2");
+        assertInstanceOf(Integer.class, integerProperty.getValue());
+        assertEquals(2, integerProperty.getValue());
+
+        LongProperty longProperty = new LongProperty();
+        longProperty.setValue(1D);
+        assertInstanceOf(Long.class, longProperty.getValue());
+        assertEquals(1L, longProperty.getValue());
+        longProperty.setValue("2");
+        assertInstanceOf(Long.class, longProperty.getValue());
+        assertEquals(2L, longProperty.getValue());
     }
 }
-- 
GitLab