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

lburgazzoli 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 3096762b96a camel-jq: add a function to retrieve value from Exchange 
properties
3096762b96a is described below

commit 3096762b96aee19841d83124bb95518f68d6a46c
Author: Luca Burgazzoli <lburgazz...@gmail.com>
AuthorDate: Thu Jun 16 19:46:23 2022 +0200

    camel-jq: add a function to retrieve value from Exchange properties
---
 .../org/apache/camel/language/jq/JqExpression.java |  17 +++-
 .../org/apache/camel/language/jq/JqFunctions.java  | 104 +++++++++++++++++++--
 ...ava => JqExpressionFromHeaderAsStringTest.java} |   4 +-
 ...erTest.java => JqExpressionFromHeaderTest.java} |  28 +++++-
 ...erFnTest.java => JqExpressionHeaderFnTest.java} |   4 +-
 ...elloPojoTest.java => JqExpressionPojoTest.java} |   4 +-
 ...erTest.java => JqExpressionPropertyFnTest.java} |  16 ++--
 ...qHelloTest.java => JqExpressionSimpleTest.java} |   4 +-
 .../apache/camel/language/jq/JqExpressionTest.java |  41 ++++++++
 9 files changed, 193 insertions(+), 29 deletions(-)

diff --git 
a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqExpression.java
 
b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqExpression.java
index d30343a3b00..97777d72724 100644
--- 
a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqExpression.java
+++ 
b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqExpression.java
@@ -29,6 +29,8 @@ import net.thisptr.jackson.jq.Versions;
 import net.thisptr.jackson.jq.exception.JsonQueryException;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.NoSuchHeaderException;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.TypeConverter;
 import org.apache.camel.spi.ExpressionResultTypeAware;
@@ -162,10 +164,19 @@ public class JqExpression extends ExpressionAdapter 
implements ExpressionResultT
             JqFunctions.EXCHANGE_LOCAL.set(exchange);
 
             final List<JsonNode> outputs = new ArrayList<>(1);
+            final JsonNode payload;
 
-            final JsonNode payload = headerName == null
-                    ? exchange.getMessage().getMandatoryBody(JsonNode.class)
-                    : exchange.getMessage().getHeader(headerName, 
JsonNode.class);
+            if (headerName == null) {
+                payload = exchange.getMessage().getBody(JsonNode.class);
+                if (payload == null) {
+                    throw new InvalidPayloadException(exchange, 
JsonNode.class);
+                }
+            } else {
+                payload = exchange.getMessage().getHeader(headerName, 
JsonNode.class);
+                if (payload == null) {
+                    throw new NoSuchHeaderException(exchange, headerName, 
JsonNode.class);
+                }
+            }
 
             this.query.apply(scope, payload, outputs::add);
 
diff --git 
a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqFunctions.java
 
