Jackson の、普段あんまり使わない機能過ぎて使いたいときに忘れてぐぐって時間を浪費してしまうようなケースを回避するためにメモメモします。随時更新予定。
見ればわかりますが、元ネタはほぼすべて Stack Overflow です。英語だけだと読むのが辛い、という方向け(主に自分)にまとめています。
snake_case でプロパティを表現している JSON と camelCase で表記している POJO をマッピングしたい
java - Jackson overcoming underscores in favor of camel-case - Stack Overflow より。
引数に PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES
PropertyNamingStrategy.SNAKE_CASE
を指定して、 ObjectMapper#setPropertyNamingStrategy()
を呼び出すと、このマッピングをする ObjectMapper
を得ることができます。
(2016-09-29 更新: PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES
は deprecated になりました。代わりに PropertyNamingStrategy.SNAKE_CASE
を使う必要があります)
以下、利用例です。
public static class Hoge {
// このフィールドは JSON の "hoge_fuga" プロパティに対応する
public String hogeFuga;
}
public static void snakeCaseJsonToCamelCasePojo() throws IOException {
ObjectMapper mapper = new ObjectMapper()
.setPropertyNamingStrategy(
PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
Hoge hogeObj = mapper.readValue("{\"hoge_fuga\": \"piyopiyo\"}", Hoge.class);
System.out.println(hogeObj.hogeFuga);
}
ObjectMapper#writeValue() などで出力される JSON を整形&インデント (pretty print) したい
書式は何でもいいので、とにかくお手軽に整形したい
java - Pretty printing JSON from Jackson 2.2's ObjectMapper - Stack Overflow より。
引数に SerializationFeature.INDENT_OUTPUT
を指定して ObjectMapper#enable()
を呼び出すと、pretty print を有効にした ObjectMapper
を得ることができます。
以下、利用例です。
public static class Fuga {
public List<String> strings = Arrays.asList("foo", "bar", "baz");
public int number = 3;
}
public static void withPrettyPrint() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper()
.enable(SerializationFeature.INDENT_OUTPUT);
String json = mapper.writeValueAsString(new Fuga());
System.out.println(json);
}
出力結果はこんな感じ。この出力結果はそうでもないですが、標準の pretty printer はクセがあるので要注意です。
{
"strings" : [ "foo", "bar", "baz" ],
"number" : 3
}
書式はそのままでいいけど、インデント数は 2 つから 4 つに変更したい
java - Custom pretty printer using Jackson library - Stack Overflow より。
DefaultPrettyPrinter
が利用している Indenter
を標準の DefaultPrettyPrinter.Lf2SpacesIndenter
から独自のものに差し替えてあげることで実現できます。
/**
* インデント 4 つの Indenter 実装です。
*/
public class Lf4SpacesIndenter extends DefaultPrettyPrinter.Lf2SpacesIndenter {
final static char[] LONG_SPACES = new char[64 * 2];
static {
Arrays.fill(LONG_SPACES, ' ');
}
@Override
public void writeIndentation(JsonGenerator jg, int level) throws IOException, JsonGenerationException {
jg.writeRaw(_lf);
if (level > 0) {
int numSpaces = level * 4;
while (numSpaces > LONG_SPACES.length) {
jg.writeRaw(LONG_SPACES, 0, LONG_SPACES.length);
numSpaces -= LONG_SPACES.length;
}
jg.writeRaw(LONG_SPACES, 0, numSpaces);
}
}
}
public static class Fuga {
public List<String> strings = Arrays.asList("foo", "bar", "baz");
public int number = 3;
}
public static void with4SpacesIndentation() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper()
.enable(SerializationFeature.INDENT_OUTPUT);
String json = objectMapper
.writer(new DefaultPrettyPrinter()
.withObjectIndenter(new Lf4SpacesIndenter()))
.writeValueAsString(new Fuga());
System.out.println(json);
}
やっぱり標準の pretty printer の書式が気持ち悪いので JSON.stringify() ぽくしたい
サンプルコードは長くなってしまったので、Gist に投稿しました。
https://gist.github.com/komiya-atsushi/832a97c84ccae7cdfc2a
実装は非常にだるいのですが、 com.fasterxml.jackson.core.PrettyPrinter
を実装してしまえばだいたいなんでもできるようになります。
POJO の null なフィールドは出力しないで JSON にシリアライズしたい
幾つか方法があります。
その 1 : ObjectMapper に null なフィールドを無視させる設定をする
POJO のクラスをいじりたくない (いじれない) 場合に有効な方法です。
引数に JsonInclude.Include.NON_NULL
を指定して、 ObjectMapper#setSerializationInclusion()
を呼び出すことで、null なフィールドをシリアライズしない ObjectMapper
を得ることができます。
public static class Fuga {
public List<String> strings = null; // このフィールドはシリアライズして欲しくない
public int number = 3;
}
public static void ignoreNullFieldByObjectMapper() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper()
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
String json = mapper.writeValueAsString(new Fuga());
System.out.println(json);
}
実行結果はこちら。
{"number":3}
その 2 : POJO にアノテーションで、null なフィールドはシリアライズ不要である旨を表現させる
ObjectMapper
がいろんなところで使われていて、その 1 の対応方法では対処が難しい・面倒な場合にオススメです。
対象の POJO のクラス宣言にて、クラスに対して @JsonInclude(JsonInclude.Include.NON_NULL)
のアノテーションを付与します。
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Fuga {
public List<String> strings = null; // このフィールドはシリアライズして欲しくない
public int number = 3;
}
public static void ignoreNullFieldByAnnotation() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(new Fuga());
System.out.println(json);
}
列挙型 (enum) のフィールドを、文字列ではなく #ordinal() な値でシリアライズしたい
SerializationConfig.Feature.WRITE_ENUMS_USING_INDEX
と true
を指定して、 ObjectMapper#configure()
を呼び出します。
public enum Gender {
MALE, FEMALE
}
public static void serializeUsingEnumOrdinal() throws IOException {
List<Gender> genders = Arrays.asList(Gender.FEMALE, Gender.MALE);
String json = new ObjectMapper()
.configure(SerializationConfig.Feature.WRITE_ENUMS_USING_INDEX, true)
.writeValueAsString(genders);
System.out.println(json);
}