A Custom reuseable LoadableDetachableModel for Spring/Hibernate
May 21st, 2008 by Michael Sparer | Published in Hibernate, Spring, Wicketthe annoyance
org.hibernate.LazyInitializationException - could not initialize proxy - the owning Session was closed
org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed
the problem
Generally, detached objects in Hibernate are a bad thing when it comes to reusing objects between web-requests. Detached objects are objects that have been persistent but are not attached to a Hibernate session. They’re easily produced but can be a mess if it comes to Lazy-Loading or updating them. Just consider the following case
Foo foo = _myDAO.getFoo(); // attached object
add(new Link("fooLink", new Model(foo)) {
protected void onClick() {
Foo foo = (Foo) getModelObject(); // now it's detached as this is called in the next request
Bar bar = foo.getBar(); // possible lazy-loading exception if bar gets loaded lazily
}
}
the solution
First be sure to use the OpenSessionInViewFilter sothat a new hibernate session is opened when the request gets attached and closed when it gets detached.
Then the solution of course is a to use a LoadableDetachableModel that gets a fresh instance from the persistence-layer on each request. Could look like that:
IModel fooModel = new LoadableDetachableModel() {
protected Object load() {
return _myDAO.getFoo();
}
}
add(new Link("fooLink", fooModel) {
protected void onClick() {
Foo foo = (Foo) getModelObject(); // attached as LDM has loaded a fresh instance
Bar bar = foo.getBar(); // no lazy loading exception as still attached
}
}
the improvement
LoadableDetachableModels are a nice thing but it’s quite a lot of work to inject your DAO (or service) and then create a new LDM for each of your objects in each and every one of your panels. so we came up with a more generic version of the LoadableDetachableModel. First, let your model-objects implement an Interface, say IPersistentObject with the single method
Serializable getId();
As your object are likely to have a primary key named id it’ll be no problem anyway. Then create the following class:
public class PersistentObjectModel extends LoadableDetachableModel {
private static final long serialVersionUID = 1L;
private final Class _clazz;
private final Serializable _id;
@SpringBean(name = "myDao")
private IMyDao _myDao;
@SuppressWarnings("unchecked")
public PersistentObjectModel(final T object) {
super(object);
// object may be a hibernate proxy, so get the actual class
if (object instanceof HibernateProxy) {
_clazz = (Class) ((HibernateProxy) object).getHibernateLazyInitializer()
.getImplementation().getClass();
} else {
_clazz = (Class) object.getClass();
}
_id = object.getId();
// inject the bean
InjectorHolder.getInjector().inject(this);
}
public PersistentObjectModel(final Class clazz, final Serializable id) {
clazz = clazz;
_id = id;
// inject the bean
InjectorHolder.getInjector().inject(this);
}
@Override
protected T load() {
// the DAO then simply passes the params to hibernate (or spring's hibernatetemplate
return _myDao.getById(_clazz, _id);
}
@SuppressWarnings("unchecked")
@Override
public T getObject() {
return (T) super.getObject();
}
}
This makes working with hibernate objects really easy. There are two options:
- Use the object e.g.
setModel(new PersistentObjectModel(foo));
- Use only class and id.
This might happen e.g. if you pass your id using PageParameters (but better encrypt it
)
setModel(new PersistentObjectModel(Foo.class, 1));
Hope that saved you some time writing boilerplate code
have fun