シリアライゼーション完全ガイド
シリアライゼーション完全ガイド
Section titled “シリアライゼーション完全ガイド”Javaのシリアライゼーション(直列化)の仕組みと実践的な使用方法を、実務で使える実装例とベストプラクティスとともに詳しく解説します。
1. シリアライゼーションとは
Section titled “1. シリアライゼーションとは”シリアライゼーションの役割
Section titled “シリアライゼーションの役割”シリアライゼーションは、オブジェクトをバイトストリームに変換するプロセスです。
シリアライゼーションの用途 ├─ オブジェクトの永続化 ├─ ネットワーク通信 ├─ 分散システム └─ キャッシング基本的な使用
Section titled “基本的な使用”import java.io.*;
// Serializableインターフェースを実装public class User implements Serializable { private String name; private int age;
public User(String name, int age) { this.name = name; this.age = age; }
// シリアライゼーション public void serialize(String filename) throws IOException { try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(filename))) { oos.writeObject(this); } }
// デシリアライゼーション public static User deserialize(String filename) throws IOException, ClassNotFoundException { try (ObjectInputStream ois = new ObjectInputStream( new FileInputStream(filename))) { return (User) ois.readObject(); } }}2. Serializableインターフェース
Section titled “2. Serializableインターフェース”基本的な実装
Section titled “基本的な実装”import java.io.Serializable;
public class Person implements Serializable { private String name; private int age;
// デフォルトコンストラクタが必要 public Person() {}
public Person(String name, int age) { this.name = name; this.age = age; }
// getters and setters}serialVersionUID
Section titled “serialVersionUID”import java.io.Serializable;
public class User implements Serializable { // serialVersionUIDを明示的に定義(推奨) private static final long serialVersionUID = 1L;
private String name; private int age;
// クラスの構造が変更された場合、serialVersionUIDを更新 // private static final long serialVersionUID = 2L;}3. カスタムシリアライゼーション
Section titled “3. カスタムシリアライゼーション”writeObjectとreadObject
Section titled “writeObjectとreadObject”import java.io.*;
public class CustomSerialization implements Serializable { private static final long serialVersionUID = 1L; private String name; private transient String password; // シリアライズしない
private void writeObject(ObjectOutputStream oos) throws IOException { oos.defaultWriteObject(); // デフォルトのシリアライゼーション oos.writeObject(encrypt(password)); // カスタム処理 }
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); // デフォルトのデシリアライゼーション password = decrypt((String) ois.readObject()); // カスタム処理 }
private String encrypt(String data) { // 暗号化処理 return data; }
private String decrypt(String data) { // 復号化処理 return data; }}4. Externalizableインターフェース
Section titled “4. Externalizableインターフェース”Externalizableの実装
Section titled “Externalizableの実装”import java.io.*;
public class ExternalizableExample implements Externalizable { private String name; private int age;
// デフォルトコンストラクタが必要 public ExternalizableExample() {}
public ExternalizableExample(String name, int age) { this.name = name; this.age = age; }
@Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(name); // 明示的に書き込む out.writeInt(age); }
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name = in.readUTF(); // 明示的に読み込む age = in.readInt(); }}5. シリアライゼーションのバージョン管理
Section titled “5. シリアライゼーションのバージョン管理”バージョン互換性
Section titled “バージョン互換性”import java.io.*;
public class VersionedClass implements Serializable { private static final long serialVersionUID = 1L; private String name; private int age;
// 新しいフィールドを追加する場合 // private String email; // 新しいフィールド
// 後方互換性を保つための処理 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject();
// 古いバージョンのデータを読み込む場合の処理 try { // 新しいフィールドの読み込みを試みる // email = (String) ois.readObject(); } catch (EOFException e) { // 古いバージョンのデータの場合 email = "default@example.com"; } }}6. パフォーマンス最適化
Section titled “6. パフォーマンス最適化”オブジェクトプーリング
Section titled “オブジェクトプーリング”import java.io.*;
public class SerializationOptimization { // オブジェクトを再利用 private static final ThreadLocal<ByteArrayOutputStream> outputStreamPool = ThreadLocal.withInitial( ByteArrayOutputStream::new);
public byte[] serialize(Object obj) throws IOException { ByteArrayOutputStream baos = outputStreamPool.get(); baos.reset(); // リセット
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { oos.writeObject(obj); return baos.toByteArray(); } }}カスタムシリアライゼーションによる最適化
Section titled “カスタムシリアライゼーションによる最適化”import java.io.*;
public class OptimizedSerialization implements Serializable { private static final long serialVersionUID = 1L; private String name; private int age;
// カスタムシリアライゼーションでサイズを削減 private void writeObject(ObjectOutputStream oos) throws IOException { oos.writeUTF(name); // Stringを直接書き込む oos.writeInt(age); }
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { name = ois.readUTF(); age = ois.readInt(); }}7. セキュリティ考慮事項
Section titled “7. セキュリティ考慮事項”シリアライゼーションのリスク
Section titled “シリアライゼーションのリスク”// 問題のあるコード: 信頼できないソースからのデシリアライゼーションpublic class SecurityIssue { public Object deserialize(byte[] data) throws IOException, ClassNotFoundException { try (ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream(data))) { return ois.readObject(); // 危険: 任意のクラスを読み込める } }}安全なデシリアライゼーション
Section titled “安全なデシリアライゼーション”import java.io.*;
public class SecureDeserialization { // 許可されたクラスのリスト private static final Set<String> ALLOWED_CLASSES = Set.of("com.example.User", "com.example.Product");
public Object deserialize(byte[] data) throws IOException, ClassNotFoundException { try (ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream(data)) { // カスタムObjectInputStreamでクラスを検証 return new SecureObjectInputStream(ois).readObject(); } }
private static class SecureObjectInputStream extends ObjectInputStream { public SecureObjectInputStream(InputStream in) throws IOException { super(in); }
@Override protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { String className = desc.getName(); if (!ALLOWED_CLASSES.contains(className)) { throw new SecurityException( "Class not allowed: " + className); } return super.resolveClass(desc); } }}8. 実践的な使用例
Section titled “8. 実践的な使用例”オブジェクトの永続化
Section titled “オブジェクトの永続化”import java.io.*;
public class PersistenceExample { public void saveUser(User user, String filename) throws IOException { try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(filename))) { oos.writeObject(user); } }
public User loadUser(String filename) throws IOException, ClassNotFoundException { try (ObjectInputStream ois = new ObjectInputStream( new FileInputStream(filename))) { return (User) ois.readObject(); } }}ネットワーク通信
Section titled “ネットワーク通信”import java.io.*;import java.net.*;
public class NetworkSerialization { // サーバー側 public void server() throws IOException { try (ServerSocket serverSocket = new ServerSocket(8080); Socket socket = serverSocket.accept(); ObjectOutputStream oos = new ObjectOutputStream( socket.getOutputStream())) { User user = new User("Alice", 25); oos.writeObject(user); } }
// クライアント側 public void client() throws IOException, ClassNotFoundException { try (Socket socket = new Socket("localhost", 8080); ObjectInputStream ois = new ObjectInputStream( socket.getInputStream())) { User user = (User) ois.readObject(); System.out.println(user.getName()); } }}シリアライゼーション完全ガイドのポイント:
- Serializable: 基本的なシリアライゼーション
- serialVersionUID: バージョン管理
- カスタムシリアライゼーション: writeObject/readObject
- Externalizable: 完全な制御
- バージョン管理: 後方互換性
- パフォーマンス最適化: オブジェクトプーリング、カスタムシリアライゼーション
- セキュリティ: 安全なデシリアライゼーション
適切なシリアライゼーションにより、効率的なデータ永続化とネットワーク通信が可能になります。