My開発メモ

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