Hibernate Tips: How to activate an entity listener for all entities


Hibernate Tips is a series of posts in which I describe a quick and easy solution for common Hibernate questions. If you have a question for a future Hibernate Tip, please post a comment below.

Question:

We use an EntityListener to write an audit log. Is there an easy way to attach the EntityListener to all entities?

Solution:

In most cases, you register an EntityListener for an entity using the @EntityListeners annotations on an entity class. That works fine if you use different listeners for each entity class.

But it’s inconvenient if you want to assign the same listener to all entity classes. In that situation, it’s easier to use an XML configuration to register the EntityListener to all entities by default.

Configure a default listener

The easiest way to do that is to create a file called orm.xml and place it in the META-INF folder of your jar file. All JPA implementations will read and process that file automatically.

The following code snippet configures the MyEntityListener class as the default EntityListener for all entity classes in the persistence unit.

<entity-mappings>
	<persistence-unit-metadata>
		<persistence-unit-defaults>
			<entity-listeners>
				<entity-listener class="org.thoughts.on.java.model.MyEntityListener"/>
			</entity-listeners>
		</persistence-unit-defaults>
	</persistence-unit-metadata>
</entity-mappings>

A simple EntityListener

The MyEntityListener class is very simple. It only has 1 method that expects an object as a parameter and is annotated with @PreUpdate, @PrePersist, and @PreRemove. Hibernate calls this method and provides then entity object as a parameter whenever it persists, updates or removes an entity for which this listener is registered.

public class MyEntityListener {
    Logger log = Logger.getLogger(MyEntityListener.class); 

    @PreUpdate
    @PrePersist
    @PreRemove
    public void handleLifecycleEvent(Object entity) {
        log.info(entity);
    }
}

Use the EntityListener

Let’s give it a try and run this simple test case that persists and updates a Book entity.

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

Book b = new Book();
b.setTitle("Hibernate Tips");
em.persist(b);

em.getTransaction().commit();
em.close();

em = emf.createEntityManager();
em.getTransaction().begin();

b = em.find(Book.class, b.getId());
b.setTitle("Hibernate Tips - More than 70 solutions to common Hibernate problems");

em.getTransaction().commit();
em.close();

As you can see in the log file, Hibernate calls the MyEntityListener before the SQL INSERT and the SQL UPDATE statements.

20:03:33,124 INFO  [org.thoughts.on.java.model.MyEntityListener] - Book title: Hibernate Tips
20:03:33,127 DEBUG [org.hibernate.SQL] - select nextval ('hibernate_sequence')
20:03:33,160 DEBUG [org.hibernate.SQL] - insert into Book (publishingDate, title, version, id) values (?, ?, ?, ?)
20:03:33,188 DEBUG [org.hibernate.SQL] - select book0_.id as id1_0_0_, book0_.publishingDate as publishi2_0_0_, book0_.title as title3_0_0_, book0_.version as version4_0_0_ from Book book0_ where book0_.id=?
20:03:33,204 INFO  [org.thoughts.on.java.model.MyEntityListener] - Book title: Hibernate Tips - More than 70 solutions to common Hibernate problems
20:03:33,205 DEBUG [org.hibernate.SQL] - update Book set publishingDate=?, title=?, version=? where id=? and version=?

Learn more:

If you liked this article, you might also be interested in:

 

Hibernate Tips Book







Get more recipes like this one in my new book Hibernate Tips: More than 70 solutions to common Hibernate problems.

It gives you more than 70 ready-to-use recipes for topics like basic and advanced mappings, logging, Java 8 support, caching, and statically and dynamically defined queries.

Get it now!


Related Articles

Responses

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.