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
commit 102ac539105072137d0318434f5dd42aab9b82e1 Author: Luca Burgazzoli <lburgazz...@gmail.com> AuthorDate: Wed Jun 1 20:15:36 2022 +0200 CAMEL-14847: create a camel-jq component --- bom/camel-bom/pom.xml | 5 + camel-dependencies/pom.xml | 1 + catalog/camel-allcomponents/pom.xml | 4 + components/camel-jq/pom.xml | 93 ++++++++ .../services/org/apache/camel/language.properties | 7 + .../META-INF/services/org/apache/camel/language/jq | 2 + .../camel-jq/src/generated/resources/jq.json | 14 ++ .../resources/org/apache/camel/language/jq/jq.json | 25 +++ components/camel-jq/src/main/docs/jq-language.adoc | 88 ++++++++ .../main/java/org/apache/camel/language/jq/Jq.java | 35 +++ .../org/apache/camel/language/jq/JqExpression.java | 197 +++++++++++++++++ .../org/apache/camel/language/jq/JqFunctions.java | 144 ++++++++++++ .../org/apache/camel/language/jq/JqLanguage.java | 85 ++++++++ .../apache/camel/language/jq/JqExpressionTest.java | 242 +++++++++++++++++++++ .../org/apache/camel/language/jq/JqFilterTest.java | 44 ++++ .../camel/language/jq/JqHelloFromHeaderTest.java | 49 +++++ .../camel/language/jq/JqHelloHeaderFnTest.java | 48 ++++ .../apache/camel/language/jq/JqHelloPojoTest.java | 107 +++++++++ .../org/apache/camel/language/jq/JqHelloTest.java | 49 +++++ .../apache/camel/language/jq/JqTestSupport.java | 24 ++ .../camel-jq/src/test/resources/log4j2.properties | 31 +++ components/pom.xml | 1 + .../services/org/apache/camel/model.properties | 1 + .../org/apache/camel/model/aggregate.json | 8 +- .../resources/org/apache/camel/model/delay.json | 2 +- .../org/apache/camel/model/dynamicRouter.json | 2 +- .../resources/org/apache/camel/model/enrich.json | 2 +- .../resources/org/apache/camel/model/filter.json | 2 +- .../org/apache/camel/model/idempotentConsumer.json | 2 +- .../org/apache/camel/model/language/jaxb.index | 1 + .../org/apache/camel/model/language/jq.json | 22 ++ .../apache/camel/model/loadbalancer/sticky.json | 2 +- .../resources/org/apache/camel/model/loop.json | 2 +- .../org/apache/camel/model/onException.json | 6 +- .../org/apache/camel/model/pollEnrich.json | 2 +- .../org/apache/camel/model/propertyExpression.json | 2 +- .../org/apache/camel/model/recipientList.json | 2 +- .../org/apache/camel/model/resequence.json | 2 +- .../org/apache/camel/model/routingSlip.json | 2 +- .../resources/org/apache/camel/model/script.json | 2 +- .../resources/org/apache/camel/model/setBody.json | 2 +- .../org/apache/camel/model/setHeader.json | 2 +- .../org/apache/camel/model/setProperty.json | 2 +- .../resources/org/apache/camel/model/sort.json | 2 +- .../resources/org/apache/camel/model/split.json | 2 +- .../resources/org/apache/camel/model/throttle.json | 4 +- .../org/apache/camel/model/transform.json | 2 +- .../resources/org/apache/camel/model/validate.json | 2 +- .../resources/org/apache/camel/model/when.json | 2 +- .../apache/camel/model/whenSkipSendToEndpoint.json | 2 +- .../java/org/apache/camel/builder/Builder.java | 18 ++ .../org/apache/camel/builder/ExpressionClause.java | 44 ++++ .../camel/builder/ExpressionClauseSupport.java | 52 +++++ .../apache/camel/model/language/JqExpression.java | 86 ++++++++ .../camel/reifier/language/ExpressionReifier.java | 3 + .../reifier/language/JqExpressionReifier.java | 68 ++++++ .../java/org/apache/camel/xml/in/ModelParser.java | 11 + parent/pom.xml | 12 + 58 files changed, 1644 insertions(+), 31 deletions(-) diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml index 22ac7386481..264d992d07d 100644 --- a/bom/camel-bom/pom.xml +++ b/bom/camel-bom/pom.xml @@ -1197,6 +1197,11 @@ <artifactId>camel-jpa</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-jq</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-js-dsl</artifactId> diff --git a/camel-dependencies/pom.xml b/camel-dependencies/pom.xml index b12144ab478..b23b1130171 100644 --- a/camel-dependencies/pom.xml +++ b/camel-dependencies/pom.xml @@ -275,6 +275,7 @@ <ironmq-version>3.0.5</ironmq-version> <ivy-version>2.5.0</ivy-version> <jackrabbit-version>2.21.10</jackrabbit-version> + <jackson-jq-version>1.0.0-preview.20210928</jackson-jq-version> <jackson-version>1.9.12</jackson-version> <jackson2-version>2.13.3</jackson2-version> <jakarta-api-version>2.1.5</jakarta-api-version> diff --git a/catalog/camel-allcomponents/pom.xml b/catalog/camel-allcomponents/pom.xml index 5bbd47d99e4..30c313535d3 100644 --- a/catalog/camel-allcomponents/pom.xml +++ b/catalog/camel-allcomponents/pom.xml @@ -797,6 +797,10 @@ <groupId>org.apache.camel</groupId> <artifactId>camel-jpa</artifactId> </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-jq</artifactId> + </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jsch</artifactId> diff --git a/components/camel-jq/pom.xml b/components/camel-jq/pom.xml new file mode 100644 index 00000000000..ae012f2bb43 --- /dev/null +++ b/components/camel-jq/pom.xml @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.camel</groupId> + <artifactId>components</artifactId> + <version>3.18.0-SNAPSHOT</version> + </parent> + + <artifactId>camel-jq</artifactId> + <packaging>jar</packaging> + <name>Camel :: JQ</name> + <description>Java expression language using JQ</description> + + <properties> + <firstVersion>3.18.0</firstVersion> + <sourcecheckExcludes> + **/MyRoutes*.java + </sourcecheckExcludes> + <sourcecheckExcludesComma> + ${sourcecheckExcludes}, + </sourcecheckExcludesComma> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-support</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-jackson</artifactId> + </dependency> + + <dependency> + <groupId>net.thisptr</groupId> + <artifactId>jackson-jq</artifactId> + <version>${jackson-jq-version}</version> + </dependency> + + <!-- test dependencies --> + <dependency> + <groupId>net.javacrumbs.json-unit</groupId> + <artifactId>json-unit</artifactId> + <version>${json-unit-version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>net.javacrumbs.json-unit</groupId> + <artifactId>json-unit-assertj</artifactId> + <version>${json-unit-version}</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-junit5</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-slf4j-impl</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + +</project> \ No newline at end of file diff --git a/components/camel-jq/src/generated/resources/META-INF/services/org/apache/camel/language.properties b/components/camel-jq/src/generated/resources/META-INF/services/org/apache/camel/language.properties new file mode 100644 index 00000000000..ba42174dee7 --- /dev/null +++ b/components/camel-jq/src/generated/resources/META-INF/services/org/apache/camel/language.properties @@ -0,0 +1,7 @@ +# Generated by camel build tools - do NOT edit this file! +languages=jq +groupId=org.apache.camel +artifactId=camel-jq +version=3.18.0-SNAPSHOT +projectName=Camel :: JQ +projectDescription=Java expression language using JQ diff --git a/components/camel-jq/src/generated/resources/META-INF/services/org/apache/camel/language/jq b/components/camel-jq/src/generated/resources/META-INF/services/org/apache/camel/language/jq new file mode 100644 index 00000000000..1d82f43387b --- /dev/null +++ b/components/camel-jq/src/generated/resources/META-INF/services/org/apache/camel/language/jq @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.language.jq.JqLanguage diff --git a/components/camel-jq/src/generated/resources/jq.json b/components/camel-jq/src/generated/resources/jq.json new file mode 100644 index 00000000000..1abe9b039c6 --- /dev/null +++ b/components/camel-jq/src/generated/resources/jq.json @@ -0,0 +1,14 @@ +{ + "other": { + "kind": "other", + "name": "jq", + "title": "Jq", + "description": "Java expression language using JQ", + "deprecated": false, + "firstVersion": "3.18.0", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-jq", + "version": "3.18.0-SNAPSHOT" + } +} 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 new file mode 100644 index 00000000000..3051e61bbd6 --- /dev/null +++ b/components/camel-jq/src/generated/resources/org/apache/camel/language/jq/jq.json @@ -0,0 +1,25 @@ +{ + "language": { + "kind": "language", + "name": "jq", + "title": "JQ", + "description": "Evaluates a JQ expression against a JSON message body.", + "deprecated": false, + "firstVersion": "3.18.0", + "label": "language,json", + "javaType": "org.apache.camel.language.jq.JqLanguage", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-jq", + "version": "3.18.0-SNAPSHOT", + "modelName": "jq", + "modelJavaType": "org.apache.camel.model.language.JqExpression" + }, + "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" }, + "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/docs/jq-language.adoc b/components/camel-jq/src/main/docs/jq-language.adoc new file mode 100644 index 00000000000..1933fb43ee6 --- /dev/null +++ b/components/camel-jq/src/main/docs/jq-language.adoc @@ -0,0 +1,88 @@ += JQ Language +:doctitle: JQ +:shortname: jq +:artifactid: camel-jq +:description: Evaluates a JQ expression against a JSON message body. +:since: 3.18 +:supportlevel: Preview +//Manually maintained attributes +:camel-spring-boot-name: jq + +*Since Camel {since}* + +Camel supports https://stedolan.github.io/jq[JQ] to allow using xref:manual::expression.adoc[Expression] or xref:manual::predicate.adoc[Predicate] on JSON messages. + +== JQ Options + +// language options: START +include::partial$language-options.adoc[] +// language options: END + + +== Examples + +For example, you can use JQ in a xref:manual::predicate.adoc[Predicate] with the xref:eips:choice-eip.adoc[Content Based Router] EIP. + +[source,java] +---- +from("queue:books.new") + .choice() + .when().jq(".store.book.price < 10)") + .to("jms:queue:book.cheap") + .when().jq(".store.book.price < 30)") + .to("jms:queue:book.average") + .otherwise() + .to("jms:queue:book.expensive"); +---- + +== Message body types + +Camel JQ leverages `camel-jackson` for type conversion. +To enable camel-jackson` POJO type conversion, refer to the Camel Jackson documentation. + + +== Using header as input + +By default, JQ uses the message body as the input source. However, you can also use a header as input by specifying the `headerName` option. + +For example to count the number of books from a JSON document that was stored in a header named `books` you can do: + +[source,java] +---- +from("direct:start") + .setHeader("numberOfBooks") + .jq(".store.books | length", int.class, "books") + .to("mock:result"); +---- + +== Camel supplied JQ Functions + +The camel-jq adds the following functions: + +* `header`: allow to access the Message header in a JQ expression. ++ +For example, to set the property foo to the Message header `MyHeader': ++ +[source, java] +---- +from("direct:start") + .transform() + .jq(".foo = header(\"MyHeader\")") + .to("mock:result"); +---- + + +== Dependencies + +If you use Maven you could just add the following to your `pom.xml`, substituting the version number for the latest and greatest release (see the download page for the latest versions). + +[source,xml] +--------------------------------------- +<dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-jq</artifactId> + <version>x.x.x</version> +</dependency> +--------------------------------------- + +include::spring-boot:partial$starter.adoc[] diff --git a/components/camel-jq/src/main/java/org/apache/camel/language/jq/Jq.java b/components/camel-jq/src/main/java/org/apache/camel/language/jq/Jq.java new file mode 100644 index 00000000000..bb11e449ade --- /dev/null +++ b/components/camel-jq/src/main/java/org/apache/camel/language/jq/Jq.java @@ -0,0 +1,35 @@ +/* + * 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.language.jq; + +import org.apache.camel.CamelContext; + +public final class Jq { + private Jq() { + } + + public static JqExpression expression(String expression) { + return new JqExpression(expression); + } + + public static JqExpression expression(CamelContext context, String expression) { + JqExpression answer = new JqExpression(expression); + answer.init(context); + + return answer; + } +} 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 new file mode 100644 index 00000000000..09a6278183f --- /dev/null +++ b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqExpression.java @@ -0,0 +1,197 @@ +/* + * 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.language.jq; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.BooleanNode; +import net.thisptr.jackson.jq.JsonQuery; +import net.thisptr.jackson.jq.Scope; +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.RuntimeCamelException; +import org.apache.camel.TypeConverter; +import org.apache.camel.spi.ExpressionResultTypeAware; +import org.apache.camel.support.CamelContextHelper; +import org.apache.camel.support.ExpressionAdapter; + +public class JqExpression extends ExpressionAdapter implements ExpressionResultTypeAware { + private final String expression; + + private Scope scope; + private String resultTypeName; + private Class<?> resultType; + private String headerName; + + private JsonQuery query; + private TypeConverter typeConverter; + + public JqExpression(String expression) { + this(null, expression); + } + + public JqExpression(Scope scope, String expression) { + this.scope = scope; + this.expression = expression; + } + + @Override + public void init(CamelContext camelContext) { + super.init(camelContext); + + this.typeConverter = camelContext.getTypeConverter(); + + if (this.scope == null) { + this.scope = CamelContextHelper.findSingleByType(camelContext, Scope.class); + } + + if (this.scope == null) { + // if no scope is explicit set or no scope is found in the registry, + // then a local scope is created and functions are loaded from the + // jackson-jq library and the component. + this.scope = Scope.newEmptyScope(); + + JqFunctions.load(camelContext, scope); + JqFunctions.loadLocal(scope); + } else { + // if no scope is explicit set or found in the registry, then a local + // child scope is created and local functions are loaded. Local + // functions do not leak into the global scope as they are local to + // the child scope. + this.scope = Scope.newChildScope(scope); + + JqFunctions.loadLocal(scope); + } + + try { + this.query = JsonQuery.compile(this.expression, Versions.JQ_1_6); + } catch (JsonQueryException e) { + throw new RuntimeException(e); + } + + if (resultTypeName != null && (resultType == null || resultType == Object.class)) { + resultType = camelContext.getClassResolver().resolveClass(resultTypeName); + } + if (resultType == null || resultType == Object.class) { + resultType = JsonNode.class; + } + } + + public Scope getScope() { + return scope; + } + + public void setScope(Scope scope) { + this.scope = scope; + } + + @Override + public String getExpressionText() { + return this.expression; + } + + @Override + public Class<?> getResultType() { + return this.resultType; + } + + public void setResultType(Class<?> resultType) { + this.resultType = resultType; + } + + public String getResultTypeName() { + return resultTypeName; + } + + public void setResultTypeName(String resultTypeName) { + this.resultTypeName = resultTypeName; + } + + public String getHeaderName() { + return headerName; + } + + /** + * Name of header to use as input, instead of the message body + */ + public void setHeaderName(String headerName) { + this.headerName = headerName; + } + + @Override + public boolean matches(Exchange exchange) { + final Object value = evaluate(exchange, Object.class); + + if (value instanceof BooleanNode) { + return ((BooleanNode) value).asBoolean(); + } + if (value instanceof Collection) { + return !((Collection<?>) value).isEmpty(); + } + + return false; + } + + @Override + public Object evaluate(Exchange exchange) { + if (this.query == null) { + return null; + } + + try { + JqFunctions.EXCHANGE_LOCAL.set(exchange); + + final List<JsonNode> outputs = new ArrayList<>(1); + + final JsonNode payload = headerName == null + ? exchange.getMessage().getMandatoryBody(JsonNode.class) + : exchange.getMessage().getHeader(headerName, JsonNode.class); + + this.query.apply(scope, payload, outputs::add); + + if (outputs.size() == 1) { + // no need to convert output + if (resultType == JsonNode.class) { + return outputs.get(0); + } + + return this.typeConverter.convertTo(resultType, exchange, outputs.get(0)); + } else if (outputs.size() > 1) { + // no need to convert outputs + if (resultType == JsonNode.class) { + return outputs; + } + + return outputs.stream() + .map(item -> this.typeConverter.convertTo(resultType, exchange, item)) + .collect(Collectors.toList()); + } + } catch (Exception e) { + throw new RuntimeCamelException(e); + } finally { + JqFunctions.EXCHANGE_LOCAL.remove(); + } + + return null; + } +} 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 new file mode 100644 index 00000000000..fd27f25c40f --- /dev/null +++ b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqFunctions.java @@ -0,0 +1,144 @@ +/* + * 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.language.jq; + +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.TextNode; +import net.thisptr.jackson.jq.BuiltinFunctionLoader; +import net.thisptr.jackson.jq.Expression; +import net.thisptr.jackson.jq.Function; +import net.thisptr.jackson.jq.PathOutput; +import net.thisptr.jackson.jq.Scope; +import net.thisptr.jackson.jq.Version; +import net.thisptr.jackson.jq.Versions; +import net.thisptr.jackson.jq.exception.JsonQueryException; +import net.thisptr.jackson.jq.path.Path; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class JqFunctions { + public static final ThreadLocal<Exchange> EXCHANGE_LOCAL = new ThreadLocal<>(); + + private static final Logger LOGGER = LoggerFactory.getLogger(JqFunctions.class); + + private JqFunctions() { + } + + public static void load(CamelContext camelContext, Scope scope) { + Map<String, Function> fromServiceLoader = BuiltinFunctionLoader.getInstance() + .loadFunctionsFromServiceLoader( + camelContext.getApplicationContextClassLoader() != null + ? camelContext.getApplicationContextClassLoader() + : BuiltinFunctionLoader.class.getClassLoader(), + Versions.JQ_1_6); + + Map<String, Function> fromJq = BuiltinFunctionLoader.getInstance() + .loadFunctionsFromJsonJq( + camelContext.getApplicationContextClassLoader() != null + ? camelContext.getApplicationContextClassLoader() + : BuiltinFunctionLoader.class.getClassLoader(), + Versions.JQ_1_6, + scope); + + Map<String, Function> fromRegistry = camelContext.getRegistry().findByTypeWithName(Function.class); + + if (fromServiceLoader != null) { + LOGGER.debug("Loading {} jq functions from ServiceLoader", fromServiceLoader.size()); + fromServiceLoader.forEach(scope::addFunction); + } + + if (fromJq != null) { + LOGGER.debug("Loading {} jq functions from Json JQ", fromJq.size()); + fromJq.forEach(scope::addFunction); + } + + if (fromRegistry != null) { + LOGGER.debug("Loading {} jq functions from Registry", fromRegistry.size()); + fromRegistry.forEach(scope::addFunction); + } + } + + public static void loadLocal(Scope scope) { + scope.addFunction(Header.NAME, 1, new Header()); + scope.addFunction(Header.NAME, 2, new Header()); + + } + + /** + * A function that allow to retrieve an {@link org.apache.camel.Message} header 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 = header(\"CommitterName\")" + * } + * </pre> + * + */ + public static class Header implements Function { + public static final String NAME = "header"; + + @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) { + return; + } + + args.get(0).apply(scope, in, name -> { + if (args.size() == 2) { + args.get(1).apply(scope, in, defval -> { + doApply( + exchange, + name.asText(), + defval.asText(), + output); + }); + } else { + doApply( + exchange, + name.asText(), + null, + output); + } + }); + } + + private void doApply(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); + } + } + } +} 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 new file mode 100644 index 00000000000..cdfc680c108 --- /dev/null +++ b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqLanguage.java @@ -0,0 +1,85 @@ +/* + * 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.language.jq; + +import org.apache.camel.Expression; +import org.apache.camel.Predicate; +import org.apache.camel.StaticService; +import org.apache.camel.spi.annotations.Language; +import org.apache.camel.support.ExpressionToPredicateAdapter; +import org.apache.camel.support.LanguageSupport; + +@Language("jq") +public class JqLanguage extends LanguageSupport implements StaticService { + + private Class<?> resultType; + private String headerName; + + public Class<?> getResultType() { + return resultType; + } + + public void setResultType(Class<?> resultType) { + this.resultType = resultType; + } + + public String getHeaderName() { + return headerName; + } + + public void setHeaderName(String headerName) { + this.headerName = headerName; + } + + @Override + public void start() { + } + + @Override + public void stop() { + } + + @Override + public Predicate createPredicate(String expression) { + return ExpressionToPredicateAdapter.toPredicate(createExpression(expression)); + } + + @Override + public Predicate createPredicate(String expression, Object[] properties) { + return ExpressionToPredicateAdapter.toPredicate(createExpression(expression, properties)); + } + + @Override + public Expression createExpression(String expression) { + JqExpression exp = new JqExpression(expression); + exp.setResultType(resultType); + exp.setHeaderName(headerName); + exp.init(getCamelContext()); + + return exp; + } + + @Override + public Expression createExpression(String expression, Object[] properties) { + JqExpression answer = new JqExpression(expression); + answer.setResultType(property(Class.class, properties, 0, resultType)); + answer.setHeaderName(property(String.class, properties, 1, headerName)); + answer.init(getCamelContext()); + + return answer; + } +} 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 new file mode 100644 index 00000000000..a17a6034ffd --- /dev/null +++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqExpressionTest.java @@ -0,0 +1,242 @@ +/* + * 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.language.jq; + +import java.util.List; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import net.thisptr.jackson.jq.Scope; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.support.DefaultExchange; +import org.junit.jupiter.api.Test; + +import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; +import static org.assertj.core.api.Assertions.assertThat; + +public class JqExpressionTest { + public static final ObjectMapper MAPPER = new ObjectMapper(); + + @Test + public void extractHeader() throws Exception { + try (CamelContext context = new DefaultCamelContext()) { + Exchange exchange = new DefaultExchange(context); + exchange.getMessage().setBody(MAPPER.createObjectNode()); + exchange.getMessage().setHeader("CommitterName", "Andrea"); + + JqExpression expression = new JqExpression("header(\"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()) { + Exchange exchange = new DefaultExchange(context); + exchange.getMessage().setBody(MAPPER.createObjectNode()); + exchange.getMessage().setHeader("MyHeader", "Andrea"); + + JqExpression expression = new JqExpression("header(\"CommitterName\"; \"DefVal\")"); + expression.init(context); + + JsonNode result = expression.evaluate(exchange, JsonNode.class); + + assertThatJson(result) + .isString() + .isEqualTo("DefVal"); + } + } + + @Test + public void extractField() throws Exception { + try (CamelContext context = new DefaultCamelContext()) { + ObjectNode node = MAPPER.createObjectNode(); + node.put("foo", "bar"); + node.put("baz", "bak"); + + Exchange exchange = new DefaultExchange(context); + exchange.getMessage().setBody(node); + + JqExpression expression = new JqExpression(".baz"); + expression.init(context); + + JsonNode result = expression.evaluate(exchange, JsonNode.class); + + assertThatJson(result) + .isString() + .isEqualTo("bak"); + } + } + + @Test + public void matches() throws Exception { + try (CamelContext context = new DefaultCamelContext()) { + ObjectNode node = MAPPER.createObjectNode(); + node.put("foo", "bar"); + node.put("baz", "bak"); + + Exchange exchange = new DefaultExchange(context); + exchange.getMessage().setBody(node); + exchange.getMessage().setHeader("CommitterName", "Andrea"); + + assertThat(Jq.expression(context, "has(\"baz\")").matches(exchange)).isTrue(); + assertThat(Jq.expression(context, "has(\"bar\")").matches(exchange)).isFalse(); + assertThat(Jq.expression(context, "header(\"CommitterName\") == \"Andrea\"").matches(exchange)).isTrue(); + assertThat(Jq.expression(context, "header(\"CommitterName\") != \"Andrea\"").matches(exchange)).isFalse(); + } + } + + @Test + public void selectArray() throws Exception { + try (CamelContext context = new DefaultCamelContext()) { + ArrayNode node = MAPPER.createArrayNode(); + + var n1 = MAPPER.createObjectNode().with("commit"); + n1.with("commit").put("name", "Stephen Dolan"); + n1.with("commit").put("message", "Merge pull request #163 from stedolan/utf8-fixes\n\nUtf8 fixes. Closes #161"); + + var n2 = MAPPER.createObjectNode(); + n2.with("commit").put("name", "Nicolas Williams"); + n2.with("commit").put("message", "Reject all overlong UTF8 sequences."); + + node.add(n1); + node.add(n2); + + Exchange exchange = new DefaultExchange(context); + exchange.getMessage().setBody(node); + + JqExpression expression = new JqExpression(".[] | { message: .commit.message, name: .commit.name} "); + expression.init(context); + + List<JsonNode> result = (List<JsonNode>) expression.evaluate(exchange); + + assertThatJson(result.get(0)).isObject().containsEntry("name", "Stephen Dolan"); + assertThatJson(result.get(1)).isObject().containsEntry("name", "Nicolas Williams"); + } + } + + @Test + public void setField() 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.getMessage().setBody(node); + + JqExpression expression = new JqExpression(".commit.name = \"Andrea\""); + expression.init(context); + + JsonNode result = expression.evaluate(exchange, JsonNode.class); + + assertThatJson(result) + .inPath("$.commit.name") + .isString() + .isEqualTo("Andrea"); + } + } + + @Test + public void setFieldFromHeader() 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.getMessage().setHeader("CommitterName", "Andrea"); + exchange.getMessage().setBody(node); + + JqExpression expression = new JqExpression(".commit.name = header(\"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()) { + 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.getMessage().setBody(node); + + JqExpression expression = new JqExpression("del(.commit.name)"); + expression.init(context); + + JsonNode result = expression.evaluate(exchange, JsonNode.class); + + assertThatJson(result) + .inPath("$.commit") + .isObject() + .containsOnlyKeys("message"); + } + } + + @Test + public void customScope() throws Exception { + try (CamelContext context = new DefaultCamelContext()) { + Scope root = Scope.newEmptyScope(); + + JqExpression expression = new JqExpression(".foo"); + expression.setScope(root); + expression.init(context); + + assertThat(expression.getScope()).isNotSameAs(root); + assertThat(expression.getScope().getParentScope()).isSameAs(root); + + assertThat(root.getLocalFunctions()).doesNotContainKeys("header/1", "header/2"); + assertThat(expression.getScope().getLocalFunctions()).containsKeys("header/1", "header/2"); + } + } + + @Test + public void customScopeFromRegistry() throws Exception { + try (CamelContext context = new DefaultCamelContext()) { + Scope root = Scope.newEmptyScope(); + context.getRegistry().bind("scope", root); + + JqExpression expression = new JqExpression(".foo"); + expression.init(context); + + assertThat(expression.getScope()).isNotSameAs(root); + assertThat(expression.getScope().getParentScope()).isSameAs(root); + + assertThat(root.getLocalFunctions()).doesNotContainKeys("header/1", "header/2"); + assertThat(expression.getScope().getLocalFunctions()).containsKeys("header/1", "header/2"); + } + } +} diff --git a/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqFilterTest.java b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqFilterTest.java new file mode 100644 index 00000000000..5502cbc82cc --- /dev/null +++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqFilterTest.java @@ -0,0 +1,44 @@ +/* + * 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.language.jq; + +import org.apache.camel.builder.RouteBuilder; +import org.junit.jupiter.api.Test; + +public class JqFilterTest extends JqTestSupport { + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .filter().jq(".foo == \"bar\"") + .to("mock:result"); + } + }; + } + + @Test + public void testFilter() throws Exception { + getMockEndpoint("mock:result").expectedBodiesReceived(MAPPER.createObjectNode().put("foo", "bar")); + + template.sendBody("direct:start", MAPPER.createObjectNode().put("foo", "baz")); + template.sendBody("direct:start", MAPPER.createObjectNode().put("foo", "bar")); + + assertMockEndpointsSatisfied(); + } +} 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/JqHelloFromHeaderTest.java new file mode 100644 index 00000000000..dd443d0c865 --- /dev/null +++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloFromHeaderTest.java @@ -0,0 +1,49 @@ +/* + * 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.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 { + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .transform().jq(".foo", "Content") + .to("mock:result"); + } + }; + } + + @Test + public void testHelloHeader() throws Exception { + getMockEndpoint("mock:result") + .expectedBodiesReceived(new TextNode("bar")); + + ObjectNode node = MAPPER.createObjectNode(); + node.put("foo", "bar"); + + template.sendBodyAndHeader("direct:start", null, "Content", 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/JqHelloHeaderFnTest.java new file mode 100644 index 00000000000..e161413995e --- /dev/null +++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloHeaderFnTest.java @@ -0,0 +1,48 @@ +/* + * 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.language.jq; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.camel.builder.RouteBuilder; +import org.junit.jupiter.api.Test; + +public class JqHelloHeaderFnTest extends JqTestSupport { + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .transform().jq(".foo = header(\"MyHeader\")") + .to("mock:result"); + } + }; + } + + @Test + public void testHelloHeader() throws Exception { + getMockEndpoint("mock:result") + .expectedBodiesReceived(MAPPER.createObjectNode().put("foo", "MyValue")); + + ObjectNode node = MAPPER.createObjectNode(); + node.put("foo", "bar"); + + template.sendBodyAndHeader("direct:start", node, "MyHeader", "MyValue"); + + assertMockEndpointsSatisfied(); + } +} 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/JqHelloPojoTest.java new file mode 100644 index 00000000000..99315c17cb3 --- /dev/null +++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloPojoTest.java @@ -0,0 +1,107 @@ +/* + * 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.language.jq; + +import java.util.Objects; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.jackson.JacksonConstants; +import org.junit.jupiter.api.Test; + +public class JqHelloPojoTest extends JqTestSupport { + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext answer = super.createCamelContext(); + answer.getGlobalOptions().put(JacksonConstants.ENABLE_TYPE_CONVERTER, "true"); + answer.getGlobalOptions().put(JacksonConstants.TYPE_CONVERTER_TO_POJO, "true"); + + return answer; + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .transform().jq(".book", Book.class) + .to("mock:result"); + } + }; + } + + @Test + public void testHello() throws Exception { + getMockEndpoint("mock:result").expectedBodiesReceived(new Book("foo", "bar")); + + ObjectNode node = MAPPER.createObjectNode(); + node.with("book").put("author", "foo").put("title", "bar"); + + template.sendBody("direct:start", node); + + assertMockEndpointsSatisfied(); + } + + public static class Book { + String author; + String title; + + public Book() { + } + + public Book(String author, String title) { + this.author = author; + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Book)) { + return false; + } + Book book = (Book) o; + return Objects.equals(getAuthor(), book.getAuthor()) && Objects.equals(getTitle(), book.getTitle()); + } + + @Override + public int hashCode() { + return Objects.hash(getAuthor(), getTitle()); + } + } +} 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/JqHelloTest.java new file mode 100644 index 00000000000..61a40cd48ca --- /dev/null +++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqHelloTest.java @@ -0,0 +1,49 @@ +/* + * 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.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 JqHelloTest extends JqTestSupport { + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .transform().jq(".foo") + .to("mock:result"); + } + }; + } + + @Test + public void testHello() 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); + + 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 new file mode 100644 index 00000000000..a0416bde7d5 --- /dev/null +++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqTestSupport.java @@ -0,0 +1,24 @@ +/* + * 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.language.jq; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.test.junit5.CamelTestSupport; + +public abstract class JqTestSupport extends CamelTestSupport { + public static final ObjectMapper MAPPER = new ObjectMapper(); +} diff --git a/components/camel-jq/src/test/resources/log4j2.properties b/components/camel-jq/src/test/resources/log4j2.properties new file mode 100644 index 00000000000..26662225e40 --- /dev/null +++ b/components/camel-jq/src/test/resources/log4j2.properties @@ -0,0 +1,31 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +appender.file.type = File +appender.file.name = file +appender.file.fileName = target/camel-jq-test.log +appender.file.layout.type = PatternLayout +appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n +appender.out.type = Console +appender.out.name = out +appender.out.layout.type = PatternLayout +appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n +logger.joor.name = org.apache.camel.language.jq +logger.joor.level = DEBUG +rootLogger.level = INFO +rootLogger.appenderRef.file.ref = file +#rootLogger.appenderRef.out.ref = out diff --git a/components/pom.xml b/components/pom.xml index 56b9f5f74f6..bc71814e12f 100644 --- a/components/pom.xml +++ b/components/pom.xml @@ -195,6 +195,7 @@ <module>camel-jolt</module> <module>camel-joor</module> <module>camel-jpa</module> + <module>camel-jq</module> <module>camel-jsch</module> <module>camel-jslt</module> <module>camel-json-validator</module> diff --git a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties index 84d6b4b872a..a9ec239a0ac 100644 --- a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties +++ b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties @@ -76,6 +76,7 @@ interceptSendToEndpoint jacksonXml jaxb joor +jq json jsonApi jsonpath diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/aggregate.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/aggregate.json index 6706227f21b..8d2cd2616ea 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/aggregate.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/aggregate.json @@ -12,10 +12,10 @@ "output": false }, "properties": { - "correlationExpression": { "kind": "expression", "displayName": "Correlation Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "desc [...] - "completionPredicate": { "kind": "expression", "displayName": "Completion Predicate", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...] - "completionTimeoutExpression": { "kind": "expression", "displayName": "Completion Timeout Expression", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowi [...] - "completionSizeExpression": { "kind": "expression", "displayName": "Completion Size Expression", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": [...] + "correlationExpression": { "kind": "expression", "displayName": "Correlation Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, [...] + "completionPredicate": { "kind": "expression", "displayName": "Completion Predicate", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false [...] + "completionTimeoutExpression": { "kind": "expression", "displayName": "Completion Timeout Expression", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, " [...] + "completionSizeExpression": { "kind": "expression", "displayName": "Completion Size Expression", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowi [...] "optimisticLockRetryPolicy": { "kind": "element", "displayName": "Optimistic Lock Retry Policy", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.OptimisticLockRetryPolicyDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Allows to configure retry settings when using optimistic locking." }, "parallelProcessing": { "kind": "attribute", "displayName": "Parallel Processing", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "When aggregated are completed they are being send out of the aggregator. This option indicates whether or not Camel should use a thread pool with multiple threads for concurrency. If no custom thread pool has been specified then Camel cr [...] "optimisticLocking": { "kind": "attribute", "displayName": "Optimistic Locking", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Turns on using optimistic locking, which requires the aggregationRepository being used, is supporting this by implementing org.apache.camel.spi.OptimisticLockingAggregationRepository ." }, diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/delay.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/delay.json index fcec0f17239..33f223cc723 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/delay.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/delay.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression to [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "asyncDelayed": { "kind": "attribute", "displayName": "Async Delayed", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Enables asynchronous delay which means the thread will not block while delaying." }, "callerRunsWhenRejected": { "kind": "attribute", "displayName": "Caller Runs When Rejected", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether or not the caller should run the task when it was rejected by the thread pool. Is by default true" }, "executorService": { "kind": "attribute", "displayName": "Executor Service", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom Thread Pool if asyncDelay has been enabled." }, diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/dynamicRouter.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/dynamicRouter.json index e807b2270a7..29d97a68cba 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/dynamicRouter.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/dynamicRouter.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression to [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "uriDelimiter": { "kind": "attribute", "displayName": "Uri Delimiter", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": ",", "description": "Sets the uri delimiter to use" }, "ignoreInvalidEndpoints": { "kind": "attribute", "displayName": "Ignore Invalid Endpoints", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Ignore the invalidate endpoint exception when try to create a producer with that endpoint" }, "cacheSize": { "kind": "attribute", "displayName": "Cache Size", "label": "advanced", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the maximum size used by the org.apache.camel.spi.ProducerCache which is used to cache and reuse producers when using this dynamic router, when uris are reused. Beware that when using dynamic endpoints then it affects how well the cache can be utilized [...] diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/enrich.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/enrich.json index e571c1e35c8..fe2dc3d6de8 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/enrich.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/enrich.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression th [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "aggregationStrategy": { "kind": "attribute", "displayName": "Aggregation Strategy", "required": false, "type": "object", "javaType": "org.apache.camel.AggregationStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the AggregationStrategy to be used to merge the reply from the external service, into a single outgoing message. By default Camel will use the reply from the external service as outgoing message." }, "aggregationStrategyMethodName": { "kind": "attribute", "displayName": "Aggregation Strategy Method Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "This option can be used to explicit declare the method name to use, when using POJOs as the AggregationStrategy." }, "aggregationStrategyMethodAllowNull": { "kind": "attribute", "displayName": "Aggregation Strategy Method Allow Null", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "If this option is false then the aggregate method is not used if there was no data to enrich. If this option is true then null values is used as the oldExchange (when no data to enrich), when using POJOs as [...] diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json index 9176a20cabb..56ac873c219 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json @@ -12,7 +12,7 @@ "output": true }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "descrip [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "d [...] "statusPropertyName": { "kind": "attribute", "displayName": "Status Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of exchange property to use for storing the status of the filtering. Setting this allows to know if the filter predicate evaluated as true or false." }, "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" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/idempotentConsumer.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/idempotentConsumer.json index fc7c459f4df..05f0ff09121 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/idempotentConsumer.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/idempotentConsumer.json @@ -12,7 +12,7 @@ "output": true }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression us [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "idempotentRepository": { "kind": "attribute", "displayName": "Idempotent Repository", "required": false, "type": "object", "javaType": "org.apache.camel.spi.IdempotentRepository", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the reference name of the message id repository" }, "eager": { "kind": "attribute", "displayName": "Eager", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Sets whether to eagerly add the key to the idempotent repository or wait until the exchange is complete. Eager is default enabled." }, "completionEager": { "kind": "attribute", "displayName": "Completion Eager", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Sets whether to complete the idempotent consumer eager or when the exchange is done. If this option is true to complete eager, then the idempotent consumer will trigger its completion when the exchange reached the end of t [...] diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jaxb.index b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jaxb.index index bdb5f44744c..e35b36871fd 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jaxb.index +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jaxb.index @@ -8,6 +8,7 @@ GroovyExpression HeaderExpression Hl7TerserExpression JoorExpression +JqExpression JsonPathExpression LanguageExpression MethodCallExpression 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 new file mode 100644 index 00000000000..c388ada2e95 --- /dev/null +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jq.json @@ -0,0 +1,22 @@ +{ + "model": { + "kind": "model", + "name": "jq", + "title": "JQ", + "description": "Evaluates a JQ expression against a JSON message body.", + "deprecated": false, + "firstVersion": "3.18.0", + "label": "language", + "javaType": "org.apache.camel.model.language.JqExpression", + "abstract": false, + "input": false, + "output": false + }, + "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" }, + "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/generated/resources/org/apache/camel/model/loadbalancer/sticky.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/loadbalancer/sticky.json index fd8579543d2..e5abbb8acc9 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/loadbalancer/sticky.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/loadbalancer/sticky.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "correlationExpression": { "kind": "expression", "displayName": "Correlation Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "desc [...] + "correlationExpression": { "kind": "expression", "displayName": "Correlation Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, [...] "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The id of this node" } } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/loop.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/loop.json index 8a20b92ff74..a12be384493 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/loop.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/loop.json @@ -12,7 +12,7 @@ "output": true }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression to [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "copy": { "kind": "attribute", "displayName": "Copy", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If the copy attribute is true, a copy of the input Exchange is used for each iteration. That means each iteration will start from a copy of the same message. By default loop will loop the same exchange all over, so each iteration may have differ [...] "doWhile": { "kind": "attribute", "displayName": "Do While", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enables the while loop that loops until the predicate evaluates to false or null." }, "breakOnShutdown": { "kind": "attribute", "displayName": "Break On Shutdown", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If the breakOnShutdown attribute is true, then the loop will not iterate until it reaches the end when Camel is shut down." }, diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/onException.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/onException.json index 31e245f31fe..1d71c2e7fd6 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/onException.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/onException.json @@ -14,11 +14,11 @@ "properties": { "exception": { "kind": "element", "displayName": "Exception", "required": true, "type": "array", "javaType": "java.util.List<java.lang.String>", "deprecated": false, "autowired": false, "secret": false, "description": "A set of exceptions to react upon." }, "onWhen": { "kind": "element", "displayName": "On When", "required": false, "type": "object", "javaType": "org.apache.camel.model.WhenDefinition", "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "description": "Sets an additional predicate that should be true before the onException is triggered. To be used for fine grained controlling whether a thrown exception should be intercepted by this exception type or not." }, - "retryWhile": { "kind": "expression", "displayName": "Retry While", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPr [...] + "retryWhile": { "kind": "expression", "displayName": "Retry While", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, [...] "redeliveryPolicy": { "kind": "element", "displayName": "Redelivery Policy", "required": false, "type": "object", "javaType": "org.apache.camel.model.RedeliveryPolicyDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Used for configuring redelivery options" }, "redeliveryPolicyRef": { "kind": "attribute", "displayName": "Redelivery Policy Ref", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets a reference to a redelivery policy to lookup in the org.apache.camel.spi.Registry to be used." }, - "handled": { "kind": "expression", "displayName": "Handled", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "description [...] - "continued": { "kind": "expression", "displayName": "Continued", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredi [...] + "handled": { "kind": "expression", "displayName": "Handled", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "descr [...] + "continued": { "kind": "expression", "displayName": "Continued", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "a [...] "onRedeliveryRef": { "kind": "attribute", "displayName": "On Redelivery Ref", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets a reference to a processor that should be processed before a redelivery attempt. Can be used to change the org.apache.camel.Exchange before its being redelivered." }, "onExceptionOccurredRef": { "kind": "attribute", "displayName": "On Exception Occurred Ref", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets a reference to a processor that should be processed just after an exception occurred. Can be used to perform custom logging about the occurred exception at the exact time it happened. Important: Any exception thrown from this [...] "useOriginalMessage": { "kind": "attribute", "displayName": "Use Original Message", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Will use the original input org.apache.camel.Message (original body and headers) when an org.apache.camel.Exchange is moved to the dead letter queue. Notice: this only applies when all redeliveries attempt have fail [...] diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/pollEnrich.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/pollEnrich.json index af707e1d17a..15981333e87 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/pollEnrich.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/pollEnrich.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression th [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "aggregationStrategy": { "kind": "attribute", "displayName": "Aggregation Strategy", "required": false, "type": "object", "javaType": "org.apache.camel.AggregationStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the AggregationStrategy to be used to merge the reply from the external service, into a single outgoing message. By default Camel will use the reply from the external service as outgoing message." }, "aggregationStrategyMethodName": { "kind": "attribute", "displayName": "Aggregation Strategy Method Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "This option can be used to explicit declare the method name to use, when using POJOs as the AggregationStrategy." }, "aggregationStrategyMethodAllowNull": { "kind": "attribute", "displayName": "Aggregation Strategy Method Allow Null", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "If this option is false then the aggregate method is not used if there was no data to enrich. If this option is true then null values is used as the oldExchange (when no data to enrich), when using POJOs as [...] diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/propertyExpression.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/propertyExpression.json index 6f9a4a7d136..1ad8f61bdc9 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/propertyExpression.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/propertyExpression.json @@ -13,6 +13,6 @@ }, "properties": { "key": { "kind": "attribute", "displayName": "Key", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Property key" }, - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Property valu [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Propert [...] } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/recipientList.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/recipientList.json index 5fd2c25a526..454b97ad886 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/recipientList.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/recipientList.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression th [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "delimiter": { "kind": "attribute", "displayName": "Delimiter", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": ",", "description": "Delimiter used if the Expression returned multiple endpoints. Can be turned off using the value false. The default value is ," }, "aggregationStrategy": { "kind": "attribute", "displayName": "Aggregation Strategy", "required": false, "type": "object", "javaType": "org.apache.camel.AggregationStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the AggregationStrategy to be used to assemble the replies from the recipients, into a single outgoing message from the RecipientList. By default Camel will use the last reply as the outgoing message. You can also use a POJO as the Agg [...] "aggregationStrategyMethodName": { "kind": "attribute", "displayName": "Aggregation Strategy Method Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "This option can be used to explicit declare the method name to use, when using POJOs as the AggregationStrategy." }, diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/resequence.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/resequence.json index c63266284ad..c3e98b2898a 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/resequence.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/resequence.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression to [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "resequencerConfig": { "kind": "element", "displayName": "Resequencer Config", "required": true, "type": "object", "javaType": "org.apache.camel.model.config.ResequencerConfig", "oneOf": [ "batch-config", "stream-config" ], "deprecated": false, "autowired": false, "secret": false, "description": "To configure the resequencer in using either batch or stream configuration. Will by default use batch configuration." }, "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" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/routingSlip.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routingSlip.json index cfb20fa5acf..642f02e75c3 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/routingSlip.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routingSlip.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression to [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "uriDelimiter": { "kind": "attribute", "displayName": "Uri Delimiter", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": ",", "description": "Sets the uri delimiter to use" }, "ignoreInvalidEndpoints": { "kind": "attribute", "displayName": "Ignore Invalid Endpoints", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Ignore the invalidate endpoint exception when try to create a producer with that endpoint" }, "cacheSize": { "kind": "attribute", "displayName": "Cache Size", "label": "advanced", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the maximum size used by the org.apache.camel.spi.ProducerCache which is used to cache and reuse producers when using this routing slip, when uris are reused. Beware that when using dynamic endpoints then it affects how well the cache can be utilized. [...] diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/script.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/script.json index e6caede09bb..b1276830c3a 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/script.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/script.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression to [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "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" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/setBody.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/setBody.json index 12b157739db..ff7b2235acc 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/setBody.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/setBody.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression th [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "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" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/setHeader.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/setHeader.json index efc03f57e66..fac353dcaab 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/setHeader.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/setHeader.json @@ -13,7 +13,7 @@ }, "properties": { "name": { "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of message header to set a new value The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used." }, - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression to [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "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" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/setProperty.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/setProperty.json index 6b9f109cdfd..faf1abcbde4 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/setProperty.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/setProperty.json @@ -13,7 +13,7 @@ }, "properties": { "name": { "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of exchange property to set a new value. The simple language can be used to define a dynamic evaluated exchange property name to be used. Otherwise a constant name will be used." }, - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression to [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "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" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/sort.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/sort.json index c215d4674af..e76be9d9308 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/sort.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/sort.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Optional expr [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Optiona [...] "comparator": { "kind": "attribute", "displayName": "Comparator", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.Comparator", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the comparator to use for sorting" }, "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" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json index 7c951e4754f..42a72c93295 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json @@ -12,7 +12,7 @@ "output": true }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression of [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "delimiter": { "kind": "attribute", "displayName": "Delimiter", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": ",", "description": "Delimiter used in splitting messages. Can be turned off using the value false. The default value is ," }, "aggregationStrategy": { "kind": "attribute", "displayName": "Aggregation Strategy", "required": false, "type": "object", "javaType": "org.apache.camel.AggregationStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "Sets a reference to the AggregationStrategy to be used to assemble the replies from the split messages, into a single outgoing message from the Splitter. By default Camel will use the original incoming message to the splitter (leave it unch [...] "aggregationStrategyMethodName": { "kind": "attribute", "displayName": "Aggregation Strategy Method Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "This option can be used to explicit declare the method name to use, when using POJOs as the AggregationStrategy." }, diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/throttle.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/throttle.json index 928adfa0f14..70b870cd495 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/throttle.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/throttle.json @@ -12,8 +12,8 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression to [...] - "correlationExpression": { "kind": "expression", "displayName": "Correlation Expression", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "des [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] + "correlationExpression": { "kind": "expression", "displayName": "Correlation Expression", "required": false, "type": "object", "javaType": "org.apache.camel.model.ExpressionSubElementDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false [...] "executorService": { "kind": "attribute", "displayName": "Executor Service", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom thread pool (ScheduledExecutorService) by the throttler." }, "timePeriodMillis": { "kind": "attribute", "displayName": "Time Period Millis", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "1000", "description": "Sets the time period during which the maximum request count is valid for" }, "asyncDelayed": { "kind": "attribute", "displayName": "Async Delayed", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enables asynchronous delay which means the thread will not block while delaying." }, diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json index b9590698345..27ec16b5fe2 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression to [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Express [...] "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" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/validate.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/validate.json index c5c0556a828..c62a320abe4 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/validate.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/validate.json @@ -12,7 +12,7 @@ "output": false }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "descrip [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "d [...] "predicateExceptionFactory": { "kind": "attribute", "displayName": "Predicate Exception Factory", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.PredicateExceptionFactory", "deprecated": false, "autowired": false, "secret": false, "description": "The bean id of custom PredicateExceptionFactory to use for creating the exception when the validation fails. By default, Camel will throw PredicateValidationException. By using a custom factory yo [...] "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" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/when.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/when.json index 4fc937294b7..a61ee2392a5 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/when.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/when.json @@ -12,7 +12,7 @@ "output": true }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "descrip [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "d [...] "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" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/whenSkipSendToEndpoint.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/whenSkipSendToEndpoint.json index c7c769098c7..f14991b6f95 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/whenSkipSendToEndpoint.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/whenSkipSendToEndpoint.json @@ -12,7 +12,7 @@ "output": true }, "properties": { - "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "descrip [...] + "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "d [...] "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" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/Builder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/Builder.java index 3402c28778f..e572caa3277 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/builder/Builder.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/Builder.java @@ -22,6 +22,7 @@ import org.apache.camel.model.language.ConstantExpression; import org.apache.camel.model.language.ExchangePropertyExpression; import org.apache.camel.model.language.HeaderExpression; import org.apache.camel.model.language.JoorExpression; +import org.apache.camel.model.language.JqExpression; import org.apache.camel.model.language.JsonPathExpression; import org.apache.camel.model.language.LanguageExpression; import org.apache.camel.model.language.MethodCallExpression; @@ -226,6 +227,23 @@ public final class Builder { return new ValueBuilder(exp); } + /** + * Returns a JQ expression value builder + */ + public static ValueBuilder jq(String value) { + JqExpression exp = new JqExpression(value); + return new ValueBuilder(exp); + } + + /** + * Returns a JQ expression value builder + */ + public static ValueBuilder jq(String value, Class<?> resultType) { + JqExpression exp = new JqExpression(value); + exp.setResultType(resultType); + return new ValueBuilder(exp); + } + /** * Returns a JSonPath expression value builder */ 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 39cef0cafcc..440f7b4d71d 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 @@ -378,6 +378,50 @@ public class ExpressionClause<T> implements Expression, Predicate { return delegate.joor(value, resultType); } + /** + * Evaluates a <a href="http://camel.apache.org/jq.html">JQ expression</a> + * + * @param value the expression to be evaluated + * @return the builder to continue processing the DSL + */ + public T jq(String value) { + return delegate.jq(value); + } + + /** + * 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 + * @return the builder to continue processing the DSL + */ + public T jq(String value, Class<?> resultType) { + return delegate.jq(value, resultType); + } + + /** + * 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 + */ + public T jq(String value, String headerName) { + return delegate.jq(value, headerName); + } + + /** + * 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 + */ + public T jq(String value, Class<?> resultType, String headerName) { + return delegate.jq(value, resultType, headerName); + } + /** * Evaluates a <a href="http://camel.apache.org/datasonnet.html">Datasonnet expression</a> * 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 f2029cdee91..ca3b05b3c36 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 @@ -31,6 +31,7 @@ import org.apache.camel.model.language.GroovyExpression; import org.apache.camel.model.language.HeaderExpression; import org.apache.camel.model.language.Hl7TerserExpression; import org.apache.camel.model.language.JoorExpression; +import org.apache.camel.model.language.JqExpression; import org.apache.camel.model.language.JsonPathExpression; import org.apache.camel.model.language.LanguageExpression; import org.apache.camel.model.language.MethodCallExpression; @@ -371,6 +372,57 @@ public class ExpressionClauseSupport<T> implements ExpressionFactoryAware, Predi return expression(exp); } + /** + * Evaluates <a href="http://camel.apache.org/jq.html">JQ expression</a> + * + * @param text the expression to be evaluated + * @return the builder to continue processing the DSL + */ + public T jq(String text) { + return expression(new JqExpression(text)); + } + + /** + * 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 + * @return the builder to continue processing the DSL + */ + public T jq(String text, Class<?> resultType) { + JqExpression exp = new JqExpression(text); + exp.setResultType(resultType); + 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 + * @return the builder to continue processing the DSL + */ + public T jq(String text, String headerName) { + JqExpression exp = new JqExpression(text); + exp.setHeaderName(headerName); + 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 + */ + public T jq(String text, Class<?> resultType, String headerName) { + JqExpression exp = new JqExpression(text); + exp.setResultType(resultType); + exp.setHeaderName(headerName); + return expression(exp); + } + /** * Evaluates a <a href="http://camel.apache.org/datasonnet.html">Datasonnet expression</a> * 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 new file mode 100644 index 00000000000..1dc1bd91943 --- /dev/null +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/JqExpression.java @@ -0,0 +1,86 @@ +/* + * 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.model.language; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlTransient; + +import org.apache.camel.spi.Metadata; + +/** + * Evaluates a JQ expression against a JSON message body. + */ +@Metadata(firstVersion = "3.18.0", label = "language,json", title = "JQ") +@XmlRootElement(name = "jq") +@XmlAccessorType(XmlAccessType.FIELD) +public class JqExpression extends ExpressionDefinition { + @XmlAttribute(name = "resultType") + private String resultTypeName; + @XmlTransient + private Class<?> resultType; + @XmlAttribute + @Metadata(label = "advanced") + private String headerName; + + public JqExpression() { + } + + public JqExpression(String expression) { + super(expression); + } + + @Override + public String getLanguage() { + return "jq"; + } + + public String getResultTypeName() { + return resultTypeName; + } + + /** + * Sets the class of the result type (type from output) + */ + public void setResultTypeName(String resultTypeName) { + this.resultTypeName = resultTypeName; + } + + public Class<?> getResultType() { + return resultType; + } + + /** + * Sets the class name of the result type (type from output) + */ + public void setResultType(Class<?> resultType) { + this.resultType = resultType; + } + + public String getHeaderName() { + return headerName; + } + + /** + * Name of header to use as input, instead of the message body + */ + public void setHeaderName(String headerName) { + this.headerName = headerName; + } +} diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java index 51ba8650e7c..8005a840156 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java @@ -38,6 +38,7 @@ import org.apache.camel.model.language.GroovyExpression; import org.apache.camel.model.language.HeaderExpression; import org.apache.camel.model.language.Hl7TerserExpression; import org.apache.camel.model.language.JoorExpression; +import org.apache.camel.model.language.JqExpression; import org.apache.camel.model.language.JsonPathExpression; import org.apache.camel.model.language.LanguageExpression; import org.apache.camel.model.language.MethodCallExpression; @@ -129,6 +130,8 @@ public class ExpressionReifier<T extends ExpressionDefinition> extends AbstractR return new ExpressionReifier<>(camelContext, definition); } else if (definition instanceof JoorExpression) { return new JoorExpressionReifier(camelContext, definition); + } else if (definition instanceof JqExpression) { + return new JqExpressionReifier(camelContext, definition); } else if (definition instanceof JsonPathExpression) { return new JsonPathExpressionReifier(camelContext, definition); } else if (definition instanceof LanguageExpression) { 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 new file mode 100644 index 00000000000..d2a4c5a23f2 --- /dev/null +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/JqExpressionReifier.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.reifier.language; + +import org.apache.camel.CamelContext; +import org.apache.camel.Expression; +import org.apache.camel.Predicate; +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.model.language.ExpressionDefinition; +import org.apache.camel.model.language.JqExpression; +import org.apache.camel.spi.Language; + +public class JqExpressionReifier extends ExpressionReifier<JqExpression> { + + public JqExpressionReifier(CamelContext camelContext, ExpressionDefinition definition) { + super(camelContext, (JqExpression) definition); + } + + @Override + protected void configureLanguage(Language language) { + if (definition.getResultType() == null && definition.getResultTypeName() != null) { + try { + Class<?> clazz = camelContext.getClassResolver().resolveMandatoryClass(definition.getResultTypeName()); + definition.setResultType(clazz); + } catch (ClassNotFoundException e) { + throw RuntimeCamelException.wrapRuntimeException(e); + } + } + } + + private Object[] createProperties() { + Object[] properties = new Object[2]; + properties[0] = definition.getResultType(); + properties[1] = parseString(definition.getHeaderName()); + return properties; + } + + @Override + public boolean isResolveOptionalExternalScriptEnabled() { + // we handle this in camel-jq + return false; + } + + @Override + protected Expression createExpression(Language language, String exp) { + return language.createExpression(exp, createProperties()); + } + + @Override + protected Predicate createPredicate(Language language, String exp) { + return language.createPredicate(exp, createProperties()); + } + +} 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 fe6144cae44..61758a0af9e 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 @@ -2644,6 +2644,16 @@ public class ModelParser extends BaseParser { return true; }, noElementHandler(), expressionDefinitionValueHandler()); } + protected JqExpression doParseJqExpression() throws IOException, XmlPullParserException { + return doParse(new JqExpression(), (def, key, val) -> { + switch (key) { + case "headerName": def.setHeaderName(val); break; + case "resultType": def.setResultTypeName(val); break; + default: return expressionDefinitionAttributeHandler().accept(def, key, val); + } + return true; + }, noElementHandler(), expressionDefinitionValueHandler()); + } protected JsonPathExpression doParseJsonPathExpression() throws IOException, XmlPullParserException { return doParse(new JsonPathExpression(), (def, key, val) -> { switch (key) { @@ -3300,6 +3310,7 @@ public class ModelParser extends BaseParser { case "header": return doParseHeaderExpression(); case "hl7terser": return doParseHl7TerserExpression(); case "joor": return doParseJoorExpression(); + case "jq": return doParseJqExpression(); case "jsonpath": return doParseJsonPathExpression(); case "language": return doParseLanguageExpression(); case "method": return doParseMethodCallExpression(); diff --git a/parent/pom.xml b/parent/pom.xml index 3b9bd0ef1cb..897e9fcaf19 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -255,6 +255,7 @@ <irclib-version>1.10</irclib-version> <ironmq-version>3.0.5</ironmq-version> <ivy-version>2.5.0</ivy-version> + <jackson-jq-version>1.0.0-preview.20210928</jackson-jq-version> <jackson-version>1.9.12</jackson-version> <jackson2-version>2.13.3</jackson2-version> <jackrabbit-version>2.21.10</jackrabbit-version> @@ -334,6 +335,7 @@ <json-patch-version>1.13</json-patch-version> <jsonata4java-version>1.5.8</jsonata4java-version> <json-schema-validator-version>2.2.14</json-schema-validator-version> + <json-unit-version>2.32.0</json-unit-version> <jsoup-version>1.14.3</jsoup-version> <jt400-version>10.7</jt400-version> <junit-toolbox-version>2.4</junit-toolbox-version> @@ -1781,6 +1783,11 @@ <artifactId>camel-jpa</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-jq</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jsch</artifactId> @@ -2869,6 +2876,11 @@ <artifactId>java-driver-query-builder</artifactId> <version>${cassandra-driver-version}</version> </dependency> + <dependency> + <groupId>net.thisptr</groupId> + <artifactId>jackson-jq</artifactId> + <version>${jackson-jq-version}</version> + </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId>