第21章 JsonPath

概要

JsonPath は、JSON メッセージの一部を抽出する際に便利な構文を提供します。JsonPath の構文は XPath に似ていますが、XML ドキュメントではなく、JSON メッセージから JSON オブジェクトを抽出するために使用されます。jsonpath は式または述語 (空の結果がブール値として解釈される false) として使用できます。

JsonPath パッケージの追加

Camel ルートで JsonPath を使用するには、以下のように camel-jsonpath の依存関係をプロジェクトに追加する必要があります。

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-jsonpath</artifactId>
  <version>${camel-version}</version>
</dependency>

Java の例

以下の Java の例は、jsonpath() DSL コマンドを使用して、特定の価格範囲内の商品を選択する方法を示しています。

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 のクエリー結果が空のセットの場合、結果は false と解釈されます。このため、JsonPath のクエリーを述語として使用することができます。

XML の例

以下の XML の例は、jsonpath DSL の要素を使用してルート内で述語を定義する方法を示しています。

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

簡略化構文

jsonpath の構文を使用して基本的な述語を定義する場合、構文を覚えるのが少し難しいかもしれません。たとえば、安価な本 (20 未満) をすべて検索する場合は、以下のような構文を書く必要があります。

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

しかし、以下のように簡略化した記述もできます。

store.book.price < 20

さらに、価格キーを持つノードを確認する場合は、パスを省略することもできます。

price < 20

この構文をサポートするために、EasyPredicateParser を使用して基本的な記法で述語を定義します。つまり基本的な記法とは、述語を $ 記号で始めてはならず、演算子が 1 つだけ含まれるようにすることです。簡略化構文は以下になります。

left OP right

下記の例のように、right 部分には、Camel Simple 言語を使用することもできます。

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

サポートされるメッセージボディーのタイプ

Camel JSonPath は、以下のタイプのメッセージボディーをサポートしています。

説明

File

ファイルからの読み込み

String

プレーンテキスト

マップ

メッセージボディーは java.util.Map

リスト

メッセージボディーは java.util.List 型

POJO

任意。Jackson がクラスパス上にある場合、camel-jsonpath は Jackson を使用してメッセージボディーを POJO から java.util.Map (JSonPath でサポートされる) に変換の上、JSonPath で処理することができます。たとえば、依存関係として camel-jackson を追加して、Jackson を含めることができます。

InputStream

上記のタイプがどれも一致しない場合、Camel はメッセージボディーを java.io.InputStream 型で読み込みます。

メッセージボディーがサポートされないタイプの場合は、デフォルトでは例外が出力されますが、JSonPath の設定で例外を抑止できます。

例外の抑制

jsonpath 式によって設定されたパスが見つからない場合、JSONPath は例外を出力します。SuppressExceptions オプションを true に設定すると、例外を無視できます。たとえば、以下のコードで、jsonpath パラメーターの一部として true オプションを追加します。

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

XML DSL では、以下の構文を使用します。

<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>

JsonPath の注入

Bean インテグレーションを使用して Bean メソッドを呼び出す場合、JsonPath を使用してメッセージから値を抽出し、それをメソッドパラメーターにバインドできます。以下に例を示します。

// Java
public class Foo {

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

インライン Simple 式

Camel 2.18 の新機能。

Camel は JsonPath 式でインライン Simple 式をサポートします。Simple 言語の挿入は、以下のように Simple 構文で記述する必要があります。

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");

Simple 式のサポートを無効にするには、以下のようにオプション allowSimple=false を設定します。

Java の場合

// Java DSL
.when().jsonpath("$.store.book[?(@.price < 10)]", false, false)

XML DSL の場合

// XML DSL
<jsonpath allowSimple="false">$.store.book[?(@.price &lt; 10)]</jsonpath>

リファレンス

JsonPath の詳細については、JSonPath プロジェクト のページを参照してください。