HHH-11186 - Add examples for all Hibernate annotations
Document default entity listeners, @ExcludeDefaultListeners, and @ExcludeSuperclassListeners
This commit is contained in:
parent
43f74be58e
commit
9c53bfdd73
|
@ -182,14 +182,14 @@ See the <<chapters/domain/basic_types.adoc#basic-enums-Enumerated, `@Enumerated`
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/ExcludeDefaultListeners.html[`@ExcludeDefaultListeners`] annotation is used to specify that the current annotated entity skips the invocation of any default listener.
|
||||
|
||||
//TODO: Add example
|
||||
See the <<chapters/events/Events.adoc#events-exclude-default-listener, Exclude default entity listeners>> section for more info.
|
||||
|
||||
[[annotations-jpa-excludesuperclasslisteners]]
|
||||
==== `@ExcludeSuperclassListeners`
|
||||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/ExcludeSuperclassListeners.html[`@ExcludeSuperclassListeners`] annotation is used to specify that the current annotated entity skips the invocation of listeners declared by its superclass.
|
||||
|
||||
//TODO: Add example
|
||||
See the <<chapters/events/Events.adoc#events-exclude-default-listener, Exclude default entity listeners>> section for more info.
|
||||
|
||||
[[annotations-jpa-fieldresult]]
|
||||
==== `@FieldResult`
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[[events]]
|
||||
== Interceptors and events
|
||||
:sourcedir: ../../../../../test/java/org/hibernate/userguide/events
|
||||
:extrasdir: extras
|
||||
|
||||
It is useful for the application to react to certain events that occur inside Hibernate.
|
||||
This allows for the implementation of generic functionality and the extension of Hibernate functionality.
|
||||
|
@ -177,3 +178,105 @@ See the `javax.persistence.ExcludeSuperclassListener`s annotation.
|
|||
If a callback type is annotated on both an entity and one or more of its superclasses without method overriding, both would be called, the most general superclass first.
|
||||
An entity class is also allowed to override a callback method defined in a superclass in which case the super callback would not get invoked; the overriding method would get invoked provided it is annotated.
|
||||
|
||||
[[events-default-listener]]
|
||||
=== Default entity listeners
|
||||
|
||||
The JPA specification allows you to define a default entity listener which is going to be applied for every entity in that particular system.
|
||||
Default entity listeners can only be defined in XML mapping files.
|
||||
|
||||
[[events-default-listener-mapping-example]]
|
||||
.Default event listner mapping
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/DefaultEntityListener.java[tags=events-default-listener-mapping-example]
|
||||
----
|
||||
|
||||
[source, XML, indent=0]
|
||||
----
|
||||
include::{sourcedir}/DefaultEntityListener-orm.xml[tags=events-default-listener-mapping-example]
|
||||
----
|
||||
====
|
||||
|
||||
Considering that all entities extend the `BaseEntity` class:
|
||||
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/BaseEntity.java[tags=events-default-listener-mapping-example]
|
||||
----
|
||||
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/DefaultEntityListenerTest.java[tags=events-default-listener-mapping-example]
|
||||
----
|
||||
|
||||
When persisting a `Person` or `Book` entity, the `createdOn` is going to be set by the `onPersist` method of the `DefaultEntityListener`.
|
||||
|
||||
[[events-default-listener-persist-example]]
|
||||
.Default event listner persist event
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/DefaultEntityListenerTest.java[tags=events-default-listener-persist-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/events-default-listener-persist-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
When updating a `Person` or `Book` entity, the `updatedOn` is going to be set by the `onUpdate` method of the `DefaultEntityListener`.
|
||||
|
||||
[[events-default-listener-update-example]]
|
||||
.Default event listner update event
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/DefaultEntityListenerTest.java[tags=events-default-listener-update-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/events-default-listener-update-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
[[events-exclude-default-listener]]
|
||||
==== Exclude default entity listeners
|
||||
|
||||
If you already registered a default entity listener, but you don't want to apply it to a particular entity,
|
||||
you can use the
|
||||
http://docs.oracle.com/javaee/7/api/javax/persistence/ExcludeDefaultListeners.html[`@ExcludeDefaultListeners`] and
|
||||
http://docs.oracle.com/javaee/7/api/javax/persistence/ExcludeSuperclassListeners.html[`@ExcludeSuperclassListeners`] JPA annotations.
|
||||
|
||||
`@ExcludeDefaultListeners` instructs the current class to ignore the default entity listeners for the current entity
|
||||
while `@ExcludeSuperclassListeners` is used to ignore the default entity listeners propagated to the `BaseEntity` super-class.
|
||||
|
||||
[[events-exclude-default-listener-mapping-example]]
|
||||
.Exclude default event listner mapping
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/DefaultEntityListenerTest.java[tags=events-exclude-default-listener-mapping-example]
|
||||
----
|
||||
====
|
||||
|
||||
When persisting a `Publisher` entity,
|
||||
the `createdOn` is not going to be set by the `onPersist` method of the `DefaultEntityListener`
|
||||
because the `Publisher` entity was marked with the `@ExcludeDefaultListeners` and `@ExcludeSuperclassListeners` annotations.
|
||||
|
||||
[[events-exclude-default-listener-persist-example]]
|
||||
.Excluding default event listner events
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/DefaultEntityListenerTest.java[tags=events-exclude-default-listener-persist-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/events-exclude-default-listener-persist-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
insert
|
||||
into
|
||||
Person
|
||||
(createdOn, updatedOn, name, id)
|
||||
values
|
||||
(?, ?, ?, ?)
|
||||
|
||||
-- binding parameter [1] as [TIMESTAMP] - [2017-06-08 19:23:48.224]
|
||||
-- binding parameter [2] as [TIMESTAMP] - [null]
|
||||
-- binding parameter [3] as [VARCHAR] - [Vlad Mihalcea]
|
||||
-- binding parameter [4] as [BIGINT] - [1]
|
||||
|
||||
insert
|
||||
into
|
||||
Book
|
||||
(createdOn, updatedOn, author_id, title, id)
|
||||
values
|
||||
(?, ?, ?, ?, ?)
|
||||
|
||||
-- binding parameter [1] as [TIMESTAMP] - [2017-06-08 19:23:48.246]
|
||||
-- binding parameter [2] as [TIMESTAMP] - [null]
|
||||
-- binding parameter [3] as [BIGINT] - [1]
|
||||
-- binding parameter [4] as [VARCHAR] - [High-Performance Java Persistence]
|
||||
-- binding parameter [5] as [BIGINT] - [1]
|
|
@ -0,0 +1,29 @@
|
|||
update
|
||||
Person
|
||||
set
|
||||
createdOn=?,
|
||||
updatedOn=?,
|
||||
name=?
|
||||
where
|
||||
id=?
|
||||
|
||||
-- binding parameter [1] as [TIMESTAMP] - [2017-06-08 19:23:48.224]
|
||||
-- binding parameter [2] as [TIMESTAMP] - [2017-06-08 19:23:48.316]
|
||||
-- binding parameter [3] as [VARCHAR] - [Vlad-Alexandru Mihalcea]
|
||||
-- binding parameter [4] as [BIGINT] - [1]
|
||||
|
||||
update
|
||||
Book
|
||||
set
|
||||
createdOn=?,
|
||||
updatedOn=?,
|
||||
author_id=?,
|
||||
title=?
|
||||
where
|
||||
id=?
|
||||
|
||||
-- binding parameter [1] as [TIMESTAMP] - [2017-06-08 19:23:48.246]
|
||||
-- binding parameter [2] as [TIMESTAMP] - [2017-06-08 19:23:48.317]
|
||||
-- binding parameter [3] as [BIGINT] - [1]
|
||||
-- binding parameter [4] as [VARCHAR] - [High-Performance Java Persistence 2nd Edition]
|
||||
-- binding parameter [5] as [BIGINT] - [1]
|
|
@ -0,0 +1,11 @@
|
|||
insert
|
||||
into
|
||||
Publisher
|
||||
(createdOn, updatedOn, name, id)
|
||||
values
|
||||
(?, ?, ?, ?)
|
||||
|
||||
-- binding parameter [1] as [TIMESTAMP] - [null]
|
||||
-- binding parameter [2] as [TIMESTAMP] - [null]
|
||||
-- binding parameter [3] as [VARCHAR] - [Amazon]
|
||||
-- binding parameter [4] as [BIGINT] - [1]
|
|
@ -0,0 +1,34 @@
|
|||
package org.hibernate.userguide.events;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
//tag::events-default-listener-mapping-example[]
|
||||
@MappedSuperclass
|
||||
public abstract class BaseEntity {
|
||||
|
||||
private Timestamp createdOn;
|
||||
|
||||
private Timestamp updatedOn;
|
||||
|
||||
public Timestamp getCreatedOn() {
|
||||
return createdOn;
|
||||
}
|
||||
|
||||
void setCreatedOn(Timestamp createdOn) {
|
||||
this.createdOn = createdOn;
|
||||
}
|
||||
|
||||
public Timestamp getUpdatedOn() {
|
||||
return updatedOn;
|
||||
}
|
||||
|
||||
void setUpdatedOn(Timestamp updatedOn) {
|
||||
this.updatedOn = updatedOn;
|
||||
}
|
||||
}
|
||||
//end::events-default-listener-mapping-example[]
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<!--tag::events-default-listener-mapping-example[]-->
|
||||
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
|
||||
http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd"
|
||||
version="2.1">
|
||||
<persistence-unit-metadata>
|
||||
<persistence-unit-defaults>
|
||||
<entity-listeners>
|
||||
<entity-listener
|
||||
class="org.hibernate.userguide.events.DefaultEntityListener">
|
||||
<pre-persist method-name="onPersist"/>
|
||||
<pre-update method-name="onUpdate"/>
|
||||
</entity-listener>
|
||||
</entity-listeners>
|
||||
</persistence-unit-defaults>
|
||||
</persistence-unit-metadata>
|
||||
</entity-mappings>
|
||||
<!--end::events-default-listener-mapping-example[]-->
|
|
@ -0,0 +1,33 @@
|
|||
package org.hibernate.userguide.events;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
//tag::events-default-listener-mapping-example[]
|
||||
public class DefaultEntityListener {
|
||||
|
||||
public void onPersist(Object entity) {
|
||||
if ( entity instanceof BaseEntity ) {
|
||||
BaseEntity baseEntity = (BaseEntity) entity;
|
||||
baseEntity.setCreatedOn( now() );
|
||||
}
|
||||
}
|
||||
|
||||
public void onUpdate(Object entity) {
|
||||
if ( entity instanceof BaseEntity ) {
|
||||
BaseEntity baseEntity = (BaseEntity) entity;
|
||||
baseEntity.setUpdatedOn( now() );
|
||||
}
|
||||
}
|
||||
|
||||
private Timestamp now() {
|
||||
return Timestamp.from(
|
||||
LocalDateTime.now().toInstant( ZoneOffset.UTC )
|
||||
);
|
||||
}
|
||||
}
|
||||
//end::events-default-listener-mapping-example[]
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.userguide.events;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ExcludeDefaultListeners;
|
||||
import javax.persistence.ExcludeSuperclassListeners;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class DefaultEntityListenerTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class,
|
||||
Book.class,
|
||||
Publisher.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getMappings() {
|
||||
return new String[] { "org/hibernate/userguide/events/DefaultEntityListener-orm.xml" };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::events-default-listener-persist-example[]
|
||||
Person author = new Person();
|
||||
author.setId( 1L );
|
||||
author.setName( "Vlad Mihalcea" );
|
||||
|
||||
entityManager.persist( author );
|
||||
|
||||
Book book = new Book();
|
||||
book.setId( 1L );
|
||||
book.setTitle( "High-Performance Java Persistence" );
|
||||
book.setAuthor( author );
|
||||
|
||||
entityManager.persist( book );
|
||||
//end::events-default-listener-persist-example[]
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::events-default-listener-update-example[]
|
||||
Person author = entityManager.find( Person.class, 1L );
|
||||
author.setName( "Vlad-Alexandru Mihalcea" );
|
||||
|
||||
Book book = entityManager.find( Book.class, 1L );
|
||||
book.setTitle( "High-Performance Java Persistence 2nd Edition" );
|
||||
//end::events-default-listener-update-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExclude() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::events-exclude-default-listener-persist-example[]
|
||||
Publisher publisher = new Publisher();
|
||||
publisher.setId( 1L );
|
||||
publisher.setName( "Amazon" );
|
||||
|
||||
entityManager.persist( publisher );
|
||||
//end::events-exclude-default-listener-persist-example[]
|
||||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Publisher publisher = entityManager.find( Publisher.class, 1L );
|
||||
assertNull(publisher.getCreatedOn());
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::events-default-listener-mapping-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person extends BaseEntity {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
//Getters and setters omitted for brevity
|
||||
//end::events-default-listener-mapping-example[]
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
//tag::events-default-listener-mapping-example[]
|
||||
}
|
||||
|
||||
@Entity(name = "Book")
|
||||
public static class Book extends BaseEntity {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
@ManyToOne
|
||||
private Person author;
|
||||
|
||||
//Getters and setters omitted for brevity
|
||||
//end::events-default-listener-mapping-example[]
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Person getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(Person author) {
|
||||
this.author = author;
|
||||
}
|
||||
//tag::events-default-listener-mapping-example[]
|
||||
}
|
||||
//end::events-default-listener-mapping-example[]
|
||||
|
||||
//tag::events-exclude-default-listener-mapping-example[]
|
||||
@Entity(name = "Publisher")
|
||||
@ExcludeDefaultListeners
|
||||
@ExcludeSuperclassListeners
|
||||
public static class Publisher extends BaseEntity {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
//Getters and setters omitted for brevity
|
||||
//end::events-exclude-default-listener-mapping-example[]
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
//tag::events-exclude-default-listener-mapping-example[]
|
||||
}
|
||||
//end::events-exclude-default-listener-mapping-example[]
|
||||
}
|
Loading…
Reference in New Issue