フラットに属性が並んだオブジェクトから、階層のあるJSON への変換(1)

フラットに属性が並んだオブジェクト → 階層構造オブジェクト → JSON
という流れで処理するのは、階層構造オブジェクト の定義クラスを設計、配置するこのやり方は
非常にナンセンスと思う。
階層構造オブジェクト の定義クラスの存在無しで処理したい。

Google gson で解決してみる。

(例)Sample.class

public class Sample{
   public String title;
   public String name;
   public int value;
}

このうち、String nameint value"Unit" というキー名で括る。という要求
期待する JSON サンプルが、

{
  "title": "あいう",
  "Unit": {
    "name": "A",
    "value": 121
  }
}

JsonWriter だけで対応する場合

Sample s = new Sample();
// TODO  s に値をセットする。
try(JsonWriter writer = new JsonWriter(new PrintWriter(System.out))){
   writer.setIndent("  ");
   writer.beginObject();
   writer.name("title").value(s.title);

   JsonWriter writer2 = writer.name("Unit");
   writer2.beginObject();
   writer2.name("name").value(s.name);
   writer2.name("value").value(s.value);
   writer2.endObject();

   writer.endObject();
}catch(IOException e){
   e.printStackTrace();
}

子の階層 JsonWriter を生成して、 beginObject() と endObject() を忘れずに呼ばなければならず、
ちょっとコードが汚くなりやすい。

JsonSerializer を用意して、gson で処理

import java.lang.reflect.Type;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

public class SampleSerializer implements JsonSerializer<Sample>{

   @Override
   public JsonElement serialize(Sample src, Type typeOfSrc, JsonSerializationContext context){
      JsonObject jo = new JsonObject();
      jo.addProperty("title", src.title);
      JsonObject unit = new JsonObject();
      unit.addProperty("name", src.name);
      unit.addProperty("value", src.value);
      jo.add("Unit", unit);
      return jo;
   }

}
Gson gson = new GsonBuilder()
		.serializeNulls()
		.registerTypeAdapter(Sample.class, new SampleSerializer())
		.setPrettyPrinting()
		.create();
Sample s = new Sample();
// TODO  s に値をセットする。
String result = gson.toJson(s);

期待する JSON が以下のように、この Sample が、"sample" として入っている場合で、
JsonWriter の使用を組み合わせると、、、

{
  "name": "Uranus",
  "admin": false,
  "sample": {
    "title": "あいう",
    "Unit": {
      "name": "A",
      "value": 121
    }
  }
}
Gson gson = new GsonBuilder()
.serializeNulls()
.registerTypeAdapter(Sample.class, new SampleSerializer())
.create();

Sample sample = new Sample();
// TODO sample に値をセットする。

try(JsonWriter writer = new JsonWriter(new PrintWriter(System.out))){
   writer.setIndent("  ");
   writer.beginObject();

   writer.name("name").value("Uranus");
   writer.name("admin").value(false);

   gson.toJson(sample, TypeToken.get(Sample.class).getType(), writer.name("sample"));

   writer.endObject();
}catch(IOException e){
   e.printStackTrace();
}

Sample をセットする以下の部分は、

  gson.toJson(sample, TypeToken.get(Sample.class).getType(), writer.name("sample"));

JsonWriter#name(String) で作成した JsonWriter を toJsonに使用していることである、
つまり、

JsonWriter writer2 = writer.name("sample");
gson.toJson(sample, TypeToken.get(Sample.class).getType(), writer2);

を1つにまとめている。

フラットに属性が並んだオブジェクトから、階層のあるJSON への変換の
結論は、JsonSerializer を用意した方が良さそうである。