Serializableはどういう意味があるか?(serialVersionUIDは?)
Serializableの意味、それから serialVersionUIDについて調べてみた。
セッションを使って調べてみた。
まず、以下のコードを書く。
ex.Fruit.java
package ex;
import java.io.Serializable;
public class Fruit implements Serializable {
private String name;
private int price;
public Fruit() {}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setPrice(int price) {
this.price = price;
}
public int getPrice() {
return price;
}
}
JavaBeansである。Serializableを実装している。
ex.FruitServlet.java
package ex;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet("/fruit")
public class FruitServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Fruit fruit = new Fruit();
fruit.setName("いちご");
fruit.setPrice(700);
HttpSession session = request.getSession();
session.setAttribute("fruit", fruit);
}
}
Fruitインスタンスを作成してそれをセッションスコープに保存している。
これを表示するのが、以下。
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="ex.Fruit" %>
<%
Fruit fruit = (Fruit)session.getAttribute("fruit");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>fruit</title>
</head>
<body>
<h1>index.jspやで</h1>
<%= fruit.getName() %>の値段は <%= fruit.getPrice() %>円です。
</body>
</html>
サーバーを起動して試してみる
サーバーを再起動して、”http://localhost:8080/(project)/fruit” に
アクセスすると、サーブレットがセッションスコープに Fruitインスタンスを
保存する。
それから “http://localhost:8080/(project)/” にアクセスして
index.jspを動作させる。
index.jspやで
いちごの値段は 700円です。
と表示させる。
再起動しても表示できる
再起動しても表示できるのは、セッションスコープに保存した Fruitインスタンス
がディスクに保存されているからと推測できる。
Serializableをはずすと表示されない
Serializable実装は、直列化と復元を可能にするということなので、
“implements Serializable” を削除すると、再起動して index.jsp を表示しても、
セッションスコープに保存した Fruitインスタンスを取得できない。
serialVersionUIDの働き
Serializableインターフェースを実装して
“http://localhost:8080/(project)/fruit” にアクセスして
セッションスコープに Fruitインスタンスを保存してのち、
Fruit.java を変更する。
ex.Fruit.java
package ex;
import java.io.Serializable;
public class Fruit implements Serializable {
private String name;
// private int price;
public Fruit() {}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
// public void setPrice(int price) {
// this.price = price;
// }
//
// public int getPrice() {
// return price;
// }
}
また、それに対応して FruitServletも以下のようにする。
ex.FruitServlet.java
package ex;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet("/fruit")
public class FruitServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Fruit fruit = new Fruit();
fruit.setName("いちご");
// fruit.setPrice(700);
HttpSession session = request.getSession();
session.setAttribute("fruit", fruit);
}
}
index.jsp では、price を表示している箇所を変更しておく。
<%= fruit.getName() %>の値段は ???円です。
これで、”http://localhost:8080/(project)/” と
index.jspを表示させると、以下のようなエラーが出る。
HTTPステータス 500 — Internal Server Error
…
[/index.jsp]の処理中に行番号 [15] で例外が発生しました。
…
15: <%= fruit.getName() %>の値段は ???円です。
…
根本原因
javax.el.PropertyNotFoundException: タイプ [ex.Fruit] で
プロパティー [price] が見つかりません。
直列化してファイルに保存したのだが、Fruitインスタンスのフィールドを
変更したので、復元に失敗している。
serialVersionUID = 1L の働き
しかし、Fruit.java に serialVersionUID を記述すると、うまくいく。
ex.Fruit.java
package ex;
import java.io.Serializable;
public class Fruit implements Serializable {
private static final long serialVersionUID = 1L; // <==
private String name;
private int price;
public Fruit() {}
...
(以下、略)
これを記述してから、”http://localhost:8080/(project)/fruit” に
アクセスして、Fruitインスタンスをセッションスコープに保存する。
それから、Fruit.java の private int priceフィールドと、それに
関連するゲッター・セッターを削除もしくはコメントアウトし、
FruitServlet の
fruit.setPrice(700);
を削除もしくはコメントアウトしてから、
サーバーを再起動する。
“http://localhost:8080/(project)/” にアクセスして index.jsp を
表示させる。
serialVersionUIDを記述しなければ、
セッションスコープに保存して直列化されたときに自動的に
serialVersionUIDが設定されるが、
フィールドを変更すると、直列化したときの serialVersionUID は別の数字に
変わってしまう。
だから、サーバーを再起動したのちに index.jspでセッションスコープから
Fruitインスタンスを取得したとき、その serialVersionUIDと、index.jsp
が importした ex.Fruitインスタンスの serialVersionUIDが違っている
のである。
しかし、”serialVersionUID = 1L” と設定しておくと、セッションスコープから
取得した Fruitインスタンスと、importした ex.Fruitインスタンスに
違いがあっても、同じものとみなされるのである。
カテゴリー: Java, memo
タグ: Serializable, serialversionuid, session, セッション, 直列化
カウント: 134