This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch camel-4.4.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-4.4.x by this push:
     new 9df80f9f47d CAMEL-21109: Make comparing numbers and floating numbers 
in typeCoerce work better with better support for float type also. (#15281)
9df80f9f47d is described below

commit 9df80f9f47dddcc7f4c55144b75da00a7b2d4b4a
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Fri Aug 23 06:59:27 2024 +0200

    CAMEL-21109: Make comparing numbers and floating numbers in typeCoerce work 
better with better support for float type also. (#15281)
---
 .../camel/converter/TypeCoerceCompareTest.java     | 330 +++++++++++++++++++++
 .../org/apache/camel/support/ObjectHelper.java     |  29 +-
 2 files changed, 355 insertions(+), 4 deletions(-)

diff --git 
a/core/camel-core/src/test/java/org/apache/camel/converter/TypeCoerceCompareTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/converter/TypeCoerceCompareTest.java
new file mode 100644
index 00000000000..8d0695fafa7
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/converter/TypeCoerceCompareTest.java
@@ -0,0 +1,330 @@
+/*
+ * 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.apache.camel.converter;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.support.ObjectHelper;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class TypeCoerceCompareTest extends ContextTestSupport {
+
+    @Test
+    public void testCompareStringString() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", "7") > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", "7.5") > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", "40") == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7", "40") < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.5", "40") < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.5", "7.5") == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.5", "7.5") == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.0", "7") == 0);
+    }
+
+    @Test
+    public void testCompareStringInteger() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", 7) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", 40) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7", 40) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.5", 40) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.0", 7) == 0);
+    }
+
+    @Test
+    public void testCompareStringLong() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", 7L) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", 40L) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7", 40L) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.5", 40L) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.0", 7L) == 0);
+    }
+
+    @Test
+    public void testCompareStringDouble() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", 7d) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", 7.5d) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", 40d) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7", 40d) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.5", 40d) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.5", 7.5d) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.5", 7.5d) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.0", 7d) == 0);
+    }
+
+    @Test
+    public void testCompareStringFloat() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", 7f) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", 7.5f) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "40", 40f) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7", 40f) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.5", 40f) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.5", 7.5f) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.5", 7.5f) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, "7.0", 7f) == 0);
+    }
+
+    @Test
+    public void testCompareIntegerString() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40, "7") > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40, "7.5") > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40, "40") == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, "40") < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, "7.5") < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, "7") == 0);
+    }
+
+    @Test
+    public void testCompareLongString() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40L, "7") > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40L, "7.5") > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40L, "40") == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, "40") < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, "7.5") < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, "7") == 0);
+    }
+
+    @Test
+    public void testCompareDoubleString() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40d, "7") > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40.5d, "7.5") > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40d, "40") == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7d, "40.5") < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.5d, "40") < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.5d, "7.5") == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.5d, "7.5") == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.0d, "7") == 0);
+    }
+
+    @Test
+    public void testCompareFloatString() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40f, "7") > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40.5f, "7.5") > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40f, "40") == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7f, "40.5") < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.5f, "40") < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.5f, "7.5") == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.5f, "7.5") == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.0f, "7") == 0);
+    }
+
+    @Test
+    public void testCompareIntegerInteger() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40, 7) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40, 40) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, 40) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8, 40) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, 7) == 0);
+    }
+
+    @Test
+    public void testCompareLongLong() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40L, 7L) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40L, 40L) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, 40L) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8L, 40L) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, 7L) == 0);
+    }
+
+    @Test
+    public void testCompareIntegerLong() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40, 7L) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40, 40L) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, 40L) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8, 40L) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, 7L) == 0);
+    }
+
+    @Test
+    public void testCompareLongInteger() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40L, 7) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40L, 40) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, 40) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8L, 40) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, 7) == 0);
+    }
+
+    @Test
+    public void testCompareDoubleInteger() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40.5d, 7) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40d, 40) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.5d, 40) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8d, 40) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7d, 7) == 0);
+    }
+
+    @Test
+    public void testCompareIntegerDouble() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40, 7.5d) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40, 40.0d) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, 40d) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8, 40d) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, 7d) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, 7.0d) == 0);
+    }
+
+    @Test
+    public void testCompareDoubleLong() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40.5d, 7L) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40d, 40L) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.5d, 40L) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8d, 40L) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7d, 7L) == 0);
+    }
+
+    @Test
+    public void testCompareLongDouble() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40L, 7.5d) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40L, 40d) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, 40.5d) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8L, 40d) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, 7d) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, 7.0d) == 0);
+    }
+
+    @Test
+    public void testCompareFloatInteger() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40.5f, 7) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40f, 40) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.5f, 40) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8f, 40) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7f, 7) == 0);
+    }
+
+    @Test
+    public void testCompareIntegerFloat() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40, 7.5f) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40, 40f) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, 40.0f) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8, 40f) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7, 7.0f) == 0);
+    }
+
+    @Test
+    public void testCompareFloatLong() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40.5f, 7L) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40f, 40L) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7.5f, 40L) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8f, 40L) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7f, 7L) == 0);
+    }
+
+    @Test
+    public void testCompareLongFloat() {
+        TypeConverter tc = context.getTypeConverter();
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40L, 7.5f) > 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 40L, 40.0f) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, 40f) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 8L, 40f) < 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, 7f) == 0);
+        assertTrue(ObjectHelper.typeCoerceCompare(tc, 7L, 7.0f) == 0);
+    }
+
+    @Test
+    public void testPredicate() throws Exception {
+        getMockEndpoint("mock:match").expectedBodiesReceived("40", "8", "7.5", 
41f, 8f, 7.5f);
+        getMockEndpoint("mock:other").expectedBodiesReceived("6", "1", 5f, 2f);
+
+        // string
+        template.sendBody("direct:start", "40");
+        template.sendBody("direct:start", "8");
+        template.sendBody("direct:start", "7.5");
+        template.sendBody("direct:start", "6");
+        template.sendBody("direct:start", "1");
+
+        // float
+        template.sendBody("direct:start", 41f);
+        template.sendBody("direct:start", 8f);
+        template.sendBody("direct:start", 7.5f);
+        template.sendBody("direct:start", 5f);
+        template.sendBody("direct:start", 2f);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testPredicate2() throws Exception {
+        getMockEndpoint("mock:match2").expectedBodiesReceived("40", "8", 
"7.0", 41f, 8f, 7.0f);
+        getMockEndpoint("mock:other2").expectedBodiesReceived("6", "1", 5f, 
2f);
+
+        // string
+        template.sendBody("direct:start2", "40");
+        template.sendBody("direct:start2", "8");
+        template.sendBody("direct:start2", "7.0");
+        template.sendBody("direct:start2", "6");
+        template.sendBody("direct:start2", "1");
+
+        // float
+        template.sendBody("direct:start2", 41f);
+        template.sendBody("direct:start2", 8f);
+        template.sendBody("direct:start2", 7.0f);
+        template.sendBody("direct:start2", 5f);
+        template.sendBody("direct:start2", 2f);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .setProperty("left", simple("${body}"))
+                    .setProperty("right", simple("7.5"))
+                    .choice()
+                        .when(simple("${exchangeProperty.left} >= 
${exchangeProperty.right}"))
+                            .to("mock:match")
+                        .otherwise()
+                            .to("mock:other")
+                        .end();
+
+                from("direct:start2")
+                    .setProperty("left", simple("${body}"))
+                    .setProperty("right", simple("7"))
+                    .choice()
+                        .when(simple("${exchangeProperty.left} >= 
${exchangeProperty.right}"))
+                            .to("mock:match2")
+                        .otherwise()
+                            .to("mock:other2")
+                        .end();
+            }
+        };
+    }
+}
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java 
b/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java
index 3c0d30cb902..3b4cc9fb02f 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java
@@ -264,12 +264,25 @@ public final class ObjectHelper {
         if (leftValue instanceof String && rightValue instanceof String) {
             String leftNum = (String) leftValue;
             String rightNum = (String) rightValue;
-            if (isNumber(leftNum) && isNumber(rightNum)) {
-                // favour to use numeric comparison
-                Long num1 = Long.parseLong(leftNum);
-                Long num2 = Long.parseLong(rightNum);
+            // prioritize non-floating numbers first
+            Long num1 = isNumber(leftNum) ? Long.parseLong(leftNum) : null;
+            Long num2 = isNumber(rightNum) ? Long.parseLong(rightNum) : null;
+            Double dec1 = num1 == null && isFloatingNumber(leftNum) ? 
Double.parseDouble(leftNum) : null;
+            Double dec2 = num2 == null && isFloatingNumber(rightNum) ? 
Double.parseDouble(rightNum) : null;
+            if (num1 != null && num2 != null) {
                 return num1.compareTo(num2);
+            } else if (dec1 != null && dec2 != null) {
+                return dec1.compareTo(dec2);
             }
+            // okay mixed but we need to convert to floating
+            if (num1 != null && dec2 != null) {
+                dec1 = Double.parseDouble(leftNum);
+                return dec1.compareTo(dec2);
+            } else if (num2 != null && dec1 != null) {
+                dec2 = Double.parseDouble(rightNum);
+                return dec1.compareTo(dec2);
+            }
+            // fallback to string comparison
             return leftNum.compareTo(rightNum);
         } else if (leftValue instanceof Integer && rightValue instanceof 
Integer) {
             Integer leftNum = (Integer) leftValue;
@@ -283,6 +296,10 @@ public final class ObjectHelper {
             Double leftNum = (Double) leftValue;
             Double rightNum = (Double) rightValue;
             return leftNum.compareTo(rightNum);
+        } else if (leftValue instanceof Float && rightValue instanceof Float) {
+            Float leftNum = (Float) leftValue;
+            Float rightNum = (Float) rightValue;
+            return leftNum.compareTo(rightNum);
         } else if ((rightValue instanceof Integer || rightValue instanceof 
Long) &&
                 leftValue instanceof String && isNumber((String) leftValue)) {
             if (rightValue instanceof Integer) {
@@ -309,6 +326,10 @@ public final class ObjectHelper {
             Double leftNum = Double.valueOf((String) leftValue);
             Double rightNum = (Double) rightValue;
             return leftNum.compareTo(rightNum);
+        } else if (rightValue instanceof Float rightNum && leftValue 
instanceof String
+                && isFloatingNumber((String) leftValue)) {
+            Float leftNum = Float.valueOf((String) leftValue);
+            return leftNum.compareTo(rightNum);
         } else if (rightValue instanceof Boolean && leftValue instanceof 
String) {
             Boolean leftBool = Boolean.valueOf((String) leftValue);
             Boolean rightBool = (Boolean) rightValue;

Reply via email to