Camel Components

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 (common)

String

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.

resultType (common)

String

The class of the result type (type from output).

trim (advanced)

true

Boolean

Whether to trim the source code to remove leading and trailing whitespaces and line breaks.

resolveResource (advanced)

false

Boolean

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.

Message Body

The message body at each side of the JQ language: Expression input is the body its expressions can read, and Expression result what they return.

Side Body Description

Expression input

text, bytes, stream, file or map, as json

JSON as text, bytes, a stream or a file, or a Map.

Not known when source is set.

Expression result

pojo, list or null

A JsonNode; a List of JsonNode when the filter gives several, null when it gives none.

Not known when resultType is set.

The bodies are the ones with the default options. A side that is not listed is not known, and tooling does not guess it. The carriers are described in the Camel Catalog.

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 &lt; 10</jq>
      <to uri="jms:queue:book.cheap"/>
    </when>
    <when>
      <jq>.store.book.price &lt; 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>