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 <lburgazz...@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) -> {