To use ObjectOutputStream with a Java record, you need to make the record implement the java.io.Serializable interface.
One of the great things about records is that they are designed to be “data carriers,” and Java’s serialization mechanism handles them more robustly and securely than regular classes. Specifically, records are serialized using only their components (the fields defined in the header), and the deserialization process uses the record’s canonical constructor, ensuring that any validation logic you’ve placed there is always executed.
Here is a complete example of how to write a record to a file and read it back:
1. Define the Record
Make sure it implements Serializable.
package org.kodejava.io;
import java.io.Serializable;
/**
* A simple record representing a Person.
* Records are implicitly final and their fields are private and final.
*/
public record Person(String name, int age) implements Serializable {
// Compact constructor for validation
public Person {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
}
}
2. Serialize and Deserialize
Use ObjectOutputStream to write the object and ObjectInputStream to read it.
package org.kodejava.io;
import java.io.*;
public class RecordSerializationDemo {
public static void main(String[] args) {
String filename = "person.ser";
Person person = new Person("John Doe", 30);
// 1. Serialize the record
try (FileOutputStream fos = new FileOutputStream(filename);
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(person);
System.out.println("Record saved: " + person);
} catch (IOException e) {
e.printStackTrace();
}
// 2. Deserialize the record
try (FileInputStream fis = new FileInputStream(filename);
ObjectInputStream ois = new ObjectInputStream(fis)) {
Person savedPerson = (Person) ois.readObject();
System.out.println("Record loaded: " + savedPerson);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Key Points to Remember:
- Immutability: Since records are immutable, serialization is very straightforward.
- No
serialVersionUIDRequired (mostly): While you can define aserialVersionUID, Java’s serialization for records ignores the field-matching rules that usually require it. The serialization is based strictly on the component names. - Security: Records are less susceptible to “deserialization attacks” because they don’t allow the creation of “ghost” objects; they must go through the canonical constructor.
- Customization: Records do not support
writeObject,readObject,readObjectNoData, orwriteExternalmethods. If you need custom serialization logic, you should use a regular class instead.
