JQ
Since Camel 3.18
Camel supports JQ to allow using Expression or Predicate on JSON messages.
JQ Options
The JQ language supports the following options which are listed below.
| Name | Default | Java Type | Description |
|---|---|---|---|
| Source to use, instead of message body. You can prefix with variable:, header:, or property: to specify kind of source. Otherwise, the source is assumed to be a variable. Use empty or null to use default source, which is the message body. | ||
| The class of the result type (type from output). | ||
|
| Whether to trim the source code to remove leading and trailing whitespaces and line breaks. | |
|
| Whether a result of the expression that is a String starting with resource: is loaded as a resource and its content becomes the result, e.g. a script that returns resource:file:order.json or resource:classpath:templates/order.json (a name without a scheme is a classpath resource). Off by default; the resource: prefix on the expression text itself is always resolved. Applies to the expression used as a value, not as a predicate. |
Usage
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, property or variable as input by specifying the source option, such as header:books.
For example, to count the number of books from a JSON document that was stored in a header named books you can do:
-
Java
-
XML
-
YAML
from("direct:start")
.setHeader("numberOfBooks",
expression().jq(".store.books | length").resultType(int.class).source("header:books").end())
.to("mock:result"); <route>
<from uri="direct:start"/>
<setHeader name="numberOfBooks">
<jq source="header:books" resultType="int">.store.books | length</jq>
</setHeader>
<to uri="mock:result"/>
</route> - route:
from:
uri: direct:start
steps:
- setHeader:
name: numberOfBooks
expression:
jq:
expression: .store.books | length
resultType: int
source: header:books
- to:
uri: mock:result Camel supplied JQ Functions
| JQ comes with about a hundred built-in functions, and you can see many examples from JQ documentation. |
The camel-jq adds the following functions:
-
header: allow accessing the Message header in a JQ expression. -
property: allow accessing the Exchange property in a JQ expression. -
constant: allow using a constant value as-is in a JQ expression. -
variable: allow accessing the Exchange variable in a JQ expression. -
body: the message body as a textual value.
For example, to set the property foo with the value from the Message header `MyHeader':
-
Java
-
XML
-
YAML
from("direct:start")
.transform()
.jq(".foo = header(\"MyHeader\")")
.to("mock:result"); <route>
<from uri="direct:start"/>
<transform>
<jq>.foo = header("MyHeader")</jq>
</transform>
<to uri="mock:result"/>
</route> - route:
from:
uri: direct:start
steps:
- transform:
expression:
jq:
expression: '.foo = header("MyHeader")'
- to:
uri: mock:result Or from the exchange property:
-
Java
-
XML
-
YAML
from("direct:start")
.transform()
.jq(".foo = property(\"MyProperty\")")
.to("mock:result"); <route>
<from uri="direct:start"/>
<transform>
<jq>.foo = property("MyProperty")</jq>
</transform>
<to uri="mock:result"/>
</route> - route:
from:
uri: direct:start
steps:
- transform:
expression:
jq:
expression: '.foo = property("MyProperty")'
- to:
uri: mock:result And using a constant value
-
Java
-
XML
-
YAML
from("direct:start")
.transform()
.jq(".foo = constant(\"Hello World\")")
.to("mock:result"); <route>
<from uri="direct:start"/>
<transform>
<jq>.foo = constant("Hello World")</jq>
</transform>
<to uri="mock:result"/>
</route> - route:
from:
uri: direct:start
steps:
- transform:
expression:
jq:
expression: '.foo = constant("Hello World")'
- to:
uri: mock:result Or using an exchange variable:
-
Java
-
XML
-
YAML
from("direct:start")
.transform()
.jq(".foo = variable(\"MyVar\")")
.to("mock:result"); <route>
<from uri="direct:start"/>
<transform>
<jq>.foo = variable("MyVar")</jq>
</transform>
<to uri="mock:result"/>
</route> - route:
from:
uri: direct:start
steps:
- transform:
expression:
jq:
expression: '.foo = variable("MyVar")'
- to:
uri: mock:result The header, property and variable functions also support returning a default value in case the key does not exist, as shown in the following:
-
Java
-
XML
-
YAML
from("direct:start")
.transform()
.jq(".foo = header(\"MyHeader\", \"MyDefaultValue\")")
.to("mock:result"); <route>
<from uri="direct:start"/>
<transform>
<jq>.foo = header("MyHeader", "MyDefaultValue")</jq>
</transform>
<to uri="mock:result"/>
</route> - route:
from:
uri: direct:start
steps:
- transform:
expression:
jq:
expression: '.foo = header("MyHeader", "MyDefaultValue")'
- to:
uri: mock:result Transforming a JSon message
For basic JSon transformation where you have a fixed structure, you can represent with a combination of using Camel simple and JQ language as:
{
"company": "${jq(.customer.name)}",
"location": "${jq(.customer.address.country)}",
"gold": ${jq(.customer.orders[] | length > 5)}
} Here we use the simple language to define the structure and use JQ as inlined functions via the ${jq(exp)} syntax.
This makes it possible to use simple as a template language to define a basic structure and then JQ to grab the data from an incoming JSon message. The output of the transformation is also JSon, but with simple you could also make it XML or plain text based:
<customer gold="${jq(.customer.orders[] | length > 5)}">
<company>${jq(.customer.name)}</company>
<location>${jq(.customer.address.country)}</location>
</customer> Examples
For example, you can use JQ in a Predicate with the Content-Based Router EIP.
-
Java
-
XML
-
YAML
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"); <route>
<from uri="queue:books.new"/>
<choice>
<when>
<jq>.store.book.price < 10</jq>
<to uri="jms:queue:book.cheap"/>
</when>
<when>
<jq>.store.book.price < 30</jq>
<to uri="jms:queue:book.average"/>
</when>
<otherwise>
<to uri="jms:queue:book.expensive"/>
</otherwise>
</choice>
</route> - route:
from:
uri: queue:books.new
steps:
- choice:
when:
- expression:
jq:
expression: ".store.book.price < 10"
steps:
- to:
uri: jms:queue:book.cheap
- expression:
jq:
expression: ".store.book.price < 30"
steps:
- to:
uri: jms:queue:book.average
otherwise:
steps:
- to:
uri: jms:queue:book.expensive 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).
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jq</artifactId>
<version>x.x.x</version>
</dependency>