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 26aff3ce211 CAMEL-21818: camel-core: Add list/map functions to
simple/csimple languages
26aff3ce211 is described below
commit 26aff3ce211c73b634955b20d73a34b49b198e29
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Feb 28 20:46:50 2025 +0100
CAMEL-21818: camel-core: Add list/map functions to simple/csimple languages
---
.../org/apache/camel/catalog/languages/simple.json | 20 +++---
.../language/csimple/joor/OriginalSimpleTest.java | 17 +++++
.../org/apache/camel/language/simple/simple.json | 20 +++---
.../modules/languages/pages/simple-language.adoc | 6 +-
.../camel/language/csimple/CSimpleHelper.java | 19 ++++++
.../camel/language/simple/SimpleConstants.java | 8 ++-
.../language/simple/SimpleExpressionBuilder.java | 78 ++++++++++++++++++++++
.../simple/ast/SimpleFunctionExpression.java | 60 +++++++++++++++++
.../apache/camel/language/simple/SimpleTest.java | 17 +++++
9 files changed, 225 insertions(+), 20 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 86bacbf7bdd..dc32cebe45e 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
@@ -75,15 +75,17 @@
"messageHistory(boolean)": { "index": 50, "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 [...]
"uuid(type)": { "index": 51, "kind": "function", "displayName": "Generate
UUID", "group": "function", "label": "function", "required": false, "javaType":
"String", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Returns a UUID using the
Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and
`simple` as the type. If no type is given, the default is used. It is also
possible to use a custom `UuidG [...]
"hash(exp,algorithm)": { "index": 52, "kind": "function", "displayName":
"Compute Hash Value", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a hashed value (string in hex decimal) of the message body\/expression
using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.",
"ognl": false, "suffix": "}" },
- "empty(type)": { "index": 53, "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.HashMap`.", "ognl": false [...]
+ "empty(type)": { "index": 53, "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`.", "ognl": [...]
"iif(predicate,trueExp,falseExp)": { "index": 54, "kind": "function",
"displayName": "If Then Else", "group": "function", "label": "function",
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Evaluates the predicate and returns the value of trueExp or falseExp. This
function is similar to the ternary operator in Java.", "ognl": false, "suffix":
"}" },
- "attachments": { "index": 55, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "java.util.Map", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "All
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
- "attachments.size": { "index": 56, "kind": "function", "displayName":
"Attachments", "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": "}" },
- "attachmentContentAsText": { "index": 57, "kind": "function",
"displayName": "Attachment Content As Text", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment as text (ie String).",
"ognl": false, "suffix": "}" },
- "attachmentContent": { "index": 58, "kind": "function", "displayName":
"Attachment Content", "group": "function", "label": "function", "required":
false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
content of the attachment", "ognl": false, "suffix": "}" },
- "attachmentContentAs(type)": { "index": 59, "kind": "function",
"displayName": "Attachment Content As", "group": "function", "label":
"function", "required": false, "javaType": "Object", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment, converted to the given
type.", "ognl": false, "suffix": "}" },
- "attachmentHeader(key,name)": { "index": 60, "kind": "function",
"displayName": "Attachment 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": "}" },
- "attachmentHeader(key,name,type)": { "index": 61, "kind": "function",
"displayName": "Attachment Header", "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": "}" },
- "attachment(key)": { "index": 62, "kind": "function", "displayName":
"Attachment", "group": "function", "label": "function", "required": false,
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The DataHandler for the given attachment.", "ognl": true,
"suffix": "}" }
+ "list(val...)": { "index": 55, "kind": "function", "displayName": "Create
List of values", "group": "function", "label": "function", "required": false,
"javaType": "java.util.ArrayList", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
list function creates an ArrayList with the given set of values.", "ognl":
false, "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": "}" },
+ "attachments": { "index": 57, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "java.util.Map", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "All
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
+ "attachments.size": { "index": 58, "kind": "function", "displayName":
"Attachments", "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": "}" },
+ "attachmentContentAsText": { "index": 59, "kind": "function",
"displayName": "Attachment Content As Text", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment as text (ie String).",
"ognl": false, "suffix": "}" },
+ "attachmentContent": { "index": 60, "kind": "function", "displayName":
"Attachment Content", "group": "function", "label": "function", "required":
false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
content of the attachment", "ognl": false, "suffix": "}" },
+ "attachmentContentAs(type)": { "index": 61, "kind": "function",
"displayName": "Attachment Content As", "group": "function", "label":
"function", "required": false, "javaType": "Object", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment, converted to the given
type.", "ognl": false, "suffix": "}" },
+ "attachmentHeader(key,name)": { "index": 62, "kind": "function",
"displayName": "Attachment 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": "}" },
+ "attachmentHeader(key,name,type)": { "index": 63, "kind": "function",
"displayName": "Attachment Header", "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": "}" },
+ "attachment(key)": { "index": 64, "kind": "function", "displayName":
"Attachment", "group": "function", "label": "function", "required": false,
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The DataHandler for the given attachment.", "ognl": true,
"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 68cb1ff109d..b81c45826d5 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
@@ -2002,6 +2002,23 @@ public class OriginalSimpleTest extends
LanguageTestSupport {
assertThrows(ExpressionEvaluationException.class, () ->
evaluateExpression("${empty(unknownType)}", null));
}
+ @Test
+ public void testList() {
+ exchange.getMessage().setBody("4");
+ assertExpression("${list(1,2,3)}", "[1, 2, 3]");
+ assertExpression("${list(1,2,3,${body})}", "[1, 2, 3, 4]");
+ assertExpression("${list('a','b','c')}", "[a, b, c]");
+ assertExpression("${list()}", "[]");
+ }
+
+ @Test
+ public void testMap() {
+ exchange.getMessage().setBody("d");
+ assertExpression("${map(1,'a',2,'b',3,'c')}", "{1=a, 2=b, 3=c}");
+ assertExpression("${map(1,'a',2,'b',3,'c',4,${body})}", "{1=a, 2=b,
3=c, 4=d}");
+ assertExpression("${map()}", "{}");
+ }
+
private void assertExpressionCreateNewEmpty(
String type, Class<?> expectedClass,
java.util.function.Predicate<Object> isEmptyAssertion) {
Object value = evaluateExpression("${empty(%s)}".formatted(type),
null);
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 86bacbf7bdd..dc32cebe45e 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
@@ -75,15 +75,17 @@
"messageHistory(boolean)": { "index": 50, "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 [...]
"uuid(type)": { "index": 51, "kind": "function", "displayName": "Generate
UUID", "group": "function", "label": "function", "required": false, "javaType":
"String", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Returns a UUID using the
Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and
`simple` as the type. If no type is given, the default is used. It is also
possible to use a custom `UuidG [...]
"hash(exp,algorithm)": { "index": 52, "kind": "function", "displayName":
"Compute Hash Value", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a hashed value (string in hex decimal) of the message body\/expression
using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.",
"ognl": false, "suffix": "}" },
- "empty(type)": { "index": 53, "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.HashMap`.", "ognl": false [...]
+ "empty(type)": { "index": 53, "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`.", "ognl": [...]
"iif(predicate,trueExp,falseExp)": { "index": 54, "kind": "function",
"displayName": "If Then Else", "group": "function", "label": "function",
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Evaluates the predicate and returns the value of trueExp or falseExp. This
function is similar to the ternary operator in Java.", "ognl": false, "suffix":
"}" },
- "attachments": { "index": 55, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "java.util.Map", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "All
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
- "attachments.size": { "index": 56, "kind": "function", "displayName":
"Attachments", "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": "}" },
- "attachmentContentAsText": { "index": 57, "kind": "function",
"displayName": "Attachment Content As Text", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment as text (ie String).",
"ognl": false, "suffix": "}" },
- "attachmentContent": { "index": 58, "kind": "function", "displayName":
"Attachment Content", "group": "function", "label": "function", "required":
false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
content of the attachment", "ognl": false, "suffix": "}" },
- "attachmentContentAs(type)": { "index": 59, "kind": "function",
"displayName": "Attachment Content As", "group": "function", "label":
"function", "required": false, "javaType": "Object", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment, converted to the given
type.", "ognl": false, "suffix": "}" },
- "attachmentHeader(key,name)": { "index": 60, "kind": "function",
"displayName": "Attachment 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": "}" },
- "attachmentHeader(key,name,type)": { "index": 61, "kind": "function",
"displayName": "Attachment Header", "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": "}" },
- "attachment(key)": { "index": 62, "kind": "function", "displayName":
"Attachment", "group": "function", "label": "function", "required": false,
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The DataHandler for the given attachment.", "ognl": true,
"suffix": "}" }
+ "list(val...)": { "index": 55, "kind": "function", "displayName": "Create
List of values", "group": "function", "label": "function", "required": false,
"javaType": "java.util.ArrayList", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
list function creates an ArrayList with the given set of values.", "ognl":
false, "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": "}" },
+ "attachments": { "index": 57, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "java.util.Map", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "All
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
+ "attachments.size": { "index": 58, "kind": "function", "displayName":
"Attachments", "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": "}" },
+ "attachmentContentAsText": { "index": 59, "kind": "function",
"displayName": "Attachment Content As Text", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment as text (ie String).",
"ognl": false, "suffix": "}" },
+ "attachmentContent": { "index": 60, "kind": "function", "displayName":
"Attachment Content", "group": "function", "label": "function", "required":
false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
content of the attachment", "ognl": false, "suffix": "}" },
+ "attachmentContentAs(type)": { "index": 61, "kind": "function",
"displayName": "Attachment Content As", "group": "function", "label":
"function", "required": false, "javaType": "Object", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment, converted to the given
type.", "ognl": false, "suffix": "}" },
+ "attachmentHeader(key,name)": { "index": 62, "kind": "function",
"displayName": "Attachment 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": "}" },
+ "attachmentHeader(key,name,type)": { "index": 63, "kind": "function",
"displayName": "Attachment Header", "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": "}" },
+ "attachment(key)": { "index": 64, "kind": "function", "displayName":
"Attachment", "group": "function", "label": "function", "required": false,
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The DataHandler for the given attachment.", "ognl": true,
"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 3d9afef38d0..1ec24b1a428 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
@@ -234,7 +234,11 @@ constant field from Exchange as:
`org.apache.camel.Exchange.FILE_NAME`
`string` -> empty String +
`list` -> empty ArrayList +
-`map` -> empty HashMap +
+`map` -> empty LinkedHashMap +
+
+|list(val1,val2,...) | java.util.ArrayList | The list function creates an
ArrayList with the given set of values.
+
+|map(key1,value1,...) | java.util.LinkedHashMap | The map function creates a
LinkedHashMap with the given set of pairs.
|null |null |represents a *null*
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 428f79be280..1bf95915039 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
@@ -504,6 +504,25 @@ public final class CSimpleHelper {
throw new IllegalArgumentException("function empty(%s) has unknown
type".formatted(type));
}
+ public static List<Object> list(Exchange exchange, Object... args) {
+ List<Object> answer = new ArrayList<>();
+ for (int i = 0; args != null && i < args.length; i++) {
+ answer.add(args[i]);
+ }
+ return answer;
+ }
+
+ public static Map<String, Object> map(Exchange exchange, Object... args) {
+ Map<String, Object> answer = new LinkedHashMap<>();
+ for (int i = 0, j = 0; args != null && i < args.length - 1; j++) {
+ String key =
exchange.getContext().getTypeConverter().convertTo(String.class, exchange,
args[i]);
+ Object value = args[i + 1];
+ answer.put(key, value);
+ i = i + 2;
+ }
+ return answer;
+ }
+
public static String substring(Exchange exchange, Object num1, Object
num2) {
int head =
exchange.getContext().getTypeConverter().tryConvertTo(int.class, exchange,
num1);
int tail =
exchange.getContext().getTypeConverter().tryConvertTo(int.class, exchange,
num2);
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 bbfb12048eb..cfed2884a95 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
@@ -206,12 +206,18 @@ public final class SimpleConstants {
@Metadata(description = "Returns a hashed value (string in hex decimal) of
the message body/expression using JDK MessageDigest. The algorithm can be
SHA-256 (default) or SHA3-256.",
label = "function", javaType = "String", displayName = "Compute
Hash Value")
public static final String HASH = "hash(exp,algorithm)";
- @Metadata(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.HashMap`.",
+ @Metadata(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`.",
label = "function", javaType = "Object", displayName = "Create
Empty Object")
public static final String EMPTY = "empty(type)";
@Metadata(description = "Evaluates the predicate and returns the value of
trueExp or falseExp. This function is similar to the ternary operator in Java.",
label = "function", javaType = "Object", displayName = "If Then
Else")
public static final String IIF = "iif(predicate,trueExp,falseExp)";
+ @Metadata(description = "The list function creates an ArrayList with the
given set of values.",
+ label = "function", javaType = "java.util.ArrayList",
displayName = "Create List of values")
+ public static final String LIST = "list(val...)";
+ @Metadata(description = "The map function creates a LinkedHashMap with the
given set of pairs.",
+ label = "function", javaType = "java.util.LinkedHashMap",
displayName = "Create Map of pairs")
+ public static final String MAP = "map(key1,value1,...)";
@Metadata(description = "All the attachments as a
Map<String,DataHandler.", javaType = "java.util.Map", label = "function")
public static final String ATTACHMENTS = "attachments";
@Metadata(description = "The number of attachments. Is 0 if there are no
attachments.", javaType = "int",
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 e616167f8d1..0e583d41d80 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
@@ -18,10 +18,12 @@ package org.apache.camel.language.simple;
import java.security.MessageDigest;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;
@@ -212,6 +214,82 @@ public final class SimpleExpressionBuilder {
};
}
+ /**
+ * An expression that creates an ArrayList
+ */
+ public static Expression listExpression(String[] values) {
+ return new ExpressionAdapter() {
+
+ private final Expression[] exps = new Expression[values != null ?
values.length : 0];
+
+ @Override
+ public void init(CamelContext context) {
+ for (int i = 0; values != null && i < values.length; i++) {
+ Expression exp =
context.resolveLanguage("simple").createExpression(values[i]);
+ exp.init(context);
+ exps[i] = exp;
+ }
+ }
+
+ @Override
+ public Object evaluate(Exchange exchange) {
+ List<Object> answer = new ArrayList<>(values != null ?
values.length : 0);
+ for (Expression exp : exps) {
+ Object val = exp.evaluate(exchange, Object.class);
+ answer.add(val);
+ }
+ return answer;
+ }
+
+ @Override
+ public String toString() {
+ return "list(" + Arrays.toString(values) + ")";
+ }
+ };
+ }
+
+ /**
+ * An expression that creates an LinkedHashMap
+ */
+ public static Expression mapExpression(String[] pairs) {
+ return new ExpressionAdapter() {
+
+ private final Expression[] keys = new Expression[pairs != null ?
pairs.length / 2 : 0];
+ private final Expression[] values = new Expression[pairs != null ?
pairs.length / 2 : 0];
+
+ @Override
+ public void init(CamelContext context) {
+ for (int i = 0, j = 0; pairs != null && i < pairs.length - 1;
j++) {
+ String key = pairs[i];
+ String value = pairs[i + 1];
+ Expression exp =
context.resolveLanguage("simple").createExpression(key);
+ exp.init(context);
+ keys[j] = exp;
+ exp =
context.resolveLanguage("simple").createExpression(value);
+ exp.init(context);
+ values[j] = exp;
+ i = i + 2;
+ }
+ }
+
+ @Override
+ public Object evaluate(Exchange exchange) {
+ Map<String, Object> answer = new LinkedHashMap<>(keys.length);
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i].evaluate(exchange, String.class);
+ Object val = values[i].evaluate(exchange, Object.class);
+ answer.put(key, val);
+ }
+ return answer;
+ }
+
+ @Override
+ public String toString() {
+ return "map(" + Arrays.toString(values) + ")";
+ }
+ };
+ }
+
/**
* Joins together the values from the expression
*/
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
index 55c6701ce6d..24127aab861 100644
---
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.StringJoiner;
import org.apache.camel.CamelContext;
import org.apache.camel.Expression;
@@ -891,6 +892,33 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return SimpleExpressionBuilder.iifExpression(tokens[0].trim(),
tokens[1].trim(), tokens[2].trim());
}
+ // list function
+ remainder = ifStartsWithReturnRemainder("list(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ String[] tokens = null;
+ if (ObjectHelper.isNotEmpty(values)) {
+ tokens = StringQuoteHelper.splitSafeQuote(values, ',');
+ }
+ return SimpleExpressionBuilder.listExpression(tokens);
+ }
+ // map function
+ remainder = ifStartsWithReturnRemainder("map(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ String[] tokens = null;
+ if (ObjectHelper.isNotEmpty(values)) {
+ tokens = StringQuoteHelper.splitSafeQuote(values, ',');
+ }
+ // there must be an even number of tokens as each map element is a
pair
+ if (tokens != null && tokens.length % 2 == 1) {
+ throw new SimpleParserException(
+ "Map function must have an even number of values, was:
" + tokens.length + " values.",
+ token.getIndex());
+ }
+ return SimpleExpressionBuilder.mapExpression(tokens);
+ }
+
return null;
}
@@ -1913,6 +1941,38 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return "empty(exchange, " + value + ")";
}
+ // list function
+ remainder = ifStartsWithReturnRemainder("list(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ String[] tokens = null;
+ if (ObjectHelper.isNotEmpty(values)) {
+ tokens = codeSplitSafe(values, ',', true, true);
+ }
+ StringJoiner sj = new StringJoiner(", ");
+ for (int i = 0; tokens != null && i < tokens.length; i++) {
+ sj.add(tokens[i]);
+ }
+ String p = sj.length() > 0 ? sj.toString() : "null";
+ return "list(exchange, " + p + ")";
+ }
+
+ // map function
+ remainder = ifStartsWithReturnRemainder("map(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ String[] tokens = null;
+ if (ObjectHelper.isNotEmpty(values)) {
+ tokens = codeSplitSafe(values, ',', true, true);
+ }
+ StringJoiner sj = new StringJoiner(", ");
+ for (int i = 0; tokens != null && i < tokens.length; i++) {
+ sj.add(tokens[i]);
+ }
+ String p = sj.length() > 0 ? sj.toString() : "null";
+ return "map(exchange, " + p + ")";
+ }
+
// hash function
remainder = ifStartsWithReturnRemainder("hash(", function);
if (remainder != null) {
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 fbcc49b19a1..c6a2d27650a 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
@@ -2045,6 +2045,23 @@ public class SimpleTest extends LanguageTestSupport {
assertExpression("${replace(",',${header.foo})}", "{'foo':
'cheese'}");
}
+ @Test
+ public void testList() {
+ exchange.getMessage().setBody("4");
+ assertExpression("${list(1,2,3)}", "[1, 2, 3]");
+ assertExpression("${list(1,2,3,${body})}", "[1, 2, 3, 4]");
+ assertExpression("${list('a','b','c')}", "[a, b, c]");
+ assertExpression("${list()}", "[]");
+ }
+
+ @Test
+ public void testMap() {
+ exchange.getMessage().setBody("d");
+ assertExpression("${map(1,a,2,b,3,c)}", "{1=a, 2=b, 3=c}");
+ assertExpression("${map(1,a,2,b,3,c,4,${body})}", "{1=a, 2=b, 3=c,
4=d}");
+ assertExpression("${map()}", "{}");
+ }
+
@Test
public void testSubstringExpression() {
exchange.getMessage().setBody("ABCDEFGHIJK");