An application I’m working on uses Hibernate exclusively to fetch a bunch of persistent objects from a database to memory. The application is to refresh this in-memory snapshot from the database every now and then, and that should be the only communication with the database.
The in-memory objects are then used for a bunch of calculations. The calculations must not modify these objects. Except some class somewhere accidentally did, and I had to spend a day hunting down the bug. Now I’m wondering what the best way to make the entire object tree immutable is.
Suppose the class hierarchy looks like this:
public class Building { // persistent entity
private String name; // hibernate-mapped property
private Set<Person> inhabitants; // hibernate-mapped collection
// getters
}
public class Person { // persistent entity
private String name; // hibernate-mapped property
// getters
}
I’ve prevented clients from accessing the database by:
- eagerly fetching all entities and collections
- marking all entities and collections with
mutable=falsein Hibernate mappings - not providing any instances of the Hibernate session, or state-changing dao methods.
Now the error I’d like to prevent is, someone accidentally going building.getInhabitants().clear();. I can think of these options:
-
Getter wrapping: Make
getInhabitantsfirst wrapinhabitantsin aCollections.unmodifiableSet()call, then return it.- Pros: Least work, least extra code
- Cons: Feels hacky
-
Wrapper classes: Rename
BuildingtoMutableBuilding,PersontoMutablePerson, and provide immutable classesBuildingandPerson. Since my application has a clear snapshot point, I can fetch the records as mutable objects (as I do now), make deeply immutable copies and present that object tree to clients.- Pros: Straight java, no Hibernate magic. I get to use my favorite keyword:
final - Cons: More code to write and maintain. Also, will Hibernate keep the mutable instances in memory?
- Pros: Straight java, no Hibernate magic. I get to use my favorite keyword:
-
Hibernate mapping magic: Use that one magic keyword to instruct Hibernate to wrap the collections it sets on my entity objects in
Collections.unmodifiableSet()or equivalent. (Note: I use an xml mapping file)- Pros: Elegant, no extra code
- Cons: Such keyword may not exist
-
Hibernate extension: Use that one Hibernate extension point to write my own object instantiator, and in there wrap the set in
Collections.unmodifiableSet()before returning it.- Pros: More elegant than hacking my getters
- Cons: Such extension point may not exist
Right now I’m leaning towards #2, mostly because I don’t know if 3 and 4 are possible.
What is the best way?
Option 1, for sure. It’s not “hacky”, and that’s exactly why you abstracted the property access into methods, in the first place 🙂 Just note that you should use “field access” with Hibernate, instead of “method”, so that you don’t risk providing an unmodifiable collection to Hibernate.
Unfortunately, Hibernate doesn’t provides a way to place unmodifiable collections, but I think you can do a @PostLoad event listener to modify all collections once the object is loaded.