menu
書いてる野郎
orebike@gmail.com
Spring Boot には Java の JSON オペレーションライブラリの Jackson が内蔵されている。 これを使うと Java のインスタンスを楽に JSON 化できる。
このようにコントローラークラス自体を @RestController
アノテーション指定にして、メソッドがそのように作られた(アクセサがある)インスタンスを返すように記述すると、それが自動的に JSON 化されてレスポンスされる。その名前は getter から自動的に類推される。
@RestController @RequestMapping("/json/hoge") public class HogeJsonController { @RequestMapping("") public Hoge index() { Hoge hoge = new Hoge(); hoge.setV1("hogehogehoge"); hoge.setV2(123); return hoge; } public static class Hoge{ private String v1; private Integer v2; public String getP1(){ return this.v1; } public void setV1(String v){ this.v1 = v; } public Integer getP2(){ return this.v2; } public void setV2(Integer v){ this.v2 = v; } } }
このように記述しておくと、↓のようなレスポンスで返される
{"p1":"hogehogehoge","p2":123}
@Controller
アノテーション指定されている Conbtroller クラス中で一部のメソッドだけ JSON を返したいという場合はこのように @ResponseBody
アノテーションを戻す型指定にくっつける。
@RequestMapping("/hogehoge") public @ResponseBody HogeHoge hogehoge() {
public にすることで getter を作らずにそのメンバ名のまま出力できる。
public static class Hoge{ public String v1; public Integer v2; }
このように記述しておくと、↓のようなレスポンスで返される
{"v1":"hogehogehoge","v2":123}
便利なようだが、このようなインスタンスは必ず別の構造を持つインスタンス由来になっているので getter がなくなるという状況はよほど単純か手抜き仕様でなければないと思われる。 こいつは View なので元になるクラスがこいつに依存することもないし。
このように出力するクラスに @JsonPropertyOrder
をつけて出したいキーの順番に書けば順番に出る。
@JsonPropertyOrder({"v2", "v1"}) public static class Hoge{ public String v1; public Integer v2; }
データベースに入れた情報をなんでもかんでもクライアント側に返してよいわけが無い。 Jackson では何も考えず単に return するとそれが全部出力されてしまう。 なので自分の知らないところで仕様が変更されて(秘密な情報が追加等)もそれに気づかなければそのまま出てしまう。
なので出力する情報は選ぶようにして実装する必要がある。
HTML だったらちゃんと選んで成形して出すのに JSON になったとたん DB の中身全部出せばいいとか言い出す人が多くてビビる。
JSON化対象のクラスのJSON化に使いたいメソッドに @JsonValue
アノテーションをつける。そうするとそこで構築した Map で JSON を生成してくれる。
構造が込み入っている場合はこれを利用してもよいかも。
逆にこれさえ知っておけばどんな形式のデータからでも任意の JSON を作れるのでプロジェクトのルールとして変換は全部これで書くみたいなことになってもいいかも
public class Hoge { // 中略 @JsonValue public Map<String, Object> toMapForJson() { Map<String, Object> map = new HashMap<>(); map.put("v_v_v_1", 123); map.put("v_v_v_v_2", "hogehoge"); return map; } }
もうシステムの中でも JSON的な文字列としてDB等に保存していて、それをそのまま出したい場合どうするか。
そのままやってしまうと、ダブルクォートで囲まれたそのままの JSONとしても文字列でJSONっぽい文字列として出力されてしまう。JSON中に Object として出力したい場合はどうするか?。
この場合は一旦別のクラスでこの文字列をラップしてやればよい。 Doma を使っているならドメインクラスがあるのでこれを利用すればよい。
class JsonString{ public String value; public JsonString(String v){ this.value = v; } @JsonRawValue @JsonValue public String asRawJsonForJackson(){ return this.value; } }
JsonValue のアノテーションと JsonRawValue のアノテーションを2つつける。
そしてこのラッパーで包んだ状態で map にブチ込んでやると、文字列として解釈されず内蔵した JSON がそのまま JSON として出力される。
@Entity public class Hoge { // 中略 @JsonValue public Map<String, Object> toMapForJson() { Map<String, Object> map = new HashMap<>(); map.put("id", this.id.getValue()); map.put("piyo", new JsonString(this.piyo)); return map; } }