1. test 1
  2. test 2
  3. test 3
コース一覧
Spring Boot入門
recordでDTOを書く

Spring Boot入門

Java で Web API サーバーを作るための Spring Boot の入門コースです。DI コンテナ、REST コントローラ、リクエスト検証、レイヤ分割、Spring Data JPA、例外ハンドリング、テストまでを扱います。毎レッスン、Spring が裏側でやっている判断そのものを pure Java の関数として自分で書き、フレームワークが何を肩代わりしてくれているのかを手触りで理解できる構成にしました。約 12 時間 (1 日 30 分 × 24 日) で 48 レッスンを修了できます。

1
Spring Bootとは何か
01. Spring Bootで何が作れるのか10分
02. サーブレットからフレームワークへ15分
03. ルーティング表という発想15分
04. プロジェクトの構成10分
05. 起動のしくみと自動設定15分
06. パスのマッチング15分
2
DIコンテナ
01. newで書くと何が困るのか15分
02. コンストラクタインジェクション15分
03. インターフェースへの依存15分
04. @Componentと@Bean15分
05. 自作のDIコンテナ20分
06. Beanのスコープとライフサイクル15分
3
RESTコントローラ
01. RESTという設計方針15分
02. @RestControllerの役割15分
03. @GetMappingとパス変数15分
04. クエリパラメータの受け取り15分
05. @PostMappingとリクエストボディ15分
06. ステータスコードの選び方15分
07. ResponseEntityで組み立てる15分
4
リクエストとレスポンスの変換
01. JSONとオブジェクトの往復15分
02. DTOとエンティティを分ける15分
03. recordでDTOを書く15分
04. 入力検証の基本15分
05. 検証エラーをまとめて返す15分
06. アノテーションによる検証15分
5
レイヤ構成とビジネスロジック
01. 3層アーキテクチャ10分
02. @Serviceに置くもの15分
03. 状態遷移をルールにする15分
04. 料金計算のような業務ロジック15分
05. @Transactionalとは何か15分
06. トランザクションの巻き戻し15分
6
データアクセス
01. @Entityとテーブルの対応15分
02. リポジトリという抽象15分
03. メソッド名からクエリを作る20分
04. 検索条件の組み立て15分
05. ページングと並び替え15分
06. N+1問題15分
7
例外処理と横断的関心事
01. 例外をHTTPに変換する15分
02. @ExceptionHandlerと@ControllerAdvice15分
03. エラーレスポンスの形を決める15分
04. フィルタとインターセプタ15分
05. ログとリクエストの追跡15分
06. 設定値の外部化15分
8
テストと仕上げ
01. テストの種類と使い分け15分
02. Serviceの単体テスト15分
03. モックで依存を差し替える15分
04. MockMvcでエンドポイントを試す15分
05. 本番へ出すための次の一歩10分

recordでDTOを書く

このレッスンでは、Java の record がどういう仕組みで、なぜ DTO に向いているのかを説明できるようになります。

クラスで DTO を書くと長くなります

値を運ぶだけのクラスを従来の書き方で作ると、フィールド、コンストラクタ、getter、equals、hashCode、toString をすべて手で書くことになります。項目が3つあるだけで50行を超えることも珍しくありません。しかも本質的な情報は「id と name と email を持つ」という1行だけです。

record は宣言1行で済みます

Java

public record UserResponse(Long id, String name, String email) {}

この1行から、コンパイラが次のものを自動で生成します。

生成されるもの内容
フィールドprivate final な id、name、email
正準コンストラクタ宣言の順に3つの引数を取るコンストラクタ
アクセサid()、name()、email() (getId() ではありません)
equals と hashCode全コンポーネントの値で比較する実装
toStringUserResponse[id=1, name=taro, email=t@example.com] の形

アクセサの名前が getXxx ではなくコンポーネント名そのままである点に注意してください。Jackson は record を認識してコンポーネント名をそのまま JSON のキーに使うので、この違いが問題になることはほとんどありません。

不変であることが効いてきます

record のフィールドはすべて final で、setter は生成されません。一度作ったら値が変わらないので、次の利点があります。

  1. 複数のスレッドから同時に読んでも壊れない
  2. 「いつの間にか値が書き換わっていた」という種類のバグが起きない
  3. Map のキーや Set の要素として安心して使える

DTO はまさに「作って渡して読むだけ」の存在なので、この性質と噛み合います。逆に、JPA のエンティティは永続化のために引数なしコンストラクタと可変のフィールドを必要とするため、record にはできません。エンティティは普通のクラス、DTO は record、という住み分けが自然です。

コンパクトコンストラクタで検証も書けます

引数の検証を入れたいときは、コンパクトコンストラクタという書き方が使えます。

Java

public record UserResponse(Long id, String name) { public UserResponse { if (name == null || name.isBlank()) { throw new IllegalArgumentException("name is required"); } } }

引数リストを書かない形で、フィールドへ代入される直前に割り込めます。

入れ子にできます

record のコンポーネントに別の record を置けます。住所を持つ利用者のように、構造のあるレスポンスを型で素直に表現できます。

Java

public record Address(String city, String zip) {} public record UserResponse(Long id, String name, Address address) {}

演習で書くもの

演習では入れ子になった record を自分で定義し、それを組み立ててから整形した文字列を返します。Spring では、この record がそのまま JSON へ直列化されてレスポンス本文になります。ここでは直列化の代わりに、アクセサを使って値を読み出し、決まった形の文字列を組み立ててください。record を宣言するだけでアクセサとコンストラクタが手に入ること、そして入れ子でも自然に扱えることを手で確かめます。

要件

  1. Main の中に record Address(String city, String zip) を定義すること
  2. Main の中に record UserResponse(long id, String name, Address address) を定義すること
  3. describe は UserResponse を組み立て、id、name、address.city、address.zip をこの順に縦棒でつないだ文字列を返すこと

入出力例

describe(1, "taro", "tokyo", "1000001") → "1|taro|tokyo|1000001" describe(42, "hanako", "osaka", "5300001") → "42|hanako|osaka|5300001" describe(7, "guest", "kyoto", "6000001") → "7|guest|kyoto|6000001"

ヒント

record は Main の中に static なメンバとして書けます。record Address(String city, String zip) {} の1行で定義は終わりです

record のアクセサ名は getCity ではなく city です。生成されたアクセサは引数なしで呼びます

入れ子は user.address().city() のようにアクセサを続けてたどります

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/08/09

関連レッスン

  • 入力検証の基本

    必須・長さ・範囲の検証を実装できるようになります。

  • 検証エラーをまとめて返す

    複数のエラーを集約したレスポンスを組み立てます。

  • アノテーションによる検証

    @NotNull と @NotBlank の違いなどを確認します。

  • 3層アーキテクチャ

    層を分ける理由と、それぞれの責務を説明できるようになります。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • クラスデータと振る舞いを束ねる単位
  • フィールドクラスが持つデータ
  • コンストラクタインスタンス生成時の初期化処理
  • 引数位置引数=順番で渡す。
  • コンポーネントUI を構成する再利用可能な部品
  • applicationJSON 本文を送るときの Content-Type
  • スレッド1 つの質問に紐づく返信の集まり
  • エンティティDB の 1 行 = アプリの 1 オブジェクト
main.java
学習モード
エディタを読み込んでいます

メモ

recordでDTOを書く

⌘S で保存