🔧 1. Use a Custom readObject()
Method
This is the standard way to hook into deserialization:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // Restore default values
// 💡 Customize here
if (age < 0) age = 0; // Validation
if (nickname == null) nickname = "Anonymous";
}
🔍 What this gives you:
- Access to the object’s fields right after they’re deserialized
- The ability to change, correct, or fill in missing/transient data
🔐 2. Use readResolve()
to Replace the Object
This is great for:
- Singletons
- Immutable instances
- Object deduplication
private Object readResolve() throws ObjectStreamException {
// Replace the deserialized object with a canonical one
return MyObjectRegistry.getInstanceById(this.id);
}
➕ Bonus:
- You can return a completely different object than the one Java just built
🧪 3. Use transient
+ Reinitialization Logic
Fields marked as transient
are skipped during serialization. You can:
- Add default values in
readObject()
- Recalculate them using other deserialized fields
transient String cache;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.cache = this.name.toUpperCase(); // Restore derived field
}
🛡 4. Validate Object with ObjectInputValidation
(less common)
This is a special hook for post-processing:
in.registerValidation(obj -> {
if (obj.age < 0) throw new InvalidObjectException("Invalid age!");
}, 0);
✅ Used for deep validation or dependency-based checks.
⚠️ 5. Constructor Does Not Run During Deserialization!
Remember:
- Java bypasses constructors during deserialization using
ReflectionFactory
- So if you rely on constructor logic (e.g., init defaults), you need to repeat it in
readObject()
🧵 TL;DR — How to Control Values on Deserialization
Method | What It Controls | When to Use |
---|---|---|
readObject() | Modify, validate, reinitialize fields | Most flexible and common |
readResolve() | Replace the whole object | For Singletons, canonical forms |
transient + reinit | Skip field + restore manually | Derived/cached/volatile data |
ObjectInputValidation | Validate after full object graph is read | Advanced validation logic |