You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2022/06/17 13:08:56 UTC
[camel] branch main updated: camel-jq: add an option to retrieve the payload to process from an exchange property
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 9f0b55d3c54 camel-jq: add an option to retrieve the payload to process from an exchange property
9f0b55d3c54 is described below
commit 9f0b55d3c54816e7d13126c33ae2b5f8571d9c63
Author: Luca Burgazzoli <lb...@gmail.com>
AuthorDate: Fri Jun 17 14:06:17 2022 +0200
camel-jq: add an option to retrieve the payload to process from an exchange property
---
.../resources/org/apache/camel/language/jq/jq.json | 2 +-
.../org/apache/camel/language/jq/JqExpression.java | 65 ++++++++++++++++-----
.../org/apache/camel/language/jq/JqLanguage.java | 11 ++++
...a => JqExpressionFromHeaderOrPropertyTest.java} | 48 ++++++++++-----
.../language/jq/JqExpressionFromHeaderTest.java | 38 ++++++++----
...Test.java => JqExpressionFromPropertyTest.java} | 18 +++---
.../language/jq/JqExpressionHeaderFnTest.java | 8 +--
.../language/jq/JqExpressionPropertyFnTest.java | 6 +-
.../camel/language/jq/JqExpressionSimpleTest.java | 7 +--
.../apache/camel/language/jq/JqTestSupport.java | 15 +++++
.../camel/NoSuchHeaderOrPropertyException.java | 68 ++++++++++++++++++++++
.../org/apache/camel/model/language/jq.json | 2 +-
.../org/apache/camel/builder/ExpressionClause.java | 47 +++++++++++----
.../camel/builder/ExpressionClauseSupport.java | 52 ++++++++++++++---
.../apache/camel/model/language/JqExpression.java | 17 ++++++
.../reifier/language/JqExpressionReifier.java | 3 +-
.../java/org/apache/camel/xml/in/ModelParser.java | 8 ++-
17 files changed, 328 insertions(+), 87 deletions(-)
diff --git a/components/camel-jq/src/generated/resources/org/apache/camel/language/jq/jq.json b/components/camel-jq/src/generated/resources/org/apache/camel/language/jq/jq.json
index 3051e61bbd6..a6d6bab62f2 100644
--- a/components/camel-jq/src/generated/resources/org/apache/camel/language/jq/jq.json
+++ b/components/camel-jq/src/generated/resources/org/apache/camel/language/jq/jq.json
@@ -18,7 +18,7 @@
"properties": {
"expression": { "kind": "value", "displayName": "Expression", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The expression value in your chosen language syntax" },
"resultType": { "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "headerName": { "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body" },
+ "headerName": { "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
"trim": { "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" },
"id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" }
}
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 97777d72724..7512312ec85 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
@@ -30,7 +30,7 @@ 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.NoSuchHeaderOrPropertyException;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.TypeConverter;
import org.apache.camel.spi.ExpressionResultTypeAware;
@@ -44,10 +44,12 @@ public class JqExpression extends ExpressionAdapter implements ExpressionResultT
private Scope scope;
private String resultTypeName;
private Class<?> resultType;
- private String headerName;
private JsonQuery query;
private TypeConverter typeConverter;
+ private String headerName;
+ private String propertyName;
+
public JqExpression(String expression) {
this(null, expression);
}
@@ -135,11 +137,26 @@ public class JqExpression extends ExpressionAdapter implements ExpressionResultT
/**
* Name of header to use as input, instead of the message body
+ * </p>
+ * It has as higher precedent than the propertyName if both are set.
*/
public void setHeaderName(String headerName) {
this.headerName = headerName;
}
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ /**
+ * Name of property to use as input, instead of the message body.
+ * </p>
+ * It has a lower precedent than the headerName if both are set.
+ */
+ public void setPropertyName(String propertyName) {
+ this.propertyName = propertyName;
+ }
+
@Override
public boolean matches(Exchange exchange) {
final Object value = evaluate(exchange, Object.class);
@@ -164,19 +181,7 @@ public class JqExpression extends ExpressionAdapter implements ExpressionResultT
JqFunctions.EXCHANGE_LOCAL.set(exchange);
final List<JsonNode> outputs = new ArrayList<>(1);
- final JsonNode payload;
-
- 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);
- }
- }
+ final JsonNode payload = getPayload(exchange);
this.query.apply(scope, payload, outputs::add);
@@ -205,4 +210,34 @@ public class JqExpression extends ExpressionAdapter implements ExpressionResultT
return null;
}
+
+ /**
+ * Determines the payload by looking at heders, properties and finally the payload.
+ *
+ * @param exchange the {@link Exchange} being processed
+ * @return the {@link JsonNode} to be processed by the expression
+ * @throws Exception
+ */
+ private JsonNode getPayload(Exchange exchange) throws Exception {
+ JsonNode payload = null;
+
+ if (headerName == null && propertyName == null) {
+ payload = exchange.getMessage().getBody(JsonNode.class);
+ if (payload == null) {
+ throw new InvalidPayloadException(exchange, JsonNode.class);
+ }
+ } else {
+ if (headerName != null) {
+ payload = exchange.getMessage().getHeader(headerName, JsonNode.class);
+ }
+ if (payload == null && propertyName != null) {
+ payload = exchange.getProperty(propertyName, JsonNode.class);
+ }
+ if (payload == null) {
+ throw new NoSuchHeaderOrPropertyException(exchange, headerName, propertyName, JsonNode.class);
+ }
+ }
+
+ return payload;
+ }
}
diff --git a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqLanguage.java b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqLanguage.java
index 30ad2c326e1..4803da6ad4a 100644
--- a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqLanguage.java
+++ b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqLanguage.java
@@ -28,6 +28,7 @@ public class JqLanguage extends LanguageSupport implements StaticService {
private Class<?> resultType;
private String headerName;
+ private String propertyName;
public Class<?> getResultType() {
return resultType;
@@ -45,6 +46,14 @@ public class JqLanguage extends LanguageSupport implements StaticService {
this.headerName = headerName;
}
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ public void setPropertyName(String propertyName) {
+ this.propertyName = propertyName;
+ }
+
@Override
public void start() {
// noop
@@ -70,6 +79,7 @@ public class JqLanguage extends LanguageSupport implements StaticService {
JqExpression answer = new JqExpression(expression);
answer.setResultType(resultType);
answer.setHeaderName(headerName);
+ answer.setPropertyName(propertyName);
answer.init(getCamelContext());
return answer;
}
@@ -79,6 +89,7 @@ public class JqLanguage extends LanguageSupport implements StaticService {
JqExpression answer = new JqExpression(expression);
answer.setResultType(property(Class.class, properties, 0, resultType));
answer.setHeaderName(property(String.class, properties, 1, headerName));
+ answer.setPropertyName(property(String.class, properties, 2, propertyName));
answer.init(getCamelContext());
return answer;
}
diff --git a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderOrPropertyTest.java
similarity index 56%
copy from components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java
copy to components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderOrPropertyTest.java
index 718d0e3bee5..3c43371840f 100644
--- a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java
+++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderOrPropertyTest.java
@@ -16,13 +16,12 @@
*/
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.NoSuchHeaderOrPropertyException;
import org.apache.camel.builder.RouteBuilder;
import org.junit.jupiter.api.Test;
-public class JqExpressionFromHeaderTest extends JqTestSupport {
+public class JqExpressionFromHeaderOrPropertyTest extends JqTestSupport {
@Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
@@ -30,9 +29,9 @@ public class JqExpressionFromHeaderTest extends JqTestSupport {
public void configure() {
from("direct:start")
.doTry()
- .transform().jq(".foo", "Content")
+ .transform().jq(".foo", "Content", "ContentProp")
.to("mock:result")
- .doCatch(NoSuchHeaderException.class)
+ .doCatch(NoSuchHeaderOrPropertyException.class)
.to("mock:fail");
}
@@ -40,31 +39,52 @@ public class JqExpressionFromHeaderTest extends JqTestSupport {
}
@Test
- public void testExpressionFromHeader() throws Exception {
+ public void testExpressionFromProperty() throws Exception {
getMockEndpoint("mock:result")
.expectedBodiesReceived(new TextNode("bar"));
getMockEndpoint("mock:fail")
.expectedMessageCount(0);
- ObjectNode node = MAPPER.createObjectNode();
- node.put("foo", "bar");
+ fluentTemplate.to("direct:start")
+ .withProcessor(e -> {
+ e.getMessage().setHeader("Invalid", node("foo", "baz"));
+ e.setProperty("ContentProp", node("foo", "bar"));
+ })
+ .send();
- template.sendBodyAndHeader("direct:start", null, "Content", node);
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testExpressionFromHeader() throws Exception {
+ getMockEndpoint("mock:result")
+ .expectedBodiesReceived(new TextNode("baz"));
+ getMockEndpoint("mock:fail")
+ .expectedMessageCount(0);
+
+ fluentTemplate.to("direct:start")
+ .withProcessor(e -> {
+ e.getMessage().setHeader("Content", node("foo", "baz"));
+ e.setProperty("ContentProp", node("foo", "bar"));
+ })
+ .send();
assertMockEndpointsSatisfied();
}
@Test
- public void testExpressionFromHeaderFail() throws Exception {
+ public void testExpressionFail() 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);
+ fluentTemplate.to("direct:start")
+ .withProcessor(e -> {
+ e.getMessage().setHeader("Invalid", node("foo", "baz"));
+ e.setProperty("Invalid", node("foo", "bar"));
+ })
+ .send();
assertMockEndpointsSatisfied();
}
diff --git a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java
index 718d0e3bee5..2737c907118 100644
--- a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java
+++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java
@@ -16,9 +16,8 @@
*/
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.NoSuchHeaderOrPropertyException;
import org.apache.camel.builder.RouteBuilder;
import org.junit.jupiter.api.Test;
@@ -32,7 +31,7 @@ public class JqExpressionFromHeaderTest extends JqTestSupport {
.doTry()
.transform().jq(".foo", "Content")
.to("mock:result")
- .doCatch(NoSuchHeaderException.class)
+ .doCatch(NoSuchHeaderOrPropertyException.class)
.to("mock:fail");
}
@@ -46,10 +45,28 @@ public class JqExpressionFromHeaderTest extends JqTestSupport {
getMockEndpoint("mock:fail")
.expectedMessageCount(0);
- ObjectNode node = MAPPER.createObjectNode();
- node.put("foo", "bar");
+ fluentTemplate.to("direct:start")
+ .withProcessor(e -> {
+ e.getMessage().setHeader("Content", node("foo", "bar"));
+ })
+ .send();
- template.sendBodyAndHeader("direct:start", null, "Content", node);
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testExpressionFromHeaderPriority() throws Exception {
+ getMockEndpoint("mock:result")
+ .expectedBodiesReceived(new TextNode("bar"));
+ getMockEndpoint("mock:fail")
+ .expectedMessageCount(0);
+
+ fluentTemplate.to("direct:start")
+ .withProcessor(e -> {
+ e.getMessage().setHeader("Content", node("foo", "bar"));
+ e.setProperty("Content", node("foo", "baz"));
+ })
+ .send();
assertMockEndpointsSatisfied();
}
@@ -61,10 +78,11 @@ public class JqExpressionFromHeaderTest extends JqTestSupport {
getMockEndpoint("mock:fail")
.expectedMessageCount(1);
- ObjectNode node = MAPPER.createObjectNode();
- node.put("foo", "bar");
-
- template.sendBody("direct:start", node);
+ fluentTemplate.to("direct:start")
+ .withProcessor(e -> {
+ e.getMessage().setBody(node("foo", "bar"));
+ })
+ .send();
assertMockEndpointsSatisfied();
}
diff --git a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromPropertyTest.java
similarity index 77%
copy from components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java
copy to components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromPropertyTest.java
index 718d0e3bee5..4e7aa9ce969 100644
--- a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromHeaderTest.java
+++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionFromPropertyTest.java
@@ -18,11 +18,11 @@ 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.NoSuchHeaderOrPropertyException;
import org.apache.camel.builder.RouteBuilder;
import org.junit.jupiter.api.Test;
-public class JqExpressionFromHeaderTest extends JqTestSupport {
+public class JqExpressionFromPropertyTest extends JqTestSupport {
@Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
@@ -32,7 +32,7 @@ public class JqExpressionFromHeaderTest extends JqTestSupport {
.doTry()
.transform().jq(".foo", "Content")
.to("mock:result")
- .doCatch(NoSuchHeaderException.class)
+ .doCatch(NoSuchHeaderOrPropertyException.class)
.to("mock:fail");
}
@@ -40,7 +40,7 @@ public class JqExpressionFromHeaderTest extends JqTestSupport {
}
@Test
- public void testExpressionFromHeader() throws Exception {
+ public void testExpressionFromProperty() throws Exception {
getMockEndpoint("mock:result")
.expectedBodiesReceived(new TextNode("bar"));
getMockEndpoint("mock:fail")
@@ -49,13 +49,15 @@ public class JqExpressionFromHeaderTest extends JqTestSupport {
ObjectNode node = MAPPER.createObjectNode();
node.put("foo", "bar");
- template.sendBodyAndHeader("direct:start", null, "Content", node);
+ fluentTemplate.to("direct:start")
+ .withProcessor(e -> e.setProperty("Content", node))
+ .send();
assertMockEndpointsSatisfied();
}
@Test
- public void testExpressionFromHeaderFail() throws Exception {
+ public void testExpressionFromPropertyFail() throws Exception {
getMockEndpoint("mock:result")
.expectedMessageCount(0);
getMockEndpoint("mock:fail")
@@ -64,7 +66,9 @@ public class JqExpressionFromHeaderTest extends JqTestSupport {
ObjectNode node = MAPPER.createObjectNode();
node.put("foo", "bar");
- template.sendBody("direct:start", node);
+ fluentTemplate.to("direct:start")
+ .withProcessor(e -> e.getMessage().setBody(node))
+ .send();
assertMockEndpointsSatisfied();
}
diff --git a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionHeaderFnTest.java b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionHeaderFnTest.java
index f45e3075323..f726bc0cf80 100644
--- a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionHeaderFnTest.java
+++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionHeaderFnTest.java
@@ -16,7 +16,6 @@
*/
package org.apache.camel.language.jq;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.camel.builder.RouteBuilder;
import org.junit.jupiter.api.Test;
@@ -36,12 +35,9 @@ public class JqExpressionHeaderFnTest extends JqTestSupport {
@Test
public void testExpression() throws Exception {
getMockEndpoint("mock:result")
- .expectedBodiesReceived(MAPPER.createObjectNode().put("foo", "MyValue"));
+ .expectedBodiesReceived(node("foo", "MyValue"));
- ObjectNode node = MAPPER.createObjectNode();
- node.put("foo", "bar");
-
- template.sendBodyAndHeader("direct:start", node, "MyHeader", "MyValue");
+ template.sendBodyAndHeader("direct:start", node("foo", "bar"), "MyHeader", "MyValue");
assertMockEndpointsSatisfied();
}
diff --git a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionPropertyFnTest.java b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionPropertyFnTest.java
index eeccf381c34..443a7dc0c76 100644
--- a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionPropertyFnTest.java
+++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionPropertyFnTest.java
@@ -16,7 +16,6 @@
*/
package org.apache.camel.language.jq;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.camel.builder.RouteBuilder;
import org.junit.jupiter.api.Test;
@@ -38,13 +37,10 @@ public class JqExpressionPropertyFnTest extends JqTestSupport {
getMockEndpoint("mock:result")
.expectedBodiesReceived(MAPPER.createObjectNode().put("foo", "MyPropertyValue"));
- ObjectNode node = MAPPER.createObjectNode();
- node.put("foo", "bar");
-
fluentTemplate.to("direct:start")
.withProcessor(e -> {
e.setProperty("MyProperty", "MyPropertyValue");
- e.getMessage().setBody(node);
+ e.getMessage().setBody(node("foo", "bar"));
})
.send();
diff --git a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionSimpleTest.java b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionSimpleTest.java
index 5757c8042bc..e112ea043c1 100644
--- a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionSimpleTest.java
+++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionSimpleTest.java
@@ -16,7 +16,6 @@
*/
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;
@@ -38,11 +37,7 @@ public class JqExpressionSimpleTest extends JqTestSupport {
public void testExpression() throws Exception {
getMockEndpoint("mock:result").expectedBodiesReceived(new TextNode("bar"));
- ObjectNode node = MAPPER.createObjectNode();
- node.put("foo", "bar");
- node.put("baz", "bak");
-
- template.sendBody("direct:start", node);
+ template.sendBody("direct:start", node("foo", "bar", "baz", "bak"));
assertMockEndpointsSatisfied();
}
diff --git a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqTestSupport.java b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqTestSupport.java
index a0416bde7d5..d0c5566d5cf 100644
--- a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqTestSupport.java
+++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqTestSupport.java
@@ -17,8 +17,23 @@
package org.apache.camel.language.jq;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.camel.test.junit5.CamelTestSupport;
public abstract class JqTestSupport extends CamelTestSupport {
public static final ObjectMapper MAPPER = new ObjectMapper();
+
+ public static ObjectNode node(String key, String value, String... keyVals) {
+ ObjectNode answer = MAPPER.createObjectNode();
+
+ answer.put(key, value);
+
+ for (int i = 0; i < keyVals.length; i += 2) {
+ answer.put(
+ keyVals[i],
+ keyVals[i + 1]);
+ }
+
+ return answer;
+ }
}
diff --git a/core/camel-api/src/main/java/org/apache/camel/NoSuchHeaderOrPropertyException.java b/core/camel-api/src/main/java/org/apache/camel/NoSuchHeaderOrPropertyException.java
new file mode 100644
index 00000000000..8e8d4221d4a
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/NoSuchHeaderOrPropertyException.java
@@ -0,0 +1,68 @@
+/*
+ * 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;
+
+public class NoSuchHeaderOrPropertyException extends CamelExchangeException {
+
+ private final String headerName;
+ private final String propertyName;
+ private final transient Class<?> type;
+
+ public NoSuchHeaderOrPropertyException(Exchange exchange, String headerName, String propertyName, Class<?> type) {
+ super(String.format(
+ "Np '%s' header or '%s' property available of type: %s (header: %s, property: %s)",
+ headerName,
+ propertyName,
+ type.getName(),
+ header(exchange, headerName),
+ property(exchange, headerName)),
+ exchange);
+
+ this.headerName = headerName;
+ this.propertyName = propertyName;
+ this.type = type;
+ }
+
+ public String getHeaderName() {
+ return headerName;
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ public Class<?> getType() {
+ return type;
+ }
+
+ protected static String header(Exchange exchange, String headerName) {
+ Object value = exchange.getMessage().getHeader(headerName);
+ return valueDescription(value);
+ }
+
+ protected static String property(Exchange exchange, String propertyName) {
+ Object value = exchange.getProperty(propertyName);
+ return valueDescription(value);
+ }
+
+ static String valueDescription(Object value) {
+ if (value == null) {
+ return "null";
+ }
+ return "has value: " + value + " of type: " + value.getClass().getCanonicalName();
+ }
+}
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jq.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jq.json
index 5f7ff9a0664..4d69c75867a 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jq.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jq.json
@@ -15,7 +15,7 @@
"properties": {
"expression": { "kind": "value", "displayName": "Expression", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The expression value in your chosen language syntax" },
"resultType": { "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "headerName": { "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body" },
+ "headerName": { "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
"trim": { "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" },
"id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" }
}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java
index 440f7b4d71d..d785fe9a27c 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java
@@ -402,24 +402,49 @@ public class ExpressionClause<T> implements Expression, Predicate {
/**
* Evaluates a <a href="http://camel.apache.org/jq.html">JQ expression</a>
*
- * @param value the expression to be evaluated
- * @param headerName the name of the header to apply the expression to
- * @return the builder to continue processing the DSL
+ * @param value the expression to be evaluated
+ * @param headerOrPropertyName the name of the header or property to apply the expression to
+ * @return the builder to continue processing the DSL
*/
- public T jq(String value, String headerName) {
- return delegate.jq(value, headerName);
+ public T jq(String value, String headerOrPropertyName) {
+ return delegate.jq(value, headerOrPropertyName);
}
/**
* Evaluates a <a href="http://camel.apache.org/jq.html">JQ expression</a>
*
- * @param value the expression to be evaluated
- * @param resultType the return type expected by the expression
- * @param headerName the name of the header to apply the expression to
- * @return the builder to continue processing the DSL
+ * @param value the expression to be evaluated
+ * @param headerName the name of the header to apply the expression to
+ * @param propertyName the name of the property to apply the expression to
+ * @return the builder to continue processing the DSL
+ */
+ public T jq(String value, String headerName, String propertyName) {
+ return delegate.jq(value, headerName, propertyName);
+ }
+
+ /**
+ * Evaluates a <a href="http://camel.apache.org/jq.html">JQ expression</a>
+ *
+ * @param value the expression to be evaluated
+ * @param resultType the return type expected by the expression
+ * @param headerOrPropertyName the name of the header or property to apply the expression to
+ * @return the builder to continue processing the DSL
+ */
+ public T jq(String value, Class<?> resultType, String headerOrPropertyName) {
+ return delegate.jq(value, resultType, headerOrPropertyName);
+ }
+
+ /**
+ * Evaluates a <a href="http://camel.apache.org/jq.html">JQ expression</a>
+ *
+ * @param value the expression to be evaluated
+ * @param resultType the return type expected by the expression
+ * @param headerName the name of the header to apply the expression to
+ * @param propertyName the name of the property to apply the expression to
+ * @return the builder to continue processing the DSL
*/
- public T jq(String value, Class<?> resultType, String headerName) {
- return delegate.jq(value, resultType, headerName);
+ public T jq(String value, Class<?> resultType, String headerName, String propertyName) {
+ return delegate.jq(value, resultType, headerName, propertyName);
}
/**
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
index ca3b05b3c36..fba2d270aa6 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
@@ -398,28 +398,62 @@ public class ExpressionClauseSupport<T> implements ExpressionFactoryAware, Predi
/**
* Evaluates <a href="http://camel.apache.org/jq.html">JQ expression</a>
*
- * @param text the expression to be evaluated
- * @param headerName the name of the header to apply the expression to
- * @return the builder to continue processing the DSL
+ * @param text the expression to be evaluated
+ * @param headerOrPropertyName the name of the header or the property to apply the expression to
+ * @return the builder to continue processing the DSL
+ */
+ public T jq(String text, String headerOrPropertyName) {
+ JqExpression exp = new JqExpression(text);
+ exp.setHeaderName(headerOrPropertyName);
+ exp.setPropertyName(headerOrPropertyName);
+ return expression(exp);
+ }
+
+ /**
+ * Evaluates <a href="http://camel.apache.org/jq.html">JQ expression</a>
+ *
+ * @param text the expression to be evaluated
+ * @param headerName the name of the header to apply the expression to
+ * @param propertyName the name of the propertyName to apply the expression to
+ * @return the builder to continue processing the DSL
*/
- public T jq(String text, String headerName) {
+ public T jq(String text, String headerName, String propertyName) {
JqExpression exp = new JqExpression(text);
exp.setHeaderName(headerName);
+ exp.setPropertyName(propertyName);
return expression(exp);
}
/**
* Evaluates <a href="http://camel.apache.org/jq.html">JQ expression</a>
*
- * @param text the expression to be evaluated
- * @param resultType the return type expected by the expression
- * @param headerName the name of the header to apply the expression to
- * @return the builder to continue processing the DSL
+ * @param text the expression to be evaluated
+ * @param resultType the return type expected by the expression
+ * @param headerOrPropertyName the name of the header or the property to apply the expression to
+ * @return the builder to continue processing the DSL
+ */
+ public T jq(String text, Class<?> resultType, String headerOrPropertyName) {
+ JqExpression exp = new JqExpression(text);
+ exp.setResultType(resultType);
+ exp.setHeaderName(headerOrPropertyName);
+ exp.setPropertyName(headerOrPropertyName);
+ return expression(exp);
+ }
+
+ /**
+ * Evaluates <a href="http://camel.apache.org/jq.html">JQ expression</a>
+ *
+ * @param text the expression to be evaluated
+ * @param resultType the return type expected by the expression
+ * @param headerName the name of the header to apply the expression to
+ * @param propertyName the name of the propertyName to apply the expression to
+ * @return the builder to continue processing the DSL
*/
- public T jq(String text, Class<?> resultType, String headerName) {
+ public T jq(String text, Class<?> resultType, String headerName, String propertyName) {
JqExpression exp = new JqExpression(text);
exp.setResultType(resultType);
exp.setHeaderName(headerName);
+ exp.setPropertyName(propertyName);
return expression(exp);
}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/JqExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/JqExpression.java
index 1dc1bd91943..ee8a1b95bcf 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/JqExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/JqExpression.java
@@ -38,6 +38,8 @@ public class JqExpression extends ExpressionDefinition {
@XmlAttribute
@Metadata(label = "advanced")
private String headerName;
+ @Metadata(label = "advanced")
+ private String propertyName;
public JqExpression() {
}
@@ -79,8 +81,23 @@ public class JqExpression extends ExpressionDefinition {
/**
* Name of header to use as input, instead of the message body
+ * </p>
+ * It has as higher precedent than the propertyName if both are set.
*/
public void setHeaderName(String headerName) {
this.headerName = headerName;
}
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ /**
+ * Name of property to use as input, instead of the message body.
+ * </p>
+ * It has a lower precedent than the headerName if both are set.
+ */
+ public void setPropertyName(String propertyName) {
+ this.propertyName = propertyName;
+ }
}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/JqExpressionReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/JqExpressionReifier.java
index d2a4c5a23f2..fe3a5c1a4e4 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/JqExpressionReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/JqExpressionReifier.java
@@ -43,9 +43,10 @@ public class JqExpressionReifier extends ExpressionReifier<JqExpression> {
}
private Object[] createProperties() {
- Object[] properties = new Object[2];
+ Object[] properties = new Object[3];
properties[0] = definition.getResultType();
properties[1] = parseString(definition.getHeaderName());
+ properties[2] = parseString(definition.getPropertyName());
return properties;
}
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index 4cae265b4f6..4398c2d3f46 100644
--- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
+++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
@@ -2653,7 +2653,13 @@ public class ModelParser extends BaseParser {
default: return expressionDefinitionAttributeHandler().accept(def, key, val);
}
return true;
- }, noElementHandler(), expressionDefinitionValueHandler());
+ }, (def, key) -> {
+ if ("propertyName".equals(key)) {
+ def.setPropertyName(doParseText());
+ return true;
+ }
+ return false;
+ }, expressionDefinitionValueHandler());
}
protected JsonPathExpression doParseJsonPathExpression() throws IOException, XmlPullParserException {
return doParse(new JsonPathExpression(), (def, key, val) -> {