This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-3.22.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-3.22.x by this push:
new fb4f6a75089 CAMEL-21109: Make comparing numbers and floating numbers
in typeCoerce work better with better support for float type also. (#15281)
fb4f6a75089 is described below
commit fb4f6a75089933785464ab52b4621c66e66dea88
Author: Claus Ibsen <[email protected]>
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 | 30 +-
2 files changed, 356 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 c48d6a183e4..eb9a8c80a26 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
@@ -193,12 +193,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;
@@ -212,6 +225,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) {
@@ -238,6 +255,11 @@ public final class ObjectHelper {
Double leftNum = Double.valueOf((String) leftValue);
Double rightNum = (Double) rightValue;
return leftNum.compareTo(rightNum);
+ } else if (rightValue instanceof Float && leftValue instanceof String
+ && isFloatingNumber((String) leftValue)) {
+ Float leftNum = Float.valueOf((String) leftValue);
+ Float rightNum = (Float) rightValue;
+ return leftNum.compareTo(rightNum);
} else if (rightValue instanceof Boolean && leftValue instanceof
String) {
Boolean leftBool = Boolean.valueOf((String) leftValue);
Boolean rightBool = (Boolean) rightValue;