JSONとオブジェクトの往復
このレッスンでは、JSON とオブジェクトの往復を Spring Boot がどう肩代わりしているのかを理解し、その変換処理の中身を自分の手で書けるようになります。
リクエストの本文はただの文字列です
クライアントから届くのは、次のような文字の並びでしかありません。
JSON
{"name":"taro","age":20}これは Java から見ればただの String です。{ や " の位置を読み取り、キーと値に切り分け、age は数値だと判断し、User クラスのフィールドへ入れる。この一連の作業を誰かがやらなければ、コントローラのメソッドはオブジェクトを受け取れません。
Spring Boot ではその作業を Jackson というライブラリが担当します。spring-boot-starter-web を入れると Jackson が一緒に入り、MappingJackson2HttpMessageConverter として自動で登録されます。だから開発者は変換コードを1行も書きません。
@RequestBody が入口です
Java
@RestController
@RequestMapping("/users")
public class UserController {
@PostMapping
public User create(@RequestBody UserRequest req) {
return new User(req.getName(), req.getAge());
}
}@RequestBody が付いた引数を見ると、Spring はリクエストの Content-Type を確認し、application/json であれば Jackson を選び、本文の文字列を UserRequest に変換してから引数へ渡します。この方向をデシリアライズと呼びます。
戻り値は逆向きに変換されます
@RestController が付いたクラスのメソッドの戻り値は、ビューの名前ではなくレスポンス本文そのものとして扱われます。返した User オブジェクトは Jackson によって JSON の文字列に組み立て直され、Content-Type に application/json が付いて返ります。この方向をシリアライズと呼びます。
| 向き | 呼び名 | きっかけ | 変換の中身 |
|---|---|---|---|
| JSON から Java | デシリアライズ | @RequestBody | 文字列を解析してフィールドへ詰める |
| Java から JSON | シリアライズ | 戻り値 | フィールドを読み出して文字列を組む |
何をキーにするのかを Jackson は知っています
Jackson は既定でアクセサ(getter と setter)の名前からプロパティ名を決めます。getName があれば name というキーになります。record の場合はアクセサ名がそのままフィールド名なので、name と age がそのままキーになります。名前を変えたいときは @JsonProperty("user_name") のようにフィールドやアクセサへ付けて指定します。
型が合わないとどうなるでしょうか
{"age":"twenty"} のように数値のはずの場所へ文字列が入っていると、変換の途中で失敗します。Spring Boot はこれを 400 Bad Request として扱います。つまり検証の前に、まず変換が通るかどうかという関門があるわけです。コントローラのメソッドには一度も入りません。
演習で書くもの
この演習では、Jackson がやっていることを極端に単純にした形で体験します。name=taro;age=20 のような区切り文字列の解析と型の判定は、ひな形の補助メソッドが担当します。解析済みの値が数値なら数値として、そうでなければ文字列としてクオートを付けて、JSON らしい文字列を組み立てます。Spring では @RequestBody を書けば自動で行われる処理を、ここでは出力の組み立てを自分の手で書きます。区切りの解析、型の判定、出力の組み立てという3つの仕事が変換の正体だと分かるはずです。
演習で使うひな形
parseFields("name=taro;age=20") は2項目の配列です。最初は key が "name"、value が "taro"、number が false です。次は "age"、"20"、true です。fields[i].number で分岐し、JSON では文字列の "taro" は引用符で囲み、数値の 20 は囲まないことを確かめます。入力の解析は用意済みです。
要件
- 配列の項目を入力順に処理すること
- キーは引用符で囲み、number が true の値はそのまま、false の値は引用符で囲むこと
- 項目間だけにカンマを入れ、全体を波括弧で囲むこと