serialization

Serialisierung


Motivation

public class Student {

    private int id;
    private String name;
    private School school;
    private Address address;
    
    public Student(byte[]) { ... }
    
    public byte[] serialize() { ... }

Implementierung

public byte[] serialize() throws IOException {
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
         DataOutputStream output = new DataOutputStream(baos)) {
        output.writeInt(id);
        output.writeUTF(name);
        output.write(school.serialize());
        output.write(address.serialize());
        return baos.toByteArray();
    }
}
public Student(byte[] data) throws IOException {
    try (DataInputStream dis = new DataInputStream(
            new ByteArrayInputStream(data))) {
        id = dis.readInt();
        name = dis.readUTF();
        school = new School(dis.readNBytes(???));
        address = new Address(dis.readNBytes(???));
    }
}

ObjectOutputStream

School htl = new School("HTL");
Student student = new Student(42, "Bob", htl);

try (ObjectOutputStream output = new ObjectOutputStream(
        new FileOutputStream("student.dat"))) {
    output.writeObject(student);
}
Exception in thread "main" java.io.NotSerializableException: 
        serializing.domain.Student

Serializable

public interface Serializable { }

Marker-Interface, markiert Klasse als serialisierbar

public class Student implements Serializable
School htl = new School("HTL");
Student student = new Student(42, "Bob", htl);

try (ObjectOutputStream output = new ObjectOutputStream(
        new FileOutputStream("student.dat"))) {
    output.writeObject(student);
}
Exception in thread "main" java.io.NotSerializableException: 
        serializing.domain.School

public class School implements Serializable
School htl = new School("HTL");
Student student = new Student(42, "Bob", htl);

try (ObjectOutputStream output = new ObjectOutputStream(
        new FileOutputStream("student.dat"))) {
    output.writeObject(student);
}
try (ObjectInputStream input = new ObjectInputStream(
        new FileInputStream("student.dat"))) {
    Student deserialized = (Student) input.readObject();
}

Customization


transient

public class Student implements Serializable {

    private int id;
    private String name;
    private transient List<Grade> grades;
    ...
       
}

Beim Serialisieren nicht berücksichtigt:

  • statische Felder
  • transiente Felder

writeObject/readObject

public class Student implements Serializable {

    private int id;
    private String name;
    private School school;
    
    @Serial
    private void writeObject(ObjectOutputStream output)
            throws IOException {
        output.writeByte(42);
        output.writeUTF("Chuck Norris");
    }

    @Serial
    private void readObject(ObjectInputStream input)
            throws IOException, ClassNotFoundException {
        id = input.readByte();
        name = input.readUTF();
    }
}

School htl = new School("HTL");
Student student = new Student(17, "Bob", htl);

try (ObjectOutputStream output = new ObjectOutputStream(
        new FileOutputStream("student.dat"))) {
    output.writeObject(student);
}

try (ObjectInputStream input = new ObjectInputStream(
        new FileInputStream("student.dat"))) {
    Student deserialized = (Student) input.readObject();
}
Student{id=42, name='Chuck Norris', school=null}

komplette Kontrolle über Serialisierung


serialVersionUID

  • Objekt wird serialisiert
  • Klasse wird verändert
  • Objekt wird deserialisiert
    • ✔️ wenn serialVersionUID ident
    • 💥 sonst
  • serialVersionUID wird bei Bedarf vom Compiler automatisch generiert 👍
public class Student implements Serializable {

    @Serial
    private static final long serialVersionUID = 42L;
    ...