解説 · セクション 7

セッションとキャスト

HttpSession から取り出した Object を元の型にダウンキャストするときの注意。

読み終わったら問題に挑戦できます → 演習に進む

身近に置き換えると

遊園地の「入場リストバンド」と「手荷物預かり所」を想像してください。

Webサイトは通常、ページを移動するたびに「あなたが誰か」を忘れてしまいます。そこで、ログイン時に「リストバンド(HttpSession)」を渡し、あなた専用の「手荷物預かり所」を用意します。

預かり所にはどんな荷物でも預けられますが(setAttribute)、取り出すときは中身が何であれ「ただの荷物(Object)」として渡されます。そのため、受け取る側が「これはカメラだ」と明示的に確認(ダウンキャスト)しなければ使えません。そして帰るときは、リストバンドをハサミで切って(invalidate)すべてをリセットします。

3 行でまとめると

  • req.getSession() で自分専用の保管庫(セッション)を取得し、setAttribute でデータを保存する。
  • getAttribute で取り出すデータはすべて「Object型」になるため、元の型に戻す「ダウンキャスト」が必須。
  • ログアウト時などは invalidate() を呼んで、保管庫を安全に破棄する。

図で見ると

sequenceDiagram
    participant B as ブラウザ
    participant S as Servlet
    participant H as HttpSession

    B->>S: ログイン要求
    S->>H: req.getSession() で取得
    S->>H: setAttribute("user", user)
(User型を預ける) B->>S: マイページ要求 S->>H: getAttribute("user") H-->>S: Object型 として返却 Note over S: (User) でダウンキャストして復元 B->>S: ログアウト要求 S->>H: invalidate() で破棄

ページをまたいでも、同じリストバンド(セッションID)を持っていれば、サーバー側で以前預けたデータを取り出すことができます。

順を追って理解する

1. セッションを取得する

req.getSession() を呼び出すと、リクエストを送ってきたユーザー専用の HttpSession オブジェクトが取得できます。まだ存在しない場合は、新しく作成されます。

2. データを保存する

session.setAttribute("キー名", 保存したいオブジェクト) を使ってデータを預けます。キー名は、後で取り出すときの「引換券」の役割を果たします。

3. データを取り出してキャストする

別のページで session.getAttribute("キー名") を呼び出すとデータを取り出せます。ただし、セッションはどんな型でも預かれるように設計されているため、戻り値はすべて Object 型になります。元のオブジェクトとして使うには、(User) のように ダウンキャスト を行う必要があります。

4. 間違った型へのキャスト(ClassCastException)

もし "user" というキーで String を預けていたのに、取り出すときに (User) にキャストしようとすると、Javaは「型が違う」と判断し、実行時に ClassCastException というエラーを発生させます。預けた型と取り出す型は必ず一致させなければなりません。

5. セッションを破棄する

ユーザーがログアウトするときは、session.invalidate() を呼び出します。これにより、セッション内のデータがすべて消去され、セキュリティが保たれます。

応用ではこう書く

// --- ログイン処理を行う Servlet ---
HttpSession session = req.getSession();
User loginUser = new User("Taro", "taro@example.com");

// セッションに User オブジェクトを保存
session.setAttribute("user", loginUser);


// --- マイページを表示する Servlet ---
HttpSession session = req.getSession();

// getAttribute は Object 型を返すため、(User) でダウンキャストする
User user = (User) session.getAttribute("user");

if (user != null) {
    // キャストしたことで、User クラスのメソッドが呼べるようになる
    System.out.println("ようこそ、" + user.getName() + "さん");
} else {
    System.out.println("ログインしていません");
}


// --- ログアウト処理を行う Servlet ---
HttpSession session = req.getSession();
// セッションを破棄(保存されていたデータもすべて消去される)
session.invalidate();

MVCアーキテクチャでは、Controller(Servlet)で取得したデータをセッションに保存し、View(JSPなど)や別のControllerで取り出して使う、という流れが基本になります。

よくある誤解

誤解: getAttribute で取り出した値は、そのまま元の型の変数に入れられる

正しくは: getAttribute の戻り値は常に Object 型です。そのため、User user = session.getAttribute("user"); と書くとコンパイルエラーになります。必ず User user = (User) session.getAttribute("user"); のように、明示的にキャストの記述をする必要があります。

誤解: invalidate() を呼ばなくても、ブラウザを閉じればセッションはすぐに消える

正しくは: ブラウザを閉じるとセッションID(リストバンド)が失われるためアクセスできなくなりますが、サーバー側のセッションデータ自体は一定時間(デフォルトで30分など)残り続けます。ログアウト機能を作る際は、必ず invalidate() を明示的に呼んで即座に破棄するのが安全です。

つまずいたら

このトピックで詰まったら基礎復習へ: 章 3 クラスの継承 (キャスト周り)

準備できたら問題に挑戦 → 演習に進む (5 問)