- Provide a database trigger to try and insert the timestamps automatically.
- Manually set them (or have each persistent service set them) before performing a
persist()
operation with an EntityManager. - Use aspects to dynamically insert the timestamp.
- Provide an EntityListener which automatically sets the creation/modification timestamp at persist time .
Obviously the first solution is very database specific and is not really tied to the JPA code. The second solution is likely to be error prone and easily missed. The final solution is the best way to handle his. Daniel Pfeifer provides an excellent walkthrough of this technique in his blog here. I have a few comments on this. First off, the concept of an entity listener, does not follow the normal "implement this interface" convention. An entity listener is any POJO class which contains one or more methods in the format:
public void someMethod( Object obj )
It should be noted that there are
javax.persistence
annotations for each of the JPA lifecycle states. In the case of create timestamps, annotating a method with @PrePersist
will allow it to be used to provide the creation timestamp. For the modify timestamp, annotating a method with @PreUpdate
will call this method on persisting an entity which was previously persisted. The entity listener can be registered either in the orm.xml file (as described by Daniel Pfeifer) or one the Entity class itself using the annotation @EntityListeners( class ... )
. Personally I prefer this technique as it allows me to programatically tie a class with its behavior (such as storing timestamps on create/update) without having an external configuration. Using an external configuration in several modules, and unit tests quickly becomes muttled in that you forget to update the file under test etc. It also increases the developer's awareness of this association, and to be candid, it is unlikely that I really want to swap out the persistence timestamp handling at package time with a different solution. Since the annotation is applied to an abstract @MappedSuperClass
annotated class, any implementing classes will automatically inherit this behavior. I might change my stance on this approach in the future, but at least for this this seems to be the right way to approach this.