Entity Callbacks and Listeners l l l When
Entity Callbacks and Listeners l l l When you execute Entity. Manager methods like persist( ), merge( ), remove( ), and find( ), or when you execute EJB QL queries, a predefined set of life cycle events are triggered. For instance, the persist( ) method triggers database inserts. Merging triggers updates to the database. The remove( ) method triggers database deletes. Querying entities triggers a load from the database. 1
Entity Callbacks and Listeners l l l Sometimes it is very useful to have your entity bean class be notified as these events happen. For instance, maybe you want to create an audit log of every interaction done on each row in your database. The Java Persistence specification allows you to set up callback methods on your entity classes so that your entity instances are notified when these events occur. 2
Callback Events l A certain annotation represents each phase of an entity's life cycle: @javax. persistence. Pre. Persist @javax. persistence. Post. Load @javax. persistence. Pre. Update @javax. persistence. Post. Update @javax. persistence. Pre. Remove @javax. persistence. Post. Remove 3
Callback Events The @Pre. Persist and @Post. Persist events have to do with the insertion of an entity instance into the database. l The @Pre. Persist event occurs immediately when the Entity. Manager. persist( ) call is invoked or whenever an entity instance is scheduled to be inserted into the database (as with a cascaded merge). l The @Post. Persist event is not triggered until the actual database insert. l 4
Callbacks on Entity Classes l l You can have an entity bean instance register for a callback on any of these life cycle events by annotating a public, private, protected, or package-protected method on the bean class. This method must return void , throw no checked exceptions, and have no arguments. @Entity public class Cabin {. . . @Post. Persist void after. Insert( ) {. . . } @Post. Load void after. Loading( ) {. . . } } 5
Callbacks on Entity Classes l If you are annotation-averse, you can hook into these events by using the <pre-persist>, <post-persist>, <pre-update>, <post-update>, <pre-remove>, <post-remove>, and <postload> subelements of <entity> in the ORM mapping deployment descriptor: <entity class="com. titan. domain. Cabin"> <post-persist name="after. Insert"/> <post-load name="after. Loading"/> </entity> l These subelements have one attribute called name that takes the name of the method you want to invoke when the callback event happens. 6
Entity Listeners l l l Entity listeners are classes that can generically intercept entity callback events. They are not entity classes themselves, but they can be attached to an entity class through a binding annotation or XML. You can assign methods on an entity listener class to intercept a particular life cycle event. The method is annotated with the callback in which it is interested. public class Titan. Audit. Logger { @Post. Persist void post. Insert(Object entity) { System. out. println("Inserted entity: " + entity. get. Class(). get. Name( )); } @Post. Load void post. Load(Object entity) { System. out. println("Loaded entity: " + entity. get. Class(). get. Name( )); } } 7
Entity Listeners l The entity listener class must have a public no-arg constructor. It can be applied to an entity class by using the @javax. persistence. Entity. Listeners annotation: package javax. persistence; @Target(TYPE) @Retention(RUNTIME) public @interface Entity. Listeners { Class[] value( ); } l You can specify one or more entity listeners that intercept the callback events of an entity class: @Entity. Listeners ({Titan. Audit. Logger. class, Entity. Jmx. Notifier. class}) public class Cabin {. . . 8
Entity Listeners @Post. Persist void after. Insert( ) {. . . } @Post. Load void after. Loading( ) {. . . } } l Entity listeners can also be applied using XML: <entity class="com. titan. domain. Cabin"> <entity-listeners> <entity-listener class="com. titan. listeners. Titan. Audit. Logger"> </entity-listener> <entity-listener class="com. titan. listeners. Entity. Jmx. Notifier"> <pre-persist name="before. Insert"/> <post-load name="after. Loading"/> </entity-listeners> 9
Entity Listeners l Let's look at what would happen if we invoked the following operations: 1. 2. 3. 4. 5. 6. l l Entity. Manager em = factory. create. Entity. Manager( ); em. get. Transaction(). begin( ); Cabin cabin = new Cabin( ); em. persist(cabin); Cabin another. Cabin = em. find(Cabin. class, 5); em. get. Transaction(). commit( ); Pretend this code executes on the examples we have shown in this chapter. The Entity. Jmx. Notifier class is interested in a <pre -persist> callback. The Entity. Jmx. Notifier. before. Insert( ) method is executed when the Entity. Manager. persist( ) method is invoked at Line 5. 10
Entity Listeners l l l At Line 7, the Titan. Audit. Logger. post. Load( ), Entity. Jmx. Notifier. after. Loading( ), and Cabin. after. Loading( ) methods are invoked, in that order, as the @Post. Load event is triggered by the Entity. Manager. find( ) invocation. The Cabin. after. Loading( ) method is invoked on the same instance returned by the find( ) method. Our persistence provider has decided to delay the database insert of the newly persisted cabin until the transaction commits. In Line 9, the Titan. Audit. Logger. post. Persist( ) and Cabin. after. Insert( ) methods are called, in that order. The Cabin. after. Insert( ) method is invoked on the same entity instance that we persisted in Line 5. 11
Default Entity Listeners l l You can specify a set of default entity listeners that are applied to every entity class in the persistence unit by using the <entity-listeners> element under the top-level <entitymappings> element in the ORM mapping file. For instance, if you wanted to apply the Titan. Audit. Logger to every entity class in a particular persistence unit, you would do the following: <entity-mappings> <entity-listener class="com. titan. listeners. Titan. Audit. Logger"> <post-persist name="after. Insert"/> <post-load name="after. Loading"/> </entity-listener> <entity-listener class="com. titan. listeners. Entity. Jmx. Notifier"/> </entity-listeners> </entity-mappings> 12
Default Entity Listeners l If you want to turn off default entity listeners to a particular entity class, you can use the @javax. persistence. Exclude. Default. Listeners annotation: @Entity @Exclude. Default. Listeners public class Cabin {. . . } l There is also an XML equivalent of this annotation: <entity class="com. titan. domain. Cabin"> <exclude-default-listeners/> </entity l If either the @Exclude. Default. Listeners annotation or its XML equivalent are applied to the Cabin entity, the Titan. Audit. Logger is turned off for that entity. 13
Inheritance and Listeners l l If you have an inheritance entity hierarchy in which the base class has entity listeners applied to it, any subclass will inherit these entity listeners. If the subclass also has entity listeners applied to it, then both the base and the subclass's listeners will be attached. @Entity. Listeners(Titan. Audit. Logger. class) public class Person { @Post. Persist void another. Callback( ) {. . . } } @Entity. Listeners(Entity. Jmx. Notifier. class) public class Customer extends Person {. . . } 14
Inheritance and Listeners l In this example, the Titan. Audit. Logger entity listener and Entity. Jmx. Notifier will be attached to the Customer entity. If all of these listeners have an @Post. Persist callback, the order of callback execution will be as follows: l Titan. Audit. Logger's @Post. Persist method Entity. Jmx. Notifier's @Post. Persist method Person's @Post. Persist another. Callback( ) method l l l Entity listeners applied to a base class happen before any listeners attached to a subclass. Callback methods defined directly in an entity class happen last. You can turn off inherited entity listeners by using 15 @javax. persistence. Exclude. Superclass. Listeners :
Inheritance and Listeners @Entity. Listeners(Titan. Audit. Logger. class) public class Person { } @Entity. Listeners(Entity. Jmx. Notifier. class) @Exclude. Superclass. Listeners public class Customer extends Person {. . . } l l In this example, only the Entity. Jmx. Notifier listener would be executed for Customer entity instances. @Exclude. Superclass. Listeners has an XML equivalent in the <exclude-superclass-listeners/> element. 16
- Slides: 16