1. はじめに
Jacksonで簡単にJson文字列 -> Javaオブジェクト
の変換処理(デシリアライズ)ができるのですが、どうしても一部のプロパティをJSON文字列のまま取得したい要件が発生しました。
何でも入る魔法のプロパティ(ここでは仮にpayloadとする)があって、別のプロパティに定義されているデータ型(FQCN)で復元したいというのが目的です。
JacksonにはJSON文字列を文字列のまま扱う@JsonValue
がありますが、これはシリアライズの場合のみ有効なものです。残念ながらデシリアライズの場合は対象外です。
対処方法は独自のJsonDeserializer
を実装して、@JsonDeserialize
で個別にデシリアライズ処理を指定することです。といっても目的が「JSON文字列のまま取得したい」なのでJsonDeserializer
の実装は非常に簡単です。
2. ソースコード
package com.example.jacksondemo;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
// ★ポイント1
public class JsonRawValueDeserializer extends JsonDeserializer<String> {
// ★ポイント2
@Override
public String deserialize(JsonParser parser, DeserializationContext context)
throws IOException, JsonProcessingException {
return parser.readValueAsTree().toString();
}
}
package com.example.jacksondemo;
import java.io.Serializable;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
public class MyModel implements Serializable {
private static final long serialVersionUID = 1L;
// ★ポイント3
// I want json raw text!
@JsonDeserialize(using = JsonRawValueDeserializer.class)
private String payload;
// these property are auto mapped by jackson (without special operation)
private String fqcn;
private Integer priority;
private String messageId;
// constructor, setter, getter omitted
}
★ポイント1
com.fasterxml.jackson.databind.JsonDeserializer
クラスを継承し、独自のJsonDeserializer
を定義します。
型パラメータにはデシリアライズの処理結果の型、つまり今回はString
を指定します。
★ポイント2
deserialize
メソッドをオーバーライドしてJSON文字列を返すように実装します。
★ポイント3
JSONをマッピングするJavaクラスにおいて、JSON文字列のまま値をマッピングしたいプロパティに@JsonDeserialize
アノテーションを付与します。
using
属性に★ポイント1で実装した独自のJsonDeserializer
を指定します。
これでJSONのpayload
プロパティがオブジェクトになっていても、そのJSON文字列がそのままStringのpayload
プロパティに格納されます。
今回の目的を実現するにはdqcn
プロパティを見てデータ型を特定した後、payload
プロパティのStringの値を目的のデータ型でデシリアライズしてあげればOKです。
3. さいごに
今回はJacksonのデシリアライズで一部のプロパティをJSON文字列のまま取得する方法について説明しました。
JacksonにはJsonを木構造のデータで読み込むJsonNode
という機能がありますが、JsonとJavaをマッピングする使い方が多いかと思います。その際、特定のプロパティだけはJsonのままで、という事態になった場合は今回の使い方を試してみてください。