Archive for May, 2008

A Custom reuseable LoadableDetachableModel for Spring/Hibernate

the 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:

  1. Use the object e.g.

    setModel(new PersistentObjectModel(foo));

  2. 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


Hibernate: could not read column value from result set?

I got this Error today after changing the primary key of my model objects from int to Serializable (as I wanted all of my objects, even the ones with a String primary key to use the same API, which was limited to int). But when I started the app I got the Error and the following Exception:

org.hibernate.type.SerializationException: could not deserialize
at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:217)
at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:240)
at org.hibernate.type.SerializableType.fromBytes(SerializableType.java:82)
at org.hibernate.type.SerializableType.get(SerializableType.java:39)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:163)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:154)
…..

I even got this one as cause:

Caused by: java.io.EOFException
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2279)
at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:2748)
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:780)
at java.io.ObjectInputStream.(ObjectInputStream.java:280)
….

EOF? wtf? Don’t get too confused with that EOF, the solution was simply to add the type of the id in the mapping file.

Before:

<id name=”id”>
<generator class=”native”>
</id>

After:

<id name=”id” type=”integer”> <!– or long or string of whatever your hibernate type is –>
<generator class=”native”>
</id>


Introducing iSport.eu

iSport.eu is a simple but hopefully useful website for people like me who spend several hours a week to get the latest football (American readers: feel free to replace the word ‘football’ with ’soccer’) news from the major European leagues. iSport.eu is kind of an RSS reader, that adds some nice features (well, at least I like them):

  • no need to explain your less tech-savvy friends what the hell RSS is and why it is useful (RSS is only used for content retrieval, not for publishing)
  • auto-tagging of entries
  • grouping of entries into different categories (i.e. teams) – get only the news for your favorite teams.

While this tool currently is focused on football news, it could be used for everything that comes with a news feed.

Depending on the feedback, future enhancements could include:

  • Display only news from your favorite news portal
  • Create your personal set of categories and sources (not into football? create your personal hockey news site!)
  • Ratings and comments
  • Tag clouds – every web-2.0-ish site has to have those ;)
  • Mark entries as “read”
  • More languages (currently English, German, Italian, Spanish and French are supported)

iSport.eu is built on Java, Wicket, Spring, Hibernate, Derby, Jetty, Commons-Digester and about 10 days of manpower.