b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqFunctions.java
index 1b6264a6f21..114d0312a84 100644
--- 
a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqFunctions.java
+++ 
b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqFunctions.java
@@ -82,6 +82,32 @@ public final class JqFunctions {
     public static void loadLocal(Scope scope) {
         scope.addFunction(Header.NAME, 1, new Header());
         scope.addFunction(Header.NAME, 2, new Header());
+        scope.addFunction(Property.NAME, 1, new Property());
+        scope.addFunction(Property.NAME, 2, new Property());
+    }
+
+    public abstract static class ExchangeAwareFunction implements Function {
+
+        @Override
+        public void apply(Scope scope, List<Expression> args, JsonNode in, 
Path path, PathOutput output, Version version)
+                throws JsonQueryException {
+
+            Exchange exchange = EXCHANGE_LOCAL.get();
+
+            if (exchange != null) {
+                doApply(scope, args, in, path, output, version, exchange);
+            }
+        }
+
+        protected abstract void doApply(
+                Scope scope,
+                List<Expression> args,
+                JsonNode in,
+                Path path,
+                PathOutput output,
+                Version version,
+                Exchange exchange)
+                throws JsonQueryException;
     }
 
     /**
@@ -98,30 +124,90 @@ public final class JqFunctions {
      * </pre>
      *
      */
-    public static class Header implements Function {
+    public static class Header extends ExchangeAwareFunction {
         public static final String NAME = "header";
 
         @Override
-        public void apply(Scope scope, List<Expression> args, JsonNode in, 
Path path, PathOutput output, Version version)
+        protected void doApply(
+                Scope scope,
+                List<Expression> args,
+                JsonNode in,
+                Path path,
+                PathOutput output,
+                Version version,
+                Exchange exchange)
                 throws JsonQueryException {
 
-            Exchange exchange = EXCHANGE_LOCAL.get();
+            args.get(0).apply(scope, in, name -> {
+                if (args.size() == 2) {
+                    args.get(1).apply(scope, in, defval -> {
+                        extract(
+                                exchange,
+                                name.asText(),
+                                defval.asText(),
+                                output);
+                    });
+                } else {
+                    extract(
+                            exchange,
+                            name.asText(),
+                            null,
+                            output);
+                }
+            });
+        }
 
-            if (exchange == null) {
-                return;
+        private void extract(Exchange exchange, String headerName, String 
headerValue, PathOutput output)
+                throws JsonQueryException {
+            String header = exchange.getMessage().getHeader(headerName, 
headerValue, String.class);
+
+            if (header == null) {
+                output.emit(NullNode.getInstance(), null);
+            } else {
+                output.emit(new TextNode(header), null);
             }
+        }
+    }
+
+    /**
+     * A function that allow to retrieve an {@link org.apache.camel.Message} 
property value as part of JQ expression
+     * evaluation.
+     *
+     * As example, the following JQ expression sets the {@code .name} property 
to the value of the header named
+     * {@code CommitterName}.
+     *
+     * <pre>
+     * {@code
+     * .name = proeprty(\"CommitterName\")"
+     * }
+     * </pre>
+     *
+     */
+    public static class Property extends ExchangeAwareFunction {
+        public static final String NAME = "property";
+
+        @Override
+        protected void doApply(
+                Scope scope,
+                List<Expression> args,
+                JsonNode in,
+                Path path,
+                PathOutput output,
+                Version version,
+                Exchange exchange)
+                throws JsonQueryException {
 
             args.get(0).apply(scope, in, name -> {
                 if (args.size() == 2) {
                     args.get(1).apply(scope, in, defval -> {
-                        doApply(
+                        extract(
                                 exchange,
                                 name.asText(),
                                 defval.asText(),
                                 output);
                     });
                 } else {
-                    doApply(
+                    extract(
                             exchange,
                             name.asText(),
                             null,
@@ -130,9 +216,9 @@ public final class JqFunctions {
             });
         }
 
-        private void doApply(Exchange exchange, String headerName, String 
headerValue, PathOutput output)
+        private void extract(Exchange exchange, String propertyName, String 
propertyValue, PathOutput output)
                 throws JsonQueryException {
-            String header = exchange.getMessage().getHeader(headerName, 
headerValue, String.class);
+            String header = exchange.getProperty(propertyName, propertyValue, 
String.class);
 
             if (header == null) {
                 output.emit(NullNode.getInstance(), null);
diff --git 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloFromHeaderAsStringTest.java
 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderAsStringTest.java
similarity index 92%
rename from 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloFromHeaderAsStringTest.java
rename to 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderAsStringTest.java
index 52017d965d7..596d37c8f3c 100644
--- 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloFromHeaderAsStringTest.java
+++ 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderAsStringTest.java
@@ -20,7 +20,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.apache.camel.builder.RouteBuilder;
 import org.junit.jupiter.api.Test;
 
-public class JqHelloFromHeaderAsStringTest extends JqTestSupport {
+public class JqExpressionFromHeaderAsStringTest extends JqTestSupport {
     @Override
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
@@ -34,7 +34,7 @@ public class JqHelloFromHeaderAsStringTest extends 
JqTestSupport {
     }
 
     @Test
-    public void testHelloHeader() throws Exception {
+    public void testExpression() throws Exception {
         getMockEndpoint("mock:result").expectedBodiesReceived("bar");
 
         ObjectNode node = MAPPER.createObjectNode();
diff --git 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloFromHeaderTest.java
 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java
similarity index 65%
copy from 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloFromHeaderTest.java
copy to 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java
index dd443d0c865..718d0e3bee5 100644
--- 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloFromHeaderTest.java
+++ 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java
@@ -18,26 +18,33 @@ package org.apache.camel.language.jq;
 
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.fasterxml.jackson.databind.node.TextNode;
+import org.apache.camel.NoSuchHeaderException;
 import org.apache.camel.builder.RouteBuilder;
 import org.junit.jupiter.api.Test;
 
-public class JqHelloFromHeaderTest extends JqTestSupport {
+public class JqExpressionFromHeaderTest extends JqTestSupport {
     @Override
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
             @Override
             public void configure() {
                 from("direct:start")
+                        .doTry()
                         .transform().jq(".foo", "Content")
-                        .to("mock:result");
+                        .to("mock:result")
+                        .doCatch(NoSuchHeaderException.class)
+                        .to("mock:fail");
+
             }
         };
     }
 
     @Test
-    public void testHelloHeader() throws Exception {
+    public void testExpressionFromHeader() throws Exception {
         getMockEndpoint("mock:result")
                 .expectedBodiesReceived(new TextNode("bar"));
+        getMockEndpoint("mock:fail")
+                .expectedMessageCount(0);
 
         ObjectNode node = MAPPER.createObjectNode();
         node.put("foo", "bar");
@@ -46,4 +53,19 @@ public class JqHelloFromHeaderTest extends JqTestSupport {
 
         assertMockEndpointsSatisfied();
     }
+
+    @Test
+    public void testExpressionFromHeaderFail() throws Exception {
+        getMockEndpoint("mock:result")
+                .expectedMessageCount(0);
+        getMockEndpoint("mock:fail")
+                .expectedMessageCount(1);
+
+        ObjectNode node = MAPPER.createObjectNode();
+        node.put("foo", "bar");
+
+        template.sendBody("direct:start", node);
+
+        assertMockEndpointsSatisfied();
+    }
 }
diff --git 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloHeaderFnTest.java
 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionHeaderFnTest.java
similarity index 93%
rename from 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloHeaderFnTest.java
rename to 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionHeaderFnTest.java
index e161413995e..f45e3075323 100644
--- 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloHeaderFnTest.java
+++ 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionHeaderFnTest.java
@@ -20,7 +20,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.apache.camel.builder.RouteBuilder;
 import org.junit.jupiter.api.Test;
 
-public class JqHelloHeaderFnTest extends JqTestSupport {
+public class JqExpressionHeaderFnTest extends JqTestSupport {
     @Override
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
@@ -34,7 +34,7 @@ public class JqHelloHeaderFnTest extends JqTestSupport {
     }
 
     @Test
-    public void testHelloHeader() throws Exception {
+    public void testExpression() throws Exception {
         getMockEndpoint("mock:result")
                 .expectedBodiesReceived(MAPPER.createObjectNode().put("foo", 
"MyValue"));
 
diff --git 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloPojoTest.java
 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionPojoTest.java
similarity index 96%
rename from 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloPojoTest.java
rename to 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionPojoTest.java
index 99315c17cb3..87d6ad49f49 100644
--- 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloPojoTest.java
+++ 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionPojoTest.java
@@ -24,7 +24,7 @@ import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.jackson.JacksonConstants;
 import org.junit.jupiter.api.Test;
 
-public class JqHelloPojoTest extends JqTestSupport {
+public class JqExpressionPojoTest extends JqTestSupport {
 
     @Override
     protected CamelContext createCamelContext() throws Exception {
@@ -48,7 +48,7 @@ public class JqHelloPojoTest extends JqTestSupport {
     }
 
     @Test
-    public void testHello() throws Exception {
+    public void testExpression() throws Exception {
         getMockEndpoint("mock:result").expectedBodiesReceived(new Book("foo", 
"bar"));
 
         ObjectNode node = MAPPER.createObjectNode();
diff --git 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloFromHeaderTest.java
 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionPropertyFnTest.java
similarity index 73%
rename from 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloFromHeaderTest.java
rename to 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionPropertyFnTest.java
index dd443d0c865..eeccf381c34 100644
--- 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloFromHeaderTest.java
+++ 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionPropertyFnTest.java
@@ -17,32 +17,36 @@
 package org.apache.camel.language.jq;
 
 import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.fasterxml.jackson.databind.node.TextNode;
 import org.apache.camel.builder.RouteBuilder;
 import org.junit.jupiter.api.Test;
 
-public class JqHelloFromHeaderTest extends JqTestSupport {
+public class JqExpressionPropertyFnTest extends JqTestSupport {
     @Override
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
             @Override
             public void configure() {
                 from("direct:start")
-                        .transform().jq(".foo", "Content")
+                        .transform().jq(".foo = property(\"MyProperty\")")
                         .to("mock:result");
             }
         };
     }
 
     @Test
-    public void testHelloHeader() throws Exception {
+    public void testExpression() throws Exception {
         getMockEndpoint("mock:result")
-                .expectedBodiesReceived(new TextNode("bar"));
+                .expectedBodiesReceived(MAPPER.createObjectNode().put("foo", 
"MyPropertyValue"));
 
         ObjectNode node = MAPPER.createObjectNode();
         node.put("foo", "bar");
 
-        template.sendBodyAndHeader("direct:start", null, "Content", node);
+        fluentTemplate.to("direct:start")
+                .withProcessor(e -> {
+                    e.setProperty("MyProperty", "MyPropertyValue");
+                    e.getMessage().setBody(node);
+                })
+                .send();
 
         assertMockEndpointsSatisfied();
     }
diff --git 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloTest.java
 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionSimpleTest.java
similarity index 93%
rename from 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloTest.java
rename to 
components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionSimpleTest.java
index 61a40cd48ca..5757c8042bc 100644
--- 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloTest.java
+++ 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionSimpleTest.java
@@ -21,7 +21,7 @@ import com.fasterxml.jackson.databind.node.TextNode;
 import org.apache.camel.builder.RouteBuilder;
 import org.junit.jupiter.api.Test;
 
-public class JqHelloTest extends JqTestSupport {
+public class JqExpressionSimpleTest extends JqTestSupport {
     @Override
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
@@ -35,7 +35,7 @@ public class JqHelloTest extends JqTestSupport {
     }
 
     @Test
-    public void testHello() throws Exception {
+    public void testExpression() throws Exception {
         getMockEndpoint("mock:result").expectedBodiesReceived(new 
TextNode("bar"));
 
         ObjectNode node = MAPPER.createObjectNode();
diff --git 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionTest.java
 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionTest.java
index a17a6034ffd..04996682291 100644
--- 
a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionTest.java
+++ 
b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionTest.java
@@ -53,6 +53,24 @@ public class JqExpressionTest {
         }
     }
 
+    @Test
+    public void extractProperty() throws Exception {
+        try (CamelContext context = new DefaultCamelContext()) {
+            Exchange exchange = new DefaultExchange(context);
+            exchange.getMessage().setBody(MAPPER.createObjectNode());
+            exchange.setProperty("CommitterName", "Andrea");
+
+            JqExpression expression = new 
JqExpression("property(\"CommitterName\")");
+            expression.init(context);
+
+            JsonNode result = expression.evaluate(exchange, JsonNode.class);
+
+            assertThatJson(result)
+                    .isString()
+                    .isEqualTo("Andrea");
+        }
+    }
+
     @Test
     public void extractHeaderWithDefault() throws Exception {
         try (CamelContext context = new DefaultCamelContext()) {
@@ -184,6 +202,29 @@ public class JqExpressionTest {
         }
     }
 
+    @Test
+    public void setFieldFromProperty() throws Exception {
+        try (CamelContext context = new DefaultCamelContext()) {
+            ObjectNode node = MAPPER.createObjectNode();
+            node.with("commit").put("name", "Nicolas Williams");
+            node.with("commit").put("message", "Reject all overlong UTF8 
sequences.");
+
+            Exchange exchange = new DefaultExchange(context);
+            exchange.setProperty("CommitterName", "Andrea");
+            exchange.getMessage().setBody(node);
+
+            JqExpression expression = new JqExpression(".commit.name = 
property(\"CommitterName\")");
+            expression.init(context);
+
+            JsonNode result = expression.evaluate(exchange, JsonNode.class);
+
+            assertThatJson(result)
+                    .inPath("$.commit.name")
+                    .isString()
+                    .isEqualTo("Andrea");
+        }
+    }
+
     @Test
     public void removeField() throws Exception {
         try (CamelContext context = new DefaultCamelContext()) {

Reply via email to