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

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


The following commit(s) were added to refs/heads/main by this push:
     new a24e8e2e8e9b CAMEL-25366: camel-core - Type converter from String or 
Number to BigDecimal
a24e8e2e8e9b is described below

commit a24e8e2e8e9b02ce432602878c33e191c0799336
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Oct 6 09:35:17 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.
    
    Closes #27402
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../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 9c91357c9d45..12fc32e9a85e 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.

Reply via email to