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 5c7e11efdf65 camel-core - simple languge improve docs and adjust 
size/length functions
5c7e11efdf65 is described below

commit 5c7e11efdf6515da34a22fa3cf2dfd0f4c962421
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun Jan 25 12:06:48 2026 +0100

    camel-core - simple languge improve docs and adjust size/length functions
---
 .../org/apache/camel/catalog/languages/simple.json |  8 +-
 .../language/csimple/joor/OriginalSimpleTest.java  | 34 +++++---
 .../org/apache/camel/language/simple/simple.json   |  8 +-
 .../modules/languages/pages/simple-language.adoc   | 46 +++++++++--
 .../camel/language/csimple/CSimpleHelper.java      | 49 ++++++------
 .../camel/language/simple/SimpleConstants.java     | 11 ++-
 .../language/simple/SimpleExpressionBuilder.java   | 90 +++++++++++-----------
 .../apache/camel/language/simple/SimpleTest.java   | 33 +++++---
 8 files changed, 177 insertions(+), 102 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
index b2dc86943096..347fe36b5013 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
@@ -33,7 +33,7 @@
     "attachmentsHeader(key,name)": { "index": 6, "kind": "function", 
"displayName": "Attachments Header", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
attachment header with the given name.", "ognl": false, "suffix": "}" },
     "attachmentsHeaderAs(key,name,type)": { "index": 7, "kind": "function", 
"displayName": "Attachments Header As", "group": "function", "label": 
"function", "required": false, "javaType": "Object", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The attachment header with the given name, converted to 
the given type.", "ognl": false, "suffix": "}" },
     "attachmentsSize": { "index": 8, "kind": "function", "displayName": 
"Attachments Size", "group": "function", "label": "function", "required": 
false, "javaType": "int", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
number of attachments. Is 0 if there are no attachments.", "ognl": false, 
"suffix": "}" },
-    "average(val...)": { "index": 9, "kind": "function", "displayName": 
"Average Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the average number 
from all the values", "ognl": false, "suffix": "}" },
+    "average(val...)": { "index": 9, "kind": "function", "displayName": 
"Average Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the average number 
from all the values (integral numbers only).", "ognl": false, "suffix": "}" },
     "base64Decode(exp)": { "index": 10, "kind": "function", "displayName": 
"Base64 Decode", "group": "function", "label": "function", "required": false, 
"javaType": "byte[]", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 decodes the 
message body (or expression)", "ognl": false, "suffix": "}" },
     "base64Encode(exp)": { "index": 11, "kind": "function", "displayName": 
"Base64 Encode", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 encodes the 
message body (or expression)", "ognl": false, "suffix": "}" },
     "bean(name.method)": { "index": 12, "kind": "function", "displayName": 
"Call Java Bean", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Calls a Java bean. The 
name of the bean can also refer to a class name using type prefix as follows 
`bean:type:com.foo.MyClass`. If no method name is given then Camel will 
automatic attempt to find the b [...]
@@ -81,11 +81,11 @@
     "lowercase(exp)": { "index": 54, "kind": "function", "displayName": 
"Lowercase", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Lowercases the message 
body (or expression)", "ognl": false, "suffix": "}" },
     "mandatoryBodyAs(type)": { "index": 55, "kind": "function", "displayName": 
"Mandatory Body As", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Converts the message body to the given type (classname). If the body is null 
then the function will fail with an exception", "ognl": true, "suffix": "}" },
     "map(key1,value1,...)": { "index": 56, "kind": "function", "displayName": 
"Create Map of pairs", "group": "function", "label": "function", "required": 
false, "javaType": "java.util.LinkedHashMap", "prefix": "${", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The map function creates a LinkedHashMap with the given set of 
pairs.", "ognl": false, "suffix": "}" },
-    "max(val...)": { "index": 57, "kind": "function", "displayName": "Maximum 
Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the maximum number 
from all the values", "ognl": false, "suffix": "}" },
+    "max(val...)": { "index": 57, "kind": "function", "displayName": "Maximum 
Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the maximum number 
from all the values (integral numbers only).", "ognl": false, "suffix": "}" },
     "messageAs(type)": { "index": 58, "kind": "function", "displayName": 
"Message As", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the message 
to the given type (classname).", "ognl": true, "suffix": "}" },
     "messageHistory(boolean)": { "index": 59, "kind": "function", 
"displayName": "Print Message History", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The message history of the current exchange (how it has 
been routed). This is similar to the route stack-trace message history the 
error handler logs in case of an unhandled exception. The b [...]
     "messageTimestamp": { "index": 60, "kind": "function", "displayName": 
"Message Timestamp", "group": "function", "label": "function", "required": 
false, "javaType": "long", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
message timestamp (millis since epoc) that this message originates from. Some 
systems like JMS, Kafka, AWS have a timestamp on the event\/message that Camel 
received. This method returns the timestam [...]
-    "min(val...)": { "index": 61, "kind": "function", "displayName": "Minimum 
Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the minimum number 
from all the values", "ognl": false, "suffix": "}" },
+    "min(val...)": { "index": 61, "kind": "function", "displayName": "Minimum 
Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the minimum number 
from all the values (integral numbers only).", "ognl": false, "suffix": "}" },
     "newEmpty(type)": { "index": 62, "kind": "function", "displayName": 
"Create Empty Object", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Creates a new empty object (decided by type). Use `string` to create an empty 
String. Use `list` to create an empty `java.util.ArrayList`. Use `map` to 
create an empty `java.util.LinkedHashMap`. Use `s [...]
     "not": { "index": 63, "kind": "function", "displayName": "Not", "group": 
"function", "label": "function", "required": false, "javaType": "boolean", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Evaluates the predicate and returns the 
opposite.", "ognl": false, "suffix": "}" },
     "null": { "index": 64, "kind": "function", "displayName": "Null", "group": 
"function", "label": "function", "required": false, "javaType": "Object", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Represents a null value", "ognl": false, 
"suffix": "}" },
@@ -104,7 +104,7 @@
     "setHeader(name,type,exp)": { "index": 77, "kind": "function", 
"displayName": "Set Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a message header with the given expression (optional converting to the 
given type)", "ognl": false, "suffix": "}" },
     "setVariable(name,type,exp)": { "index": 78, "kind": "function", 
"displayName": "Set Variable", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a variable with the given expression (optional converting to the given 
type)", "ognl": false, "suffix": "}" },
     "shuffle(val...)": { "index": 79, "kind": "function", "displayName": 
"Shuffle Values", "group": "function", "label": "function", "required": false, 
"javaType": "List", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a list of all the 
values shuffled in random order", "ognl": false, "suffix": "}" },
-    "size(exp)": { "index": 80, "kind": "function", "displayName": "Size", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The size of the message body (or expression). 
If the payload is java.util.Collection or java.util.Map based then the size is 
the number of elements; otherwise the payload size in bytes.", "ognl": false, 
"suffix": "}" },
+    "size(exp)": { "index": 80, "kind": "function", "displayName": "Size", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Returns the number of elements in collection 
or array based payloads. If the value is null then 0 is returned, otherwise 
1.", "ognl": false, "suffix": "}" },
     "skip(num)": { "index": 81, "kind": "function", "displayName": "Skip First 
Items from the Message Body", "group": "function", "label": "function", 
"required": false, "javaType": "java.util.Iterator", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The skip function iterates the message body and skips 
the first number of items. This can be used with the Splitter EIP to split a 
message body and skip the first N number of  [...]
     "split(exp,separator)": { "index": 82, "kind": "function", "displayName": 
"Split String Values", "group": "function", "label": "function", "required": 
false, "javaType": "String[]", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Splits the message body\/expression as a String value using the separator into 
a String array", "ognl": false, "suffix": "}" },
     "stepId": { "index": 83, "kind": "function", "displayName": "Step Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current step the Exchange is being routed.", "ognl": false, "suffix": "}" },
diff --git 
a/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
 
b/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
index 192be8370c8c..cb0398c87d50 100644
--- 
a/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
+++ 
b/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
@@ -43,6 +43,7 @@ import org.apache.camel.ExpressionIllegalSyntaxException;
 import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.Predicate;
 import org.apache.camel.component.bean.MethodNotFoundException;
+import org.apache.camel.converter.stream.FileInputStreamCache;
 import org.apache.camel.language.bean.RuntimeBeanExpressionException;
 import org.apache.camel.language.csimple.CSimpleLanguage;
 import org.apache.camel.language.simple.SimpleTest;
@@ -2373,25 +2374,29 @@ public class OriginalSimpleTest extends 
LanguageTestSupport {
     public void testSize() {
         exchange.getMessage().setBody(new int[] { 4, 7, 9 });
         Expression expression = 
context.resolveLanguage("csimple").createExpression("${size()}");
-        int len = expression.evaluate(exchange, int.class);
-        assertEquals(3, len);
+        int size = expression.evaluate(exchange, int.class);
+        assertEquals(3, size);
 
         exchange.getMessage().setBody("Hello World");
-        len = expression.evaluate(exchange, int.class);
-        assertEquals(11, len);
+        size = expression.evaluate(exchange, int.class);
+        assertEquals(1, size);
+
+        exchange.getMessage().setBody(null);
+        size = expression.evaluate(exchange, int.class);
+        assertEquals(0, size);
 
         exchange.getMessage().setBody(List.of("A", "B", "C", "D"));
-        len = expression.evaluate(exchange, int.class);
-        assertEquals(4, len);
+        size = expression.evaluate(exchange, int.class);
+        assertEquals(4, size);
 
         exchange.getMessage().setBody(Map.of("A", 1, "B", 2, "C", 3));
-        len = expression.evaluate(exchange, int.class);
-        assertEquals(3, len);
+        size = expression.evaluate(exchange, int.class);
+        assertEquals(3, size);
 
         File f = new File("src/test/resources/log4j2.properties");
         exchange.getMessage().setBody(f);
-        len = expression.evaluate(exchange, int.class);
-        assertEquals(f.length(), len);
+        size = expression.evaluate(exchange, int.class);
+        assertEquals(1, size);
     }
 
     @Test
@@ -2417,6 +2422,11 @@ public class OriginalSimpleTest extends 
LanguageTestSupport {
         exchange.getMessage().setBody(f);
         len = expression.evaluate(exchange, int.class);
         assertEquals(f.length(), len);
+
+        FileInputStreamCache fis = new FileInputStreamCache(f);
+        exchange.getMessage().setBody(fis);
+        len = expression.evaluate(exchange, int.class);
+        assertEquals(f.length(), len);
     }
 
     @Test
@@ -2959,6 +2969,10 @@ public class OriginalSimpleTest extends 
LanguageTestSupport {
         Integer i = expression.evaluate(exchange, Integer.class);
         assertEquals(987, i);
 
+        expression = 
context.resolveLanguage("simple").createExpression("${abs(-5)}");
+        i = expression.evaluate(exchange, Integer.class);
+        assertEquals(5, i);
+
         expression = 
context.resolveLanguage("csimple").createExpression("${abs(${body})}");
         String s = expression.evaluate(exchange, String.class);
         assertEquals("987", s);
diff --git 
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
 
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
index b2dc86943096..347fe36b5013 100644
--- 
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
+++ 
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
@@ -33,7 +33,7 @@
     "attachmentsHeader(key,name)": { "index": 6, "kind": "function", 
"displayName": "Attachments Header", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
attachment header with the given name.", "ognl": false, "suffix": "}" },
     "attachmentsHeaderAs(key,name,type)": { "index": 7, "kind": "function", 
"displayName": "Attachments Header As", "group": "function", "label": 
"function", "required": false, "javaType": "Object", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The attachment header with the given name, converted to 
the given type.", "ognl": false, "suffix": "}" },
     "attachmentsSize": { "index": 8, "kind": "function", "displayName": 
"Attachments Size", "group": "function", "label": "function", "required": 
false, "javaType": "int", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
number of attachments. Is 0 if there are no attachments.", "ognl": false, 
"suffix": "}" },
-    "average(val...)": { "index": 9, "kind": "function", "displayName": 
"Average Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the average number 
from all the values", "ognl": false, "suffix": "}" },
+    "average(val...)": { "index": 9, "kind": "function", "displayName": 
"Average Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the average number 
from all the values (integral numbers only).", "ognl": false, "suffix": "}" },
     "base64Decode(exp)": { "index": 10, "kind": "function", "displayName": 
"Base64 Decode", "group": "function", "label": "function", "required": false, 
"javaType": "byte[]", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 decodes the 
message body (or expression)", "ognl": false, "suffix": "}" },
     "base64Encode(exp)": { "index": 11, "kind": "function", "displayName": 
"Base64 Encode", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 encodes the 
message body (or expression)", "ognl": false, "suffix": "}" },
     "bean(name.method)": { "index": 12, "kind": "function", "displayName": 
"Call Java Bean", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Calls a Java bean. The 
name of the bean can also refer to a class name using type prefix as follows 
`bean:type:com.foo.MyClass`. If no method name is given then Camel will 
automatic attempt to find the b [...]
@@ -81,11 +81,11 @@
     "lowercase(exp)": { "index": 54, "kind": "function", "displayName": 
"Lowercase", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Lowercases the message 
body (or expression)", "ognl": false, "suffix": "}" },
     "mandatoryBodyAs(type)": { "index": 55, "kind": "function", "displayName": 
"Mandatory Body As", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Converts the message body to the given type (classname). If the body is null 
then the function will fail with an exception", "ognl": true, "suffix": "}" },
     "map(key1,value1,...)": { "index": 56, "kind": "function", "displayName": 
"Create Map of pairs", "group": "function", "label": "function", "required": 
false, "javaType": "java.util.LinkedHashMap", "prefix": "${", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The map function creates a LinkedHashMap with the given set of 
pairs.", "ognl": false, "suffix": "}" },
-    "max(val...)": { "index": 57, "kind": "function", "displayName": "Maximum 
Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the maximum number 
from all the values", "ognl": false, "suffix": "}" },
+    "max(val...)": { "index": 57, "kind": "function", "displayName": "Maximum 
Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the maximum number 
from all the values (integral numbers only).", "ognl": false, "suffix": "}" },
     "messageAs(type)": { "index": 58, "kind": "function", "displayName": 
"Message As", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the message 
to the given type (classname).", "ognl": true, "suffix": "}" },
     "messageHistory(boolean)": { "index": 59, "kind": "function", 
"displayName": "Print Message History", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The message history of the current exchange (how it has 
been routed). This is similar to the route stack-trace message history the 
error handler logs in case of an unhandled exception. The b [...]
     "messageTimestamp": { "index": 60, "kind": "function", "displayName": 
"Message Timestamp", "group": "function", "label": "function", "required": 
false, "javaType": "long", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
message timestamp (millis since epoc) that this message originates from. Some 
systems like JMS, Kafka, AWS have a timestamp on the event\/message that Camel 
received. This method returns the timestam [...]
-    "min(val...)": { "index": 61, "kind": "function", "displayName": "Minimum 
Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the minimum number 
from all the values", "ognl": false, "suffix": "}" },
+    "min(val...)": { "index": 61, "kind": "function", "displayName": "Minimum 
Number", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the minimum number 
from all the values (integral numbers only).", "ognl": false, "suffix": "}" },
     "newEmpty(type)": { "index": 62, "kind": "function", "displayName": 
"Create Empty Object", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Creates a new empty object (decided by type). Use `string` to create an empty 
String. Use `list` to create an empty `java.util.ArrayList`. Use `map` to 
create an empty `java.util.LinkedHashMap`. Use `s [...]
     "not": { "index": 63, "kind": "function", "displayName": "Not", "group": 
"function", "label": "function", "required": false, "javaType": "boolean", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Evaluates the predicate and returns the 
opposite.", "ognl": false, "suffix": "}" },
     "null": { "index": 64, "kind": "function", "displayName": "Null", "group": 
"function", "label": "function", "required": false, "javaType": "Object", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Represents a null value", "ognl": false, 
"suffix": "}" },
@@ -104,7 +104,7 @@
     "setHeader(name,type,exp)": { "index": 77, "kind": "function", 
"displayName": "Set Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a message header with the given expression (optional converting to the 
given type)", "ognl": false, "suffix": "}" },
     "setVariable(name,type,exp)": { "index": 78, "kind": "function", 
"displayName": "Set Variable", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a variable with the given expression (optional converting to the given 
type)", "ognl": false, "suffix": "}" },
     "shuffle(val...)": { "index": 79, "kind": "function", "displayName": 
"Shuffle Values", "group": "function", "label": "function", "required": false, 
"javaType": "List", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a list of all the 
values shuffled in random order", "ognl": false, "suffix": "}" },
-    "size(exp)": { "index": 80, "kind": "function", "displayName": "Size", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The size of the message body (or expression). 
If the payload is java.util.Collection or java.util.Map based then the size is 
the number of elements; otherwise the payload size in bytes.", "ognl": false, 
"suffix": "}" },
+    "size(exp)": { "index": 80, "kind": "function", "displayName": "Size", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Returns the number of elements in collection 
or array based payloads. If the value is null then 0 is returned, otherwise 
1.", "ognl": false, "suffix": "}" },
     "skip(num)": { "index": 81, "kind": "function", "displayName": "Skip First 
Items from the Message Body", "group": "function", "label": "function", 
"required": false, "javaType": "java.util.Iterator", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The skip function iterates the message body and skips 
the first number of items. This can be used with the Splitter EIP to split a 
message body and skip the first N number of  [...]
     "split(exp,separator)": { "index": 82, "kind": "function", "displayName": 
"Split String Values", "group": "function", "label": "function", "required": 
false, "javaType": "String[]", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Splits the message body\/expression as a String value using the separator into 
a String array", "ognl": false, "suffix": "}" },
     "stepId": { "index": 83, "kind": "function", "displayName": "Step Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current step the Exchange is being routed.", "ognl": false, "suffix": "}" },
diff --git 
a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
 
b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
index fb25c08d3519..91dba89d7fa8 100644
--- 
a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
+++ 
b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
@@ -349,22 +349,58 @@ This will get the `Date` object from the header with key 
birthday, and format th
 |Function |Response Type |Description
 |`abs()` | `long` | Converts the message body to a long number and return the 
absolute value.
 |`abs(exp)` | `Long` | Converts the message body (or expression) to a long 
number and return the absolute value.
-|`average(val1,val2,...)` | `long` | Returns the average number from all the 
values.
+|`average(val1,val2,...)` | `long` | Returns the average number from all the 
values  (integral numbers only).
 |`ceil()` | `int` | Converts the message body to a floating number and return 
the ceil value (rounded up to nearest integer).
 |`ceil(exp)` | `int` | Converts the expression to a floating number and return 
the ceil value (rounded up to nearest integer).
 |`floor()` | `int` | Converts the message body to a floating number and return 
the floor value (rounded down to nearest integer).
 |`floor(exp)` | `int` | Converts the expression to a floating number and 
return the floor value (rounded down to nearest integer).
 |`length()` | `int` | The payload length (number of bytes) of the message body
 |`length(exp)` | `int` | The payload length (number of bytes) of the 
expression.
-|`max(val1,val2,...)` | `long` | Returns the maximum number from all the 
values.
-|`min(val1,val2,...)` | `long` | Returns the minimum number from all the 
values.
+|`max(val1,val2,...)` | `long` | Returns the maximum number from all the 
values (integral numbers only).
+|`min(val1,val2,...)` | `long` | Returns the minimum number from all the 
values (integral numbers only).
 |`random(max)` | `int` | Returns a random `Integer` between 0 (included) and 
max (excluded).
 |`random(min,max)` | `int` | Returns a random `Integer` between min (included) 
and max (excluded),
-|`size()` | `int` | The size of the message body. If the payload is 
`java.util.Collection` or `java.util.Map` based then the size is the number of 
elements; otherwise the payload size in bytes.
-|`size(exp)` | `int` | The size of the expression. If the payload is 
`java.util.Collection` or `java.util.Map` based then the size is the number of 
elements; otherwise the payload size in bytes.
+|`size()` | `int` | Returns the number of elements in collection or array 
based message body. If the value is null then 0 is returned, otherwise 1.
+|`size(exp)` | `int` | Returns the number of elements in collection or array 
based value. If the value is null then 0 is returned, otherwise 1.
 |`sum(val1,val2,...)` | `long` | Sums together all the values as integral 
numbers. This function can also be used to subtract by using negative numbers.
 |====
 
+The `abs` function returns the absolute value of a numeric value. It converts 
the input (either the message body or the result of an expression) to a long 
number and computes its absolute value.
+A few examples `${abs(-5)}` returns `5`, and `${abs(5)}` also returns `5`.
+
+The `average` function calculates the average (mean) of integral numbers (not 
floating point).
+Assume message body is `[10, 20, 30]` (as `List<Integer>` or similar) then 
`${avg()}` results in `20`
+
+The `ceil` functions returns the value of number rounded up to the nearest 
integer that is greater than or equal to number.
+For example `${ceil(5.7)}` returns `6`, and `${ceil(5.1)}` also returns `6`.
+
+The `floor` functions returns the value of number rounded down to the nearest 
integer that is smaller or equal to number.
+For example `${ceil(5.7)}` returns `5`, and `${ceil(5.1)}` also returns `5`.
+
+The `length` function calculates the payload size in bytes (if possible). This 
is calculated by
+(if necessary) converting the payload into String to use for determine the 
byte length.
+For example `${length('Hello World')}` returns `11`. For larger payloads, then 
when using xref:manual::stream-caching.adoc[stream caching]
+the length is pre-computed and usually does not require to load the content 
into memory.
+
+The `max` and `min` functions in are used to find the maximum or minimum value 
among a set of numeric integral values.
+For example message body contains a list `[10, 5, 30, 15]` then `${max()}` 
returns `30` and `${min()}` returns `5`.
+
+The `random` functions returns a random number between min and max (exclusive).
+For example `${random(10)}` returns a random number 0..9. And 
`${random(18,50)}` returns a random number between 18..49.
+
+The `size` functions is used to determine the number of elements, when using 
`Collection` or array based payloads.
+If not then either 0 or 1 is returned whether the body is `null` or not.
+For example if the message body contains a `List` with 7 elements then 
`${size()}` returns `7`.
+On the other hand if the message body contains a `InputStream` then the result 
is `1`, and when body is `null` then `0` is returned.
+And for String payloads such as `${size('Hello World')}` then `1` is always 
returned.
+
+TIP: Use the `length` function to return the payload length in bytes.
+
+The `sum` function adds up numeric values (not floating point) and returns the 
result as a long.
+Assume message body is `[10, 20, 30]` (as `List<Integer>` or similar) then 
`${sum()}` results in `60`
+You can also use the `sum` function to add or subtract numbers. For example if 
you want to add 2 to a number, you can do
+`$sum($\{body},2)}`, and likewise to subtract you use negative number, such as 
`$sum($\{body},-2)}`.
+
 === Other Functions
 
 [width="100%",cols="10%,10%,80%",options="header",]
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
index 902de3f38451..146b288bb423 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
@@ -56,6 +56,7 @@ import org.apache.camel.support.GroupIterator;
 import org.apache.camel.support.LanguageHelper;
 import org.apache.camel.support.MessageHelper;
 import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.InetAddressUtil;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.OgnlHelper;
@@ -1130,11 +1131,28 @@ public final class CSimpleHelper {
                 return arr.length;
             } else if (value instanceof double[] arr) {
                 return arr.length;
-            }
-
-            String data = 
exchange.getContext().getTypeConverter().tryConvertTo(String.class, exchange, 
value);
-            if (data != null) {
-                return data.length();
+            } else if (value instanceof StreamCache sc) {
+                return (int) sc.length();
+            } else {
+                // first read as stream
+                InputStream is = null;
+                try {
+                    is = 
exchange.getContext().getTypeConverter().tryConvertTo(InputStream.class, 
exchange, value);
+                    int len = 0;
+                    while (is.read() != -1) {
+                        len++;
+                    }
+                    return len;
+                } catch (Exception e) {
+                    // ignore
+                } finally {
+                    IOHelper.close(is);
+                }
+                // fallback to use string based
+                String data = 
exchange.getContext().getTypeConverter().tryConvertTo(String.class, exchange, 
value);
+                if (data != null) {
+                    return data.length();
+                }
             }
         } finally {
             if (value instanceof StreamCache streamCache) {
@@ -1145,8 +1163,7 @@ public final class CSimpleHelper {
     }
 
     public static int size(Exchange exchange, Object value) {
-        try {
-            // calculate length
+        if (value != null) {
             if (value instanceof byte[] arr) {
                 return arr.length;
             } else if (value instanceof char[] arr) {
@@ -1157,26 +1174,14 @@ public final class CSimpleHelper {
                 return arr.length;
             } else if (value instanceof double[] arr) {
                 return arr.length;
-            } else if (value instanceof String s) {
-                return s.length();
+            } else if (value instanceof String[] arr) {
+                return arr.length;
             } else if (value instanceof Collection<?> c) {
                 return c.size();
             } else if (value instanceof Map<?, ?> m) {
                 return m.size();
             } else {
-                // fall back to stream to read
-                InputStream is = 
exchange.getContext().getTypeConverter().tryConvertTo(InputStream.class, 
exchange, value);
-                int len = 0;
-                while (is.read() != -1) {
-                    len++;
-                }
-                return len;
-            }
-        } catch (Exception e) {
-            // ignore
-        } finally {
-            if (value instanceof StreamCache streamCache) {
-                streamCache.reset();
+                return 1;
             }
         }
         return 0;
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
index 0e12b00e0ff3..17e29b65ba4b 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
@@ -53,7 +53,8 @@ public final class SimpleConstants {
               label = "function")
     public static final String ATTACHMENTS_SIZE = "attachmentsSize";
 
-    @Metadata(description = "Returns the average number from all the values", 
label = "function", javaType = "long",
+    @Metadata(description = "Returns the average number from all the values 
(integral numbers only).", label = "function",
+              javaType = "long",
               displayName = "Average Number")
     public static final String AVERAGE = "average(val...)";
 
@@ -233,7 +234,8 @@ public final class SimpleConstants {
               javaType = "java.util.LinkedHashMap", displayName = "Create Map 
of pairs")
     public static final String MAP = "map(key1,value1,...)";
 
-    @Metadata(description = "Returns the maximum number from all the values", 
label = "function", javaType = "long",
+    @Metadata(description = "Returns the maximum number from all the values 
(integral numbers only).", label = "function",
+              javaType = "long",
               displayName = "Maximum Number")
     public static final String MAX = "max(val...)";
 
@@ -248,7 +250,8 @@ public final class SimpleConstants {
               javaType = "long", label = "function")
     public static final String MESSAGE_TIMESTAMP = "messageTimestamp";
 
-    @Metadata(description = "Returns the minimum number from all the values", 
label = "function", javaType = "long",
+    @Metadata(description = "Returns the minimum number from all the values 
(integral numbers only).", label = "function",
+              javaType = "long",
               displayName = "Minimum Number")
     public static final String MIN = "min(val...)";
 
@@ -322,7 +325,7 @@ public final class SimpleConstants {
               label = "function", javaType = "List", displayName = "Shuffle 
Values")
     public static final String SHUFFLE = "shuffle(val...)";
 
-    @Metadata(description = "The size of the message body (or expression). If 
the payload is java.util.Collection or java.util.Map based then the size is the 
number of elements; otherwise the payload size in bytes.",
+    @Metadata(description = "Returns the number of elements in collection or 
array based payloads. If the value is null then 0 is returned, otherwise 1.",
               label = "function", javaType = "int", displayName = "Size")
     public static final String SIZE = "size(exp)";
 
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
index debbc4c9e813..bf914121cb7e 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
@@ -400,7 +400,7 @@ public final class SimpleExpressionBuilder {
                 if (exp != null) {
                     body = exp.evaluate(exchange, Object.class);
                 } else {
-                    body = exchange.getMessage().getBody(Object.class);
+                    body = exchange.getMessage().getBody();
                 }
                 // this may be an object that we can iterate
                 Iterable<?> it = 
org.apache.camel.support.ObjectHelper.createIterable(body);
@@ -954,7 +954,7 @@ public final class SimpleExpressionBuilder {
     }
 
     /**
-     * Returns the size of the expression (number of elements in 
collection/map; otherwise size of payload in bytes)
+     * Returns the size of the expression (number of elements in 
collection/map; otherwise 1)
      */
     public static Expression sizeExpression(final String expression) {
         return new ExpressionAdapter() {
@@ -974,46 +974,30 @@ public final class SimpleExpressionBuilder {
                 if (exp != null) {
                     body = exp.evaluate(exchange, Object.class);
                 } else {
-                    body = exchange.getMessage().getBody(Object.class);
+                    body = exchange.getMessage().getBody();
                 }
                 if (body != null) {
-                    try {
-                        // calculate length
-                        if (body instanceof byte[] arr) {
-                            return arr.length;
-                        } else if (body instanceof char[] arr) {
-                            return arr.length;
-                        } else if (body instanceof int[] arr) {
-                            return arr.length;
-                        } else if (body instanceof long[] arr) {
-                            return arr.length;
-                        } else if (body instanceof double[] arr) {
-                            return arr.length;
-                        } else if (body instanceof String s) {
-                            return s.length();
-                        } else if (body instanceof Collection<?> c) {
-                            return c.size();
-                        } else if (body instanceof Map<?, ?> m) {
-                            return m.size();
-                        } else {
-                            // fall back to stream to read
-                            InputStream is
-                                    = 
exchange.getContext().getTypeConverter().tryConvertTo(InputStream.class, 
exchange, body);
-                            int len = 0;
-                            while (is.read() != -1) {
-                                len++;
-                            }
-                            return len;
-                        }
-                    } catch (Exception e) {
-                        // ignore
-                    } finally {
-                        if (body instanceof StreamCache streamCache) {
-                            streamCache.reset();
-                        }
+                    if (body instanceof byte[] arr) {
+                        return arr.length;
+                    } else if (body instanceof char[] arr) {
+                        return arr.length;
+                    } else if (body instanceof int[] arr) {
+                        return arr.length;
+                    } else if (body instanceof long[] arr) {
+                        return arr.length;
+                    } else if (body instanceof double[] arr) {
+                        return arr.length;
+                    } else if (body instanceof String[] arr) {
+                        return arr.length;
+                    } else if (body instanceof Collection<?> c) {
+                        return c.size();
+                    } else if (body instanceof Map<?, ?> m) {
+                        return m.size();
+                    } else {
+                        return 1;
                     }
                 }
-                return null;
+                return 0;
             }
 
             @Override
@@ -1048,7 +1032,7 @@ public final class SimpleExpressionBuilder {
                 if (exp != null) {
                     body = exp.evaluate(exchange, Object.class);
                 } else {
-                    body = exchange.getMessage().getBody(Object.class);
+                    body = exchange.getMessage().getBody();
                 }
                 try {
                     if (body instanceof byte[] arr) {
@@ -1061,10 +1045,30 @@ public final class SimpleExpressionBuilder {
                         return arr.length;
                     } else if (body instanceof double[] arr) {
                         return arr.length;
-                    }
-                    String data = 
exchange.getContext().getTypeConverter().tryConvertTo(String.class, exchange, 
body);
-                    if (data != null) {
-                        return data.length();
+                    } else if (body instanceof String[] arr) {
+                        return arr.length;
+                    } else if (body instanceof StreamCache sc) {
+                        return (int) sc.length();
+                    } else {
+                        // first read as stream
+                        InputStream is = null;
+                        try {
+                            is = 
exchange.getContext().getTypeConverter().tryConvertTo(InputStream.class, 
exchange, body);
+                            int len = 0;
+                            while (is.read() != -1) {
+                                len++;
+                            }
+                            return len;
+                        } catch (Exception e) {
+                            // ignore
+                        } finally {
+                            IOHelper.close(is);
+                        }
+                        // fallback to use string based
+                        String data = 
exchange.getContext().getTypeConverter().tryConvertTo(String.class, exchange, 
body);
+                        if (data != null) {
+                            return data.length();
+                        }
                     }
                 } finally {
                     if (body instanceof StreamCache streamCache) {
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 fbb31a78266a..606a0482aa71 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
@@ -2607,25 +2607,29 @@ public class SimpleTest extends LanguageTestSupport {
     public void testSize() {
         exchange.getMessage().setBody(new int[] { 4, 7, 9 });
         Expression expression = 
context.resolveLanguage("simple").createExpression("${size()}");
-        int len = expression.evaluate(exchange, int.class);
-        assertEquals(3, len);
+        int size = expression.evaluate(exchange, int.class);
+        assertEquals(3, size);
 
         exchange.getMessage().setBody("Hello World");
-        len = expression.evaluate(exchange, int.class);
-        assertEquals(11, len);
+        size = expression.evaluate(exchange, int.class);
+        assertEquals(1, size);
+
+        exchange.getMessage().setBody(null);
+        size = expression.evaluate(exchange, int.class);
+        assertEquals(0, size);
 
         exchange.getMessage().setBody(List.of("A", "B", "C", "D"));
-        len = expression.evaluate(exchange, int.class);
-        assertEquals(4, len);
+        size = expression.evaluate(exchange, int.class);
+        assertEquals(4, size);
 
         exchange.getMessage().setBody(Map.of("A", 1, "B", 2, "C", 3));
-        len = expression.evaluate(exchange, int.class);
-        assertEquals(3, len);
+        size = expression.evaluate(exchange, int.class);
+        assertEquals(3, size);
 
         File f = new File("src/test/resources/log4j2.properties");
         exchange.getMessage().setBody(f);
-        len = expression.evaluate(exchange, int.class);
-        assertEquals(f.length(), len);
+        size = expression.evaluate(exchange, int.class);
+        assertEquals(1, size);
     }
 
     @Test
@@ -2651,6 +2655,11 @@ public class SimpleTest extends LanguageTestSupport {
         exchange.getMessage().setBody(f);
         len = expression.evaluate(exchange, int.class);
         assertEquals(f.length(), len);
+
+        FileInputStreamCache fis = new FileInputStreamCache(f);
+        exchange.getMessage().setBody(fis);
+        len = expression.evaluate(exchange, int.class);
+        assertEquals(f.length(), len);
     }
 
     @Test
@@ -3256,6 +3265,10 @@ public class SimpleTest extends LanguageTestSupport {
         Integer i = expression.evaluate(exchange, Integer.class);
         assertEquals(987, i);
 
+        expression = 
context.resolveLanguage("simple").createExpression("${abs(-5)}");
+        i = expression.evaluate(exchange, Integer.class);
+        assertEquals(5, i);
+
         expression = 
context.resolveLanguage("simple").createExpression("${abs(${body})}");
         String s = expression.evaluate(exchange, String.class);
         assertEquals("987", s);

Reply via email to