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:
mutable=false
in Hibernate mappingsNow the error I'd like to prevent is, someone accidentally going building.getInhabitants().clear();
. I can think of these options:
Getter wrapping: Make getInhabitants
first wrap inhabitants
in a Collections.unmodifiableSet()
call, then return it.
Wrapper classes: Rename Building
to MutableBuilding
, Person
to MutablePerson
, and provide immutable classes Building
and Person
. 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.
final
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)
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.
Right now I'm leaning towards #2, mostly because I don't know if 3 and 4 are possible.
What is the best way?
You can tell Hibernate that a specific entity is immutable by using @Entity(mutable=false) or @Immutable annotations. Note that both are Hibernate extensions to JPA standard.
There's one obstacle on the way of creating immutable entity classes with an ORM framework like Hibernate. Hibernate uses reflection to instantiate entities, it, therefore requires a default, no argument constructor. This means class fields can never be final.
In hibernate, 'mutable' is default to 'true' in class and its related collection, it mean the class or collection are allow to add, update and delete. On the other hand, if the mutable is changed to false, it has different meaning in class and its related collection.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With