Posted at

Jacksonで一部のプロパティをJSON文字列のまま取得したい!

More than 1 year has passed since last update.


1. はじめに

Jacksonで簡単にJson文字列 -> Javaオブジェクトの変換処理(デシリアライズ)ができるのですが、どうしても一部のプロパティをJSON文字列のまま取得したい要件が発生しました。

何でも入る魔法のプロパティ(ここでは仮にpayloadとする)があって、別のプロパティに定義されているデータ型(FQCN)で復元したいというのが目的です。

JacksonにはJSON文字列を文字列のまま扱う@JsonValueがありますが、これはシリアライズの場合のみ有効なものです。残念ながらデシリアライズの場合は対象外です。

対処方法は独自のJsonDeserializerを実装して、@JsonDeserializeで個別にデシリアライズ処理を指定することです。といっても目的が「JSON文字列のまま取得したい」なのでJsonDeserializerの実装は非常に簡単です。


2. ソースコード


JsonRawValueDeserializer.java

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();
}
}



MyModel.java

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のままで、という事態になった場合は今回の使い方を試してみてください。