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

acosentino 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 86210fc3015 Add Jsonata frame binding functionality (#14995)
86210fc3015 is described below

commit 86210fc3015933d5dd4ec724f9a97ba894721db6
Author: Darren Vine <[email protected]>
AuthorDate: Fri Aug 2 11:39:44 2024 +0200

    Add Jsonata frame binding functionality (#14995)
    
    * feat: Add framebindings
    
    * feat: Custom jsonata frame bindings
    
    * Show sample with reversed string
    
    * Formated
    
    * Generated code
    
    * chore: update generated
---
 .../apache/camel/catalog/components/jsonata.json   |  6 +-
 .../jsonata/JsonataComponentConfigurer.java        |  6 ++
 .../jsonata/JsonataEndpointConfigurer.java         |  6 ++
 .../jsonata/JsonataEndpointUriFactory.java         |  3 +-
 .../apache/camel/component/jsonata/jsonata.json    |  6 +-
 .../src/main/docs/jsonata-component.adoc           | 26 ++++++++
 .../camel/component/jsonata/JsonataComponent.java  | 24 ++++++-
 .../camel/component/jsonata/JsonataEndpoint.java   | 23 ++++++-
 .../component/jsonata/JsonataFrameBinding.java     | 23 +++++++
 .../component/jsonata/JsonataFrameBindingTest.java | 74 ++++++++++++++++++++++
 .../jsonata/frameBinding/expressions.spec          |  6 ++
 .../component/jsonata/frameBinding/input.json      | 53 ++++++++++++++++
 .../component/jsonata/frameBinding/output.json     |  1 +
 .../dsl/JsonataComponentBuilderFactory.java        | 17 +++++
 .../dsl/JsonataEndpointBuilderFactory.java         | 34 ++++++++++
 .../camel/kotlin/components/JsonataUriDsl.kt       |  7 ++
 16 files changed, 307 insertions(+), 8 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jsonata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jsonata.json
index 49067676cea..6ab63b7f9a5 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jsonata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jsonata.json
@@ -24,7 +24,8 @@
   },
   "componentProperties": {
     "lazyStartProducer": { "index": 0, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
-    "autowiredEnabled": { "index": 1, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
+    "autowiredEnabled": { "index": 1, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
+    "frameBinding": { "index": 2, "kind": "property", "displayName": "Frame 
Binding", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.camel.component.jsonata.JsonataFrameBinding", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
configure custom frame bindings and inject user functions." }
   },
   "properties": {
     "resourceUri": { "index": 0, "kind": "path", "displayName": "Resource 
Uri", "group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "supportFileReference": true, 
"description": "Path to the resource. You can prefix with: classpath, file, 
http, ref, or bean. classpath, file and http loads the resource using these 
protocols (classpath is default). ref will look [...]
@@ -32,6 +33,7 @@
     "contentCache": { "index": 2, "kind": "parameter", "displayName": "Content 
Cache", "group": "producer", "label": "", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "autowired": false, "secret": 
false, "defaultValue": false, "description": "Sets whether to use resource 
content cache or not" },
     "inputType": { "index": 3, "kind": "parameter", "displayName": "Input 
Type", "group": "producer", "label": "", "required": false, "type": "object", 
"javaType": "org.apache.camel.component.jsonata.JsonataInputOutputType", 
"enum": [ "Jackson", "JsonString" ], "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "Jackson", "description": "Specifies if the 
input should be Jackson JsonNode or a JSON String." },
     "outputType": { "index": 4, "kind": "parameter", "displayName": "Output 
Type", "group": "producer", "label": "", "required": false, "type": "object", 
"javaType": "org.apache.camel.component.jsonata.JsonataInputOutputType", 
"enum": [ "Jackson", "JsonString" ], "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "Jackson", "description": "Specifies if the 
output should be Jackson JsonNode or a JSON String." },
-    "lazyStartProducer": { "index": 5, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produc [...]
+    "lazyStartProducer": { "index": 5, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produc [...]
+    "frameBinding": { "index": 6, "kind": "parameter", "displayName": "Frame 
Binding", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.camel.component.jsonata.JsonataFrameBinding", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
configure the Jsonata frame binding. Allows custom functions to be added." }
   }
 }
diff --git 
a/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataComponentConfigurer.java
 
b/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataComponentConfigurer.java
index b89852dce29..86bb0ad4957 100644
--- 
a/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataComponentConfigurer.java
+++ 
b/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataComponentConfigurer.java
@@ -25,6 +25,8 @@ public class JsonataComponentConfigurer extends 
PropertyConfigurerSupport implem
         switch (ignoreCase ? name.toLowerCase() : name) {
         case "autowiredenabled":
         case "autowiredEnabled": 
target.setAutowiredEnabled(property(camelContext, boolean.class, value)); 
return true;
+        case "framebinding":
+        case "frameBinding": target.setFrameBinding(property(camelContext, 
org.apache.camel.component.jsonata.JsonataFrameBinding.class, value)); return 
true;
         case "lazystartproducer":
         case "lazyStartProducer": 
target.setLazyStartProducer(property(camelContext, boolean.class, value)); 
return true;
         default: return false;
@@ -36,6 +38,8 @@ public class JsonataComponentConfigurer extends 
PropertyConfigurerSupport implem
         switch (ignoreCase ? name.toLowerCase() : name) {
         case "autowiredenabled":
         case "autowiredEnabled": return boolean.class;
+        case "framebinding":
+        case "frameBinding": return 
org.apache.camel.component.jsonata.JsonataFrameBinding.class;
         case "lazystartproducer":
         case "lazyStartProducer": return boolean.class;
         default: return null;
@@ -48,6 +52,8 @@ public class JsonataComponentConfigurer extends 
PropertyConfigurerSupport implem
         switch (ignoreCase ? name.toLowerCase() : name) {
         case "autowiredenabled":
         case "autowiredEnabled": return target.isAutowiredEnabled();
+        case "framebinding":
+        case "frameBinding": return target.getFrameBinding();
         case "lazystartproducer":
         case "lazyStartProducer": return target.isLazyStartProducer();
         default: return null;
diff --git 
a/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataEndpointConfigurer.java
 
b/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataEndpointConfigurer.java
index 57ebcc77b57..351bf6d73de 100644
--- 
a/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataEndpointConfigurer.java
+++ 
b/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataEndpointConfigurer.java
@@ -27,6 +27,8 @@ public class JsonataEndpointConfigurer extends 
PropertyConfigurerSupport impleme
         case "allowContextMapAll": 
target.setAllowContextMapAll(property(camelContext, boolean.class, value)); 
return true;
         case "contentcache":
         case "contentCache": target.setContentCache(property(camelContext, 
boolean.class, value)); return true;
+        case "framebinding":
+        case "frameBinding": target.setFrameBinding(property(camelContext, 
org.apache.camel.component.jsonata.JsonataFrameBinding.class, value)); return 
true;
         case "inputtype":
         case "inputType": target.setInputType(property(camelContext, 
org.apache.camel.component.jsonata.JsonataInputOutputType.class, value)); 
return true;
         case "lazystartproducer":
@@ -44,6 +46,8 @@ public class JsonataEndpointConfigurer extends 
PropertyConfigurerSupport impleme
         case "allowContextMapAll": return boolean.class;
         case "contentcache":
         case "contentCache": return boolean.class;
+        case "framebinding":
+        case "frameBinding": return 
org.apache.camel.component.jsonata.JsonataFrameBinding.class;
         case "inputtype":
         case "inputType": return 
org.apache.camel.component.jsonata.JsonataInputOutputType.class;
         case "lazystartproducer":
@@ -62,6 +66,8 @@ public class JsonataEndpointConfigurer extends 
PropertyConfigurerSupport impleme
         case "allowContextMapAll": return target.isAllowContextMapAll();
         case "contentcache":
         case "contentCache": return target.isContentCache();
+        case "framebinding":
+        case "frameBinding": return target.getFrameBinding();
         case "inputtype":
         case "inputType": return target.getInputType();
         case "lazystartproducer":
diff --git 
a/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataEndpointUriFactory.java
 
b/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataEndpointUriFactory.java
index 1cb289ac00b..d4708c6e769 100644
--- 
a/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataEndpointUriFactory.java
+++ 
b/components/camel-jsonata/src/generated/java/org/apache/camel/component/jsonata/JsonataEndpointUriFactory.java
@@ -23,9 +23,10 @@ public class JsonataEndpointUriFactory extends 
org.apache.camel.support.componen
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Set<String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(6);
+        Set<String> props = new HashSet<>(7);
         props.add("allowContextMapAll");
         props.add("contentCache");
+        props.add("frameBinding");
         props.add("inputType");
         props.add("lazyStartProducer");
         props.add("outputType");
diff --git 
a/components/camel-jsonata/src/generated/resources/META-INF/org/apache/camel/component/jsonata/jsonata.json
 
b/components/camel-jsonata/src/generated/resources/META-INF/org/apache/camel/component/jsonata/jsonata.json
index 49067676cea..6ab63b7f9a5 100644
--- 
a/components/camel-jsonata/src/generated/resources/META-INF/org/apache/camel/component/jsonata/jsonata.json
+++ 
b/components/camel-jsonata/src/generated/resources/META-INF/org/apache/camel/component/jsonata/jsonata.json
@@ -24,7 +24,8 @@
   },
   "componentProperties": {
     "lazyStartProducer": { "index": 0, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
-    "autowiredEnabled": { "index": 1, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
+    "autowiredEnabled": { "index": 1, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
+    "frameBinding": { "index": 2, "kind": "property", "displayName": "Frame 
Binding", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.camel.component.jsonata.JsonataFrameBinding", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
configure custom frame bindings and inject user functions." }
   },
   "properties": {
     "resourceUri": { "index": 0, "kind": "path", "displayName": "Resource 
Uri", "group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "supportFileReference": true, 
"description": "Path to the resource. You can prefix with: classpath, file, 
http, ref, or bean. classpath, file and http loads the resource using these 
protocols (classpath is default). ref will look [...]
@@ -32,6 +33,7 @@
     "contentCache": { "index": 2, "kind": "parameter", "displayName": "Content 
Cache", "group": "producer", "label": "", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "autowired": false, "secret": 
false, "defaultValue": false, "description": "Sets whether to use resource 
content cache or not" },
     "inputType": { "index": 3, "kind": "parameter", "displayName": "Input 
Type", "group": "producer", "label": "", "required": false, "type": "object", 
"javaType": "org.apache.camel.component.jsonata.JsonataInputOutputType", 
"enum": [ "Jackson", "JsonString" ], "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "Jackson", "description": "Specifies if the 
input should be Jackson JsonNode or a JSON String." },
     "outputType": { "index": 4, "kind": "parameter", "displayName": "Output 
Type", "group": "producer", "label": "", "required": false, "type": "object", 
"javaType": "org.apache.camel.component.jsonata.JsonataInputOutputType", 
"enum": [ "Jackson", "JsonString" ], "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "Jackson", "description": "Specifies if the 
output should be Jackson JsonNode or a JSON String." },
-    "lazyStartProducer": { "index": 5, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produc [...]
+    "lazyStartProducer": { "index": 5, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produc [...]
+    "frameBinding": { "index": 6, "kind": "parameter", "displayName": "Frame 
Binding", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.camel.component.jsonata.JsonataFrameBinding", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
configure the Jsonata frame binding. Allows custom functions to be added." }
   }
 }
diff --git a/components/camel-jsonata/src/main/docs/jsonata-component.adoc 
b/components/camel-jsonata/src/main/docs/jsonata-component.adoc
index 7ba453635d9..10af5b7b474 100644
--- a/components/camel-jsonata/src/main/docs/jsonata-component.adoc
+++ b/components/camel-jsonata/src/main/docs/jsonata-component.adoc
@@ -58,6 +58,8 @@ include::partial$component-endpoint-options.adoc[]
 
 == Samples
 
+=== Basic
+
 For example, you could use something like:
 
 [source,java]
@@ -75,5 +77,29 @@ from("activemq:My.Queue").
   to("activemq:Another.Queue");
 ---------------------------------------------------------------
 
+=== Frame bindings
+
+It is possible to configure custom functions that can be called from Jsonata. 
For example you might want to be able to
+inject environment variables:
+
+[source,java]
+---------------------------------------------------------------
+from("activemq:My.Queue").
+  
to("jsonata:file://myfolder/MyResponse.json?contentCache=true&frameBinding=#customBindings").
+  to("activemq:Another.Queue");
+---------------------------------------------------------------
+
+A custom binding might look like the following:
+
+[source,java]
+---------------------------------------------------------------
+@NoArgsConstructor
+public class CustomJsonataFrameBinding implements JsonataFrameBinding {
+  @Override
+  public void bindToFrame(Jsonata.Frame frame) {
+    frame.bind("env", (String s) -> System.getenv(s));
+  }
+}
+---------------------------------------------------------------
 
 include::spring-boot:partial$starter.adoc[]
diff --git 
a/components/camel-jsonata/src/main/java/org/apache/camel/component/jsonata/JsonataComponent.java
 
b/components/camel-jsonata/src/main/java/org/apache/camel/component/jsonata/JsonataComponent.java
index a2523cd1ee6..e799c01a4de 100644
--- 
a/components/camel-jsonata/src/main/java/org/apache/camel/component/jsonata/JsonataComponent.java
+++ 
b/components/camel-jsonata/src/main/java/org/apache/camel/component/jsonata/JsonataComponent.java
@@ -19,12 +19,16 @@ package org.apache.camel.component.jsonata;
 import java.util.Map;
 
 import org.apache.camel.Endpoint;
+import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.annotations.Component;
 import org.apache.camel.support.DefaultComponent;
 import org.apache.camel.support.ResourceHelper;
 
 @Component("jsonata")
 public class JsonataComponent extends DefaultComponent {
+    @Metadata(label = "advanced",
+              description = "To configure custom frame bindings and inject 
user functions.")
+    protected JsonataFrameBinding frameBinding;
 
     public JsonataComponent() {
     }
@@ -33,7 +37,14 @@ public class JsonataComponent extends DefaultComponent {
     protected Endpoint createEndpoint(String uri, String remaining, 
Map<String, Object> parameters) throws Exception {
         boolean cache = getAndRemoveParameter(parameters, "contentCache", 
Boolean.class, Boolean.TRUE);
 
-        JsonataEndpoint answer = new JsonataEndpoint(uri, this, remaining);
+        JsonataFrameBinding frameBinding
+                = resolveAndRemoveReferenceParameter(parameters, 
"frameBinding", JsonataFrameBinding.class);
+        if (frameBinding == null) {
+            // fallback to component configured
+            frameBinding = getFrameBinding();
+        }
+
+        JsonataEndpoint answer = new JsonataEndpoint(uri, this, remaining, 
frameBinding);
         answer.setContentCache(cache);
 
         // if its a http resource then append any remaining parameters and 
update the resource uri
@@ -44,4 +55,15 @@ public class JsonataComponent extends DefaultComponent {
 
         return answer;
     }
+
+    /**
+     * To use the custom JsonataFrameBinding to perform configuration of 
custom functions that will be used.
+     */
+    public void setFrameBinding(JsonataFrameBinding frameBinding) {
+        this.frameBinding = frameBinding;
+    }
+
+    public JsonataFrameBinding getFrameBinding() {
+        return frameBinding;
+    }
 }
diff --git 
a/components/camel-jsonata/src/main/java/org/apache/camel/component/jsonata/JsonataEndpoint.java
 
b/components/camel-jsonata/src/main/java/org/apache/camel/component/jsonata/JsonataEndpoint.java
index 6fb1647217c..a641906eced 100644
--- 
a/components/camel-jsonata/src/main/java/org/apache/camel/component/jsonata/JsonataEndpoint.java
+++ 
b/components/camel-jsonata/src/main/java/org/apache/camel/component/jsonata/JsonataEndpoint.java
@@ -53,11 +53,15 @@ public class JsonataEndpoint extends ResourceEndpoint {
     @UriParam(defaultValue = "Jackson")
     private JsonataInputOutputType inputType;
 
+    @UriParam(label = "advanced", description = "To configure the Jsonata 
frame binding. Allows custom functions to be added.")
+    private JsonataFrameBinding frameBinding;
+
     public JsonataEndpoint() {
     }
 
-    public JsonataEndpoint(String uri, JsonataComponent component, String 
resourceUri) {
+    public JsonataEndpoint(String uri, JsonataComponent component, String 
resourceUri, JsonataFrameBinding frameBinding) {
         super(uri, component, resourceUri);
+        this.frameBinding = frameBinding;
     }
 
     @Override
@@ -97,6 +101,17 @@ public class JsonataEndpoint extends ResourceEndpoint {
         this.inputType = inputType;
     }
 
+    /**
+     * Specifies the custom framebinding.
+     */
+    public void setFrameBinding(JsonataFrameBinding frameBinding) {
+        this.frameBinding = frameBinding;
+    }
+
+    public JsonataFrameBinding getFrameBinding() {
+        return frameBinding;
+    }
+
     @Override
     protected void onExchange(Exchange exchange) throws Exception {
         String path = getResourceUri();
@@ -122,7 +137,11 @@ public class JsonataEndpoint extends ResourceEndpoint {
                     .collect(Collectors.joining("\n"));
             expression = jsonata(spec);
         }
-        output = expression.evaluate(input);
+
+        Jsonata.Frame frame = expression.createFrame();
+        if (frameBinding != null)
+            frameBinding.bindToFrame(frame);
+        output = expression.evaluate(input, frame);
 
         // now lets output the results to the exchange
         Object body = output;
diff --git 
a/components/camel-jsonata/src/main/java/org/apache/camel/component/jsonata/JsonataFrameBinding.java
 
b/components/camel-jsonata/src/main/java/org/apache/camel/component/jsonata/JsonataFrameBinding.java
new file mode 100644
index 00000000000..1ccfb23f013
--- /dev/null
+++ 
b/components/camel-jsonata/src/main/java/org/apache/camel/component/jsonata/JsonataFrameBinding.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jsonata;
+
+import com.dashjoin.jsonata.Jsonata;
+
+public interface JsonataFrameBinding {
+    void bindToFrame(Jsonata.Frame clientBuilder);
+}
diff --git 
a/components/camel-jsonata/src/test/java/org/apache/camel/component/jsonata/JsonataFrameBindingTest.java
 
b/components/camel-jsonata/src/test/java/org/apache/camel/component/jsonata/JsonataFrameBindingTest.java
new file mode 100644
index 00000000000..0680aeded4c
--- /dev/null
+++ 
b/components/camel-jsonata/src/test/java/org/apache/camel/component/jsonata/JsonataFrameBindingTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jsonata;
+
+import com.dashjoin.jsonata.Jsonata;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.support.ResourceHelper;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.apache.camel.util.IOHelper;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit test based on the first sample test from the JSONata project.
+ */
+class JsonataFrameBindingTest extends CamelTestSupport {
+
+    private JsonataFrameBinding frameBinding = new JsonataFrameBinding() {
+        @Override
+        public void bindToFrame(Jsonata.Frame clientBuilder) {
+            clientBuilder.bind("reverse", (String originalStr) -> {
+                String reversedStr = "";
+
+                for (int i = 0; i < originalStr.length(); i++) {
+                    reversedStr = originalStr.charAt(i) + reversedStr;
+                }
+
+                return reversedStr;
+            });
+        }
+    };
+
+    @Test
+    void testFrameBindingJsonata() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived(
+                IOHelper.loadText(
+                        ResourceHelper.resolveMandatoryResourceAsInputStream(
+                                context, 
"org/apache/camel/component/jsonata/frameBinding/output.json"))
+                        .trim() // Remove the last newline added by 
IOHelper.loadText()
+        );
+
+        sendBody("direct://start",
+                ResourceHelper.resolveMandatoryResourceAsInputStream(
+                        context, 
"org/apache/camel/component/jsonata/frameBinding/input.json"));
+
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        context.getComponent("jsonata", 
JsonataComponent.class).setFrameBinding(frameBinding);
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct://start")
+                        
.to("jsonata:org/apache/camel/component/jsonata/frameBinding/expressions.spec?inputType=JsonString&outputType=JsonString")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-jsonata/src/test/resources/org/apache/camel/component/jsonata/frameBinding/expressions.spec
 
b/components/camel-jsonata/src/test/resources/org/apache/camel/component/jsonata/frameBinding/expressions.spec
new file mode 100644
index 00000000000..3d993390c9d
--- /dev/null
+++ 
b/components/camel-jsonata/src/test/resources/org/apache/camel/component/jsonata/frameBinding/expressions.spec
@@ -0,0 +1,6 @@
+{
+    "name": FirstName & " " & Surname,
+    "mobile": Phone[type = "mobile"].number,
+    "emails": Email#$i[$i>0],
+    "binding": $reverse(FirstName)
+}
\ No newline at end of file
diff --git 
a/components/camel-jsonata/src/test/resources/org/apache/camel/component/jsonata/frameBinding/input.json
 
b/components/camel-jsonata/src/test/resources/org/apache/camel/component/jsonata/frameBinding/input.json
new file mode 100644
index 00000000000..bceae29355c
--- /dev/null
+++ 
b/components/camel-jsonata/src/test/resources/org/apache/camel/component/jsonata/frameBinding/input.json
@@ -0,0 +1,53 @@
+{
+    "FirstName": "Fred",
+    "Surname": "Smith",
+    "Age": 28,
+    "Address": {
+      "Street": "Hursley Park",
+      "City": "Winchester",
+      "Postcode": "SO21 2JN"
+    },
+    "Phone": [
+      {
+        "type": "home",
+        "number": "0203 544 1234"
+      },
+      {
+        "type": "office",
+        "number": "01962 001234"
+      },
+      {
+        "type": "office",
+        "number": "01962 001235"
+      },
+      {
+        "type": "mobile",
+        "number": "077 7700 1234"
+      }
+    ],
+    "Email": [
+      {
+        "type": "office",
+        "address": [
+          "[email protected]",
+          "[email protected]"
+        ]
+      },
+      {
+        "type": "home",
+        "address": [
+          "[email protected]",
+          "[email protected]"
+        ]
+      }
+    ],
+    "Other": {
+      "Over 18 ?": true,
+      "Misc": null,
+      "Alternative.Address": {
+        "Street": "Brick Lane",
+        "City": "London",
+        "Postcode": "E1 6RF"
+      }
+    }
+  }
\ No newline at end of file
diff --git 
a/components/camel-jsonata/src/test/resources/org/apache/camel/component/jsonata/frameBinding/output.json
 
b/components/camel-jsonata/src/test/resources/org/apache/camel/component/jsonata/frameBinding/output.json
new file mode 100644
index 00000000000..ec84e86c5f6
--- /dev/null
+++ 
b/components/camel-jsonata/src/test/resources/org/apache/camel/component/jsonata/frameBinding/output.json
@@ -0,0 +1 @@
+{"name":"Fred Smith","mobile":"077 7700 
1234","emails":{"type":"home","address":["[email protected]","[email protected]"]},"binding":"derF"}
\ No newline at end of file
diff --git 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/JsonataComponentBuilderFactory.java
 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/JsonataComponentBuilderFactory.java
index 2d5d280e822..4d5c3985b2e 100644
--- 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/JsonataComponentBuilderFactory.java
+++ 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/JsonataComponentBuilderFactory.java
@@ -96,6 +96,22 @@ public interface JsonataComponentBuilderFactory {
             doSetProperty("autowiredEnabled", autowiredEnabled);
             return this;
         }
+    
+        /**
+         * To configure custom frame bindings and inject user functions.
+         * 
+         * The option is a:
+         * 
&lt;code&gt;org.apache.camel.component.jsonata.JsonataFrameBinding&lt;/code&gt; 
type.
+         * 
+         * Group: advanced
+         * 
+         * @param frameBinding the value to set
+         * @return the dsl builder
+         */
+        default JsonataComponentBuilder 
frameBinding(org.apache.camel.component.jsonata.JsonataFrameBinding 
frameBinding) {
+            doSetProperty("frameBinding", frameBinding);
+            return this;
+        }
     }
 
     class JsonataComponentBuilderImpl
@@ -113,6 +129,7 @@ public interface JsonataComponentBuilderFactory {
             switch (name) {
             case "lazyStartProducer": ((JsonataComponent) 
component).setLazyStartProducer((boolean) value); return true;
             case "autowiredEnabled": ((JsonataComponent) 
component).setAutowiredEnabled((boolean) value); return true;
+            case "frameBinding": ((JsonataComponent) 
component).setFrameBinding((org.apache.camel.component.jsonata.JsonataFrameBinding)
 value); return true;
             default: return false;
             }
         }
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/JsonataEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/JsonataEndpointBuilderFactory.java
index fe29224470a..f32e6b07f00 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/JsonataEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/JsonataEndpointBuilderFactory.java
@@ -234,6 +234,40 @@ public interface JsonataEndpointBuilderFactory {
             doSetProperty("lazyStartProducer", lazyStartProducer);
             return this;
         }
+        /**
+         * To configure the Jsonata frame binding. Allows custom functions to 
be
+         * added.
+         * 
+         * The option is a:
+         * <code>org.apache.camel.component.jsonata.JsonataFrameBinding</code>
+         * type.
+         * 
+         * Group: advanced
+         * 
+         * @param frameBinding the value to set
+         * @return the dsl builder
+         */
+        default AdvancedJsonataEndpointBuilder 
frameBinding(org.apache.camel.component.jsonata.JsonataFrameBinding 
frameBinding) {
+            doSetProperty("frameBinding", frameBinding);
+            return this;
+        }
+        /**
+         * To configure the Jsonata frame binding. Allows custom functions to 
be
+         * added.
+         * 
+         * The option will be converted to a
+         * <code>org.apache.camel.component.jsonata.JsonataFrameBinding</code>
+         * type.
+         * 
+         * Group: advanced
+         * 
+         * @param frameBinding the value to set
+         * @return the dsl builder
+         */
+        default AdvancedJsonataEndpointBuilder frameBinding(String 
frameBinding) {
+            doSetProperty("frameBinding", frameBinding);
+            return this;
+        }
     }
 
     public interface JsonataBuilders {
diff --git 
a/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/JsonataUriDsl.kt
 
b/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/JsonataUriDsl.kt
index 3f84fd15b48..9b9a5228acf 100644
--- 
a/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/JsonataUriDsl.kt
+++ 
b/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/JsonataUriDsl.kt
@@ -124,4 +124,11 @@ public class JsonataUriDsl(
   public fun lazyStartProducer(lazyStartProducer: Boolean) {
     it.property("lazyStartProducer", lazyStartProducer.toString())
   }
+
+  /**
+   * To configure the Jsonata frame binding. Allows custom functions to be 
added.
+   */
+  public fun frameBinding(frameBinding: String) {
+    it.property("frameBinding", frameBinding)
+  }
 }


Reply via email to