You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2026/10/06 06:11:37 UTC

(camel) branch fix/CAMEL-25366 created (now d520057508ce)

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

davsclaus pushed a change to branch fix/CAMEL-25366
in repository https://gitbox.apache.org/repos/asf/camel.git


      at d520057508ce CAMEL-25366: camel-core - Type converter from String or Number to BigDecimal

This branch includes the following new commits:

     new d520057508ce CAMEL-25366: camel-core - Type converter from String or Number to BigDecimal

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(camel) 01/01: CAMEL-25366: camel-core - Type converter from String or Number to BigDecimal

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit d520057508cecfd412b89bf96ee7a8a4af2fc2c0
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Oct 6 08:11:24 2026 +0200

    CAMEL-25366: camel-core - Type converter from String or Number to BigDecimal
    
    There was no type converter to BigDecimal, so converting the String "1000.01" returned null and
    simple ${bodyAs(java.math.BigDecimal)}, ${convertTo(${body}, java.math.BigDecimal)} and
    resultType BigDecimal were empty. Add toBigDecimal next to toBigInteger; a double or float is
    converted from its decimal text.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <no...@anthropic.com>
    Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
 .../converter/CamelBaseBulkConverterLoader.java    | 16 ++++++++++++-
 .../apache/camel/converter/ObjectConverter.java    | 26 ++++++++++++++++++++++
 .../camel/converter/ObjectConverterTest.java       | 17 ++++++++++++++
 .../apache/camel/language/simple/SimpleTest.java   | 10 +++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc    |  4 ++++
 5 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/core/camel-base/src/generated/java/org/apache/camel/converter/CamelBaseBulkConverterLoader.java b/core/camel-base/src/generated/java/org/apache/camel/converter/CamelBaseBulkConverterLoader.java
index 5fd9e96156ac..ff3ecc3fad1a 100644
--- a/core/camel-base/src/generated/java/org/apache/camel/converter/CamelBaseBulkConverterLoader.java
+++ b/core/camel-base/src/generated/java/org/apache/camel/converter/CamelBaseBulkConverterLoader.java
@@ -41,7 +41,7 @@ public final class CamelBaseBulkConverterLoader implements TypeConverterLoader,
 
     @Override
     public int size() {
-        return 129;
+        return 130;
     }
 
     @Override
@@ -371,6 +371,15 @@ public final class CamelBaseBulkConverterLoader implements TypeConverterLoader,
             if (value instanceof java.lang.StringBuilder) {
                 return org.apache.camel.converter.ObjectConverter.toString((java.lang.StringBuilder) value);
             }
