Reputation: 27455
I'm developing a web application based on Hibernate, Spring and Wicket.
Until now I implemented the business objects and the persistence layer. The transaction is managed by a transaction interceptor of the Spring framework. So each method of the DAO classes is encapsulated in a transaction. Implementing this together with unit test was straight forward.
Now I come to the web application part where I also use Spring for dependency injection. Together with the @SpringBean annotations of the Wicket framework I inject the DAOs in the Wicket components. But as I'm pretty new to Wicket I'm a little bit stuck when using the right model for my business objects when passing them do the Wicket components.
I tried the LoadableDetachableModel but run into some issues. I got one page to created a new or edit an existing business object depending on the input parameters of the page. If there is a id in the parameters then the corresponding business object should be loaded from the database. When there are no parameters then a new business object should be created. The part were a object should be edited runs quite well but when a new object should be created, and I fill out the web form and press save, I get a NullPointerException. After some debugging I found out that LoadableDetachableModel could not return an instance of the business object as the overridden load() method could not load the object form the database as it was not saved there yet and therefore had no id.
So now I'm wondering how to solve this problem. Is the LoadableDetachableModel the right choice? Is it advisable to separate the form into two interdependent forms and each form uses a different model. So only the edit page/form uses the LoadableDetachableModel?
Upvotes: 4
Views: 5670
Reputation: 21384
Wicket 6.x Reference Documentation > 11 Wicket models and forms > 11.6 Detachable models describes it as follows:
Now as example of a possible use of
LoadableDetachableModel
, we will build a model designed to work with entities managed via JPA. To understand the following code a basic knowledge of JPA is required even if we won't go into the detail of this standard.The following model is provided for example purposes only and is not intended to be used in production environment. Important aspects such as transaction management are not taken into account and you should rework the code before considering to use it.
public class JpaLoadableModel<T> extends LoadableDetachableModel<T> { private EntityManagerFactory entityManagerFactory; private Class<T> entityClass; private Serializable identifier; private List<Object> constructorParams; public JpaLoadableModel(EntityManagerFactory entityManagerFactory, T entity) { super(); PersistenceUnitUtil util = entityManagerFactory.getPersistenceUnitUtil(); this.entityManagerFactory = entityManagerFactory; this.entityClass = (Class<T>) entity.getClass(); this.identifier = (Serializable) util.getIdentifier(entity); setObject(entity); } @Override protected T load() { T entity = null; if(identifier != null) { EntityManager entityManager = entityManagerFactory.createEntityManager(); entity = entityManager.find(entityClass, identifier); } return entity; } @Override protected void onDetach() { super.onDetach(); T entity = getObject(); PersistenceUnitUtil persistenceUtil = entityManagerFactory.getPersistenceUnitUtil(); if(entity == null) return; identifier = (Serializable) persistenceUtil.getIdentifier(entity); } }
The constructor of the model takes as input two parameters: an implementation of the JPA interface
javax.persistence.EntityManagerFactory
to manage JPA entities and the entity that must be handled by this model. Inside its constructor the model saves the class of the entity and its id (which could be null if the entity has not been persisted yet). These two informations are required to retrieve the entity at a later time and are used by the load method.
onDetach
is responsible for updating the entity id before detachment occurs. The id can change the first time an entity is persisted (JPA generates a new id and assigns it to the entity). Please note that this model is not responsible for saving any changes occurred to the entity object before it is detached. If we don't want to loose these changes we must explicitly persist the entity before the detaching phase occurs.Since the model of this example holds a reference to the
EntityManagerFactory
, the implementation in use must beSerializable
.
Upvotes: 0
Reputation: 41127
There's a good explanation of this and some related issues by Igor Vaynberg at the Wicket In Action blog.
The last bit on that page deals with this issue, basically by not using a LoadableDetachableModel
but implementing the AbstractEntityModel
, which allows more complete control.
Upvotes: 2