フラットに属性が並んだオブジェクト → 階層構造オブジェクト → JSON
という流れで処理するのは、階層構造オブジェクト の定義クラスを設計、配置するこのやり方は
非常にナンセンスと思う。
階層構造オブジェクト の定義クラスの存在無しで処理したい。
Google gson で解決してみる。
(例)Sample.class
public class Sample{ public String title; public String name; public int value; }
このうち、String name と int 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 を用意した方が良さそうである。