+        } else if (to == java.math.BigDecimal.class) {
+            if (value instanceof java.lang.Object) {
+                Object obj = org.apache.camel.converter.ObjectConverter.toBigDecimal(value);
+                if (obj == null) {
+                    return Void.class;
+                } else {
+                    return obj;
+                }
+            }
         } else if (to == java.math.BigInteger.class) {
             if (value instanceof java.lang.Object) {
                 Object obj = org.apache.camel.converter.ObjectConverter.toBigInteger(value);
@@ -612,6 +621,7 @@ public final class CamelBaseBulkConverterLoader implements TypeConverterLoader,
         registry.addConverter(new TypeConvertible<>(java.lang.StringBuffer.class, java.lang.String.class), this);
         registry.addConverter(new TypeConvertible<>(java.io.ByteArrayOutputStream.class, java.lang.String.class), this);
         registry.addConverter(new TypeConvertible<>(java.lang.StringBuilder.class, java.lang.String.class), this);
+        registry.addConverter(new TypeConvertible<>(java.lang.Object.class, java.math.BigDecimal.class), this);
         registry.addConverter(new TypeConvertible<>(java.lang.Object.class, java.math.BigInteger.class), this);
         registry.addConverter(new TypeConvertible<>(java.lang.CharSequence.class, java.net.URI.class), this);
         registry.addConverter(new TypeConvertible<>(byte[].class, java.nio.ByteBuffer.class), this);
@@ -944,6 +954,10 @@ public final class CamelBaseBulkConverterLoader implements TypeConverterLoader,
             if (from == java.lang.StringBuilder.class) {
                 return this;
             }
+        } else if (to == java.math.BigDecimal.class) {
+            if (from == java.lang.Object.class) {
+                return this;
+            }
         } else if (to == java.math.BigInteger.class) {
             if (from == java.lang.Object.class) {
                 return this;
diff --git a/core/camel-base/src/main/java/org/apache/camel/converter/ObjectConverter.java b/core/camel-base/src/main/java/org/apache/camel/converter/ObjectConverter.java
index 9c3bc24cfde7..c06ed01e9a4d 100644
--- a/core/camel-base/src/main/java/org/apache/camel/converter/ObjectConverter.java
+++ b/core/camel-base/src/main/java/org/apache/camel/converter/ObjectConverter.java
@@ -353,4 +353,30 @@ public final class ObjectConverter {
         return toNumber(str);
     }
 
+    /**
+     * Returns the converted value, or null if the value is null
+     */
+    @Converter(order = 41, allowNull = true)
+    public static BigDecimal toBigDecimal(Object value) {
+        if (org.apache.camel.util.ObjectHelper.isNaN(value)) {
+            return null;
+        }
+        if (value instanceof String str) {
+            return new BigDecimal(str);
+        }
+
+        if (value instanceof BigDecimal bd) {
+            return bd;
+        } else if (value instanceof BigInteger bi) {
+            return new BigDecimal(bi);
+        } else if (value instanceof Double || value instanceof Float) {
+            // use the decimal text of the value, as the binary value of 0.1 is not exactly 0.1
+            return new BigDecimal(value.toString());
+        } else if (value instanceof Number number) {
+            return BigDecimal.valueOf(number.longValue());
+        } else {
+            return null;
+        }
+    }
+
 }
diff --git a/core/camel-core/src/test/java/org/apache/camel/converter/ObjectConverterTest.java b/core/camel-core/src/test/java/org/apache/camel/converter/ObjectConverterTest.java
index e818aee68263..28b68040aef8 100644
--- a/core/camel-core/src/test/java/org/apache/camel/converter/ObjectConverterTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/converter/ObjectConverterTest.java
@@ -153,6 +153,23 @@ public class ObjectConverterTest {
         assertEquals(BigInteger.ONE, ObjectConverter.toBigInteger(1.9d));
     }
 
+    @Test
+    public void testToBigDecimal() {
+        assertEquals(new BigDecimal("1000.01"), ObjectConverter.toBigDecimal("1000.01"));
+        assertEquals(new BigDecimal("4"), ObjectConverter.toBigDecimal("4"));
+        assertEquals(BigDecimal.valueOf(4), ObjectConverter.toBigDecimal(Integer.valueOf("4")));
+        assertEquals(BigDecimal.valueOf(4), ObjectConverter.toBigDecimal(Long.valueOf("4")));
+        assertEquals(new BigDecimal("14350442579497085228"),
+                ObjectConverter.toBigDecimal(new BigInteger("14350442579497085228")));
+        // the decimal text of the value, not the exact binary value of the double or float
+        assertEquals(new BigDecimal("0.1"), ObjectConverter.toBigDecimal(0.1d));
+        assertEquals(new BigDecimal("0.1"), ObjectConverter.toBigDecimal(0.1f));
+        assertNull(ObjectConverter.toBigDecimal(new Date()));
+        assertNull(ObjectConverter.toBigDecimal(Double.NaN));
+        assertNull(ObjectConverter.toBigDecimal(Float.NaN));
+        assertThrows(NumberFormatException.class, () -> ObjectConverter.toBigDecimal("abc"));
+    }
+
     @Test
     public void testToString() {
         assertEquals("ABC", ObjectConverter.toString(new StringBuffer("ABC")));
diff --git a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
index 67f3b96d87de..3e29ee9a5e56 100644
--- a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
@@ -19,6 +19,7 @@ package org.apache.camel.language.simple;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.util.ArrayList;
@@ -679,6 +680,15 @@ public class SimpleTest extends LanguageTestSupport {
         assertIsInstanceOf(ClassNotFoundException.class, e.getCause());
     }
 
+    @Test
+    public void testBodyAsBigDecimal() {
+        exchange.getIn().setBody("1000.01");
+        assertExpression("${bodyAs(java.math.BigDecimal)}", new BigDecimal("1000.01"));
+        assertExpression("${convertTo(${body}, java.math.BigDecimal)}", new BigDecimal("1000.01"));
+        Expression expression = context.resolveLanguage("simple").createExpression("${body}");
+        assertEquals(new BigDecimal("1000.01"), expression.evaluate(exchange, BigDecimal.class));
+    }
+
     @Test
     public void testMandatoryBodyAs() {
         assertExpression("${mandatoryBodyAs(String)}", "<hello id='m123'>world!</hello>");
diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 0eaa9c32cd09..f944390839d6 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -1283,6 +1283,10 @@ interfaces are tried before the super class at each level, and `java.lang.Object
 * Converting a `String` to a `Number` now returns an `Integer` for all values within the `Integer` range
 (including `Integer.MAX_VALUE`, which returned a `Long` before), and supports exponent notation such as `1e5`.
 * Converting a `BigDecimal`, or a `double` larger than a `long`, to `BigInteger` no longer loses precision.
+* A `String` or a `Number` can now be converted to `BigDecimal`. There was no such type converter before, so the
+conversion returned `null`: `${bodyAs(java.math.BigDecimal)}` was empty for a body of `"1000.01"`, and a bean method
+with a `BigDecimal` parameter could not be called with a `String` body. A `double` or `float` is converted from its
+decimal text, so `0.1` becomes `0.1`.
 * Converting a `byte[]` to `char` no longer sign-extends bytes above 127.
 * Converting a `String` to `ByteBuffer` now uses the charset from the `CamelCharsetName` header or exchange
 property (like the other converters), and falls back to the default charset.