[[jsonpath-language]]
= JsonPath Language
:docTitle: JsonPath
:artifactId: camel-jsonpath
:description: Evaluate a JsonPath expression against a JSON message body.
:since: 2.13
:supportLevel: Stable
include::{cq-version}@camel-quarkus:ROOT:partial$reference/languages/jsonpath.adoc[opts=optional]

*Since Camel {since}*

Camel supports https://code.google.com/p/json-path/[JSonPath] to allow
using Expression or Predicate
on json messages.

[source,java]
-----------------------------------------------------
from("queue:books.new")
  .choice()
    .when().jsonpath("$.store.book[?(@.price < 10)]")
      .to("jms:queue:book.cheap")
    .when().jsonpath("$.store.book[?(@.price < 30)]")
      .to("jms:queue:book.average")
    .otherwise()
      .to("jms:queue:book.expensive")
-----------------------------------------------------

== JSonPath Options


// language options: START
The JsonPath language supports 8 options, which are listed below.



[width="100%",cols="2,1m,1m,6",options="header"]
|===
| Name | Default | Java Type | Description
| resultType |  | String | Sets the class name of the result type (type from output)
| suppressExceptions | false | Boolean | Whether to suppress exceptions such as PathNotFoundException.
| allowSimple | true | Boolean | Whether to allow in inlined simple exceptions in the JsonPath expression
| allowEasyPredicate | true | Boolean | Whether to allow using the easy predicate parser to pre-parse predicates.
| writeAsString | false | Boolean | Whether to write the output of each row/element as a JSON String value instead of a Map/POJO value.
| headerName |  | String | Name of header to use as input, instead of the message body
| option |  | String | To configure additional options on json path. Multiple values can be separated by comma.
| trim | true | Boolean | Whether to trim the value to remove leading and trailing whitespaces and line breaks
|===
// language options: END




== Using XML configuration

If you prefer to configure your routes in your Spring
XML file then you can use xref:jsonpath-language.adoc[JSonPath] expressions as
follows

[source,xml]
----
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
  <route>
    <from uri="direct:start"/>
    <choice>
      <when>
        <jsonpath>$.store.book[?(@.price &lt; 10)]</jsonpath>
        <to uri="mock:cheap"/>
      </when>
      <when>
        <jsonpath>$.store.book[?(@.price &lt; 30)]</jsonpath>
        <to uri="mock:average"/>
      </when>
      <otherwise>
        <to uri="mock:expensive"/>
      </otherwise>
    </choice>
  </route>
</camelContext>
----

== Syntax

See the https://code.google.com/p/json-path/[JSonPath] project page for
further examples.

== Easy Syntax

*Since Camel 2.19*

When you just want to define a basic predicate using jsonpath syntax it can be a bit hard to remember the syntax.
 So for example to find out all the cheap books you have to do

----
$.store.book[?(@.price < 20)]
----

However what if you could just write it as

----
store.book.price < 20
----

And you can omit the path if you just want to look at nodes with a price key

----
price < 20
----

To support this there is a `EasyPredicateParser` which kicks-in if you have define the predicate
  using a basic style. That means the predicate must not start with the `$` sign, and only include one operator.

The easy syntax is:

----
left OP right
----

You can use Camel simple language in the right operator, eg

----
store.book.price < ${header.limit}
----

== Supported message body types

Camel JSonPath supports message body using the following types:

[width="100%",cols="3m,7",options="header"]
|===
| Type | Comment
| File | Reading from files
| String | Plain strings
| Map | Message bodies as `java.util.Map` types
| List | Message bodies as `java.util.List` types
| POJO | *Optional* If Jackson is on the classpath, then camel-jsonpath
  is able to use Jackson to read the message body as POJO and convert to `java.util.Map`
  which is supported by JSonPath. For example you can add `camel-jackson` as dependency to include Jackson.
| InputStream | If none of the above types matches, then Camel will attempt to read the message body as an `java.io.InputStream`.
|===

If a message body is of unsupported type then an exception is thrown by default, however you
can configure JSonPath to suppress exceptions (see below)


== Suppress exceptions

*Since Camel 2.16*

By default jsonpath will throw an exception if the json payload does not
have a valid path accordingly to the configured jsonpath expression. In
some use-cases you may want to ignore this in case the json payload
contains optional data. Therefore you can set the option
suppressExceptions to true to ignore this as shown:

[source,java]
----
from("direct:start")
    .choice()
        // use true to suppress exceptions
        .when().jsonpath("person.middlename", true)
            .to("mock:middle")
        .otherwise()
            .to("mock:other");
----

And in XML DSL:

[source,xml]
----
<route>
  <from uri="direct:start"/>
  <choice>
    <when>
      <jsonpath suppressExceptions="true">person.middlename</jsonpath>
      <to uri="mock:middle"/>
    </when>
    <otherwise>
      <to uri="mock:other"/>
    </otherwise>
  </choice>
</route>
----

This option is also available on the `@JsonPath` annotation.

== Inline Simple expressions

*Since Camel 2.18*

Its now possible to inlined Simple language expressions in the JSonPath expression using the simple syntax $\{xxx}.
An example is shown below:

[source,java]
----
from("direct:start")
  .choice()
    .when().jsonpath("$.store.book[?(@.price < ${header.cheap})]")
      .to("mock:cheap")
    .when().jsonpath("$.store.book[?(@.price < ${header.average})]")
      .to("mock:average")
    .otherwise()
      .to("mock:expensive");
----

And in XML DSL:

[source,xml]
----
<route>
  <from uri="direct:start"/>
  <choice>
    <when>
      <jsonpath>$.store.book[?(@.price < ${header.cheap})]</jsonpath>
      <to uri="mock:cheap"/>
    </when>
    <when>
      <jsonpath>$.store.book[?(@.price < ${header.average})]</jsonpath>
      <to uri="mock:average"/>
    </when>
    <otherwise>
      <to uri="mock:expensive"/>
    </otherwise>
  </choice>
</route>
----

You can turn off support for inlined simple expression by setting the option allowSimple to false as shown:

[source,java]
----
.when().jsonpath("$.store.book[?(@.price < 10)]", false, false)
----

And in XML DSL:

[source,xml]
----
<jsonpath allowSimple="false">$.store.book[?(@.price < 10)]</jsonpath>
----

== JSonPath injection

You can use Bean Integration to invoke a
method on a bean and use various languages such as JSonPath to extract a
value from the message and bind it to a method parameter.

For example

[source,java]
----
public class Foo {
    
    @Consume("activemq:queue:books.new")
    public void doSomething(@JsonPath("$.store.book[*].author") String author, @Body String json) {
      // process the inbound message here
    }
}
----

== Encoding Detection

The encoding of the JSON document is
detected automatically, if the document is encoded in unicode  (UTF-8,
UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE ) as specified in  RFC-4627. If
the encoding is a non-unicode encoding, you can either make sure that
you enter the document in String format to the JSONPath component or you
can specify the encoding in the header "*CamelJsonPathJsonEncoding*"
(JsonpathConstants.HEADER_JSON_ENCODING).

== Split JSon data into sub rows as JSon

You can use jsonpath to split a JSon document, such as:

[source,java]
----
from("direct:start")
    .split().jsonpath("$.store.book[*]")
    .to("log:book");
----

Then each book is logged, however the message body is a `Map` instance. Sometimes
you may want to output this as plain String JSon value instead, which can be done
with the `writeAsString` option as shown:

[source,java]
----
from("direct:start")
    .split().jsonpathWriteAsString("$.store.book[*]")
    .to("log:book");
----

Then each book is logged as a String JSon value. For earlier versions of Camel you
would need to use camel-jackson dataformat and marshal the message body to make it
convert the message body from `Map` to a `String` type.

== Using header as input
*Since Camel 2.20*

By default jsonpath 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")
        .jsonpath("$..store.book.length()", false, int.class, "books")
    .to("mock:result");
----

In the `jsonpath` expression above we specify the name of the header as `books`
and we also told that we wanted the result to be converted as an integer by `int.class`.

The same example in XML DSL would be:

[source,xml]
----
<route>
  <from uri="direct:start"/>
  <setHeader name="numberOfBooks">
    <jsonpath headerName="books" resultType="int">$..store.book.length()</jsonpath>
  </transform>
  <to uri="mock:result"/>
</route>
----

== Dependencies

To use JSonPath in your camel routes you need to add the a dependency on
*camel-jsonpath* which implements the JSonPath language.

If you use maven you could just add the following to your pom.xml,
substituting the version number for the latest & greatest release (see
the download page for the latest versions).

[source,xml]
----
<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-jsonpath</artifactId>
  <version>x.x.x</version>
</dependency>
----

include::camel-spring-boot::page$jsonpath-starter.adoc[]
