diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc index 9ccdcd1287..325010be2b 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc @@ -929,14 +929,6 @@ include::{docTestsDir}/MapKeyTypeTest.java[tags=collections-map-custom-key-type- ---- ==== -The associated `TimestampEpochType` looks as follows: - ----- -include::{docTestsDir}/type/TimestampEpochType.java[tags=collections-map-custom-key-type-mapping-example,indent=0] ----- - -The `TimestampEpochType` allows us to map a Unix timestamp since epoch to a `java.util.Date`. -But, without the `@MapKeyType` Hibernate annotation, it would not be possible to customize the `Map` key type. [[collections-map-key-class]] ===== Maps having an interface type as the key diff --git a/documentation/src/main/asciidoc/userguide/chapters/events/Events.adoc b/documentation/src/main/asciidoc/userguide/chapters/events/Events.adoc index e75efa87ea..71e18d0308 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/events/Events.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/events/Events.adoc @@ -81,7 +81,12 @@ Here is an example of a custom load event listener: ==== [source, JAVA, indent=0] ---- -include::{sourcedir}/ListenerTest.java[tags=events-interceptors-load-listener-example] +include::{sourcedir}/ListenerTest.java[tags=events-interceptors-load-listener-example-part1] +---- + +[source, JAVA, indent=0] +---- +include::{sourcedir}/ListenerTest.java[tags=events-interceptors-load-listener-example-part2] ---- ==== diff --git a/documentation/src/test/java/org/hibernate/userguide/collections/MapKeyTypeTest.java b/documentation/src/test/java/org/hibernate/userguide/collections/MapKeyTypeTest.java index 5c5a80a819..64b7442e7b 100644 --- a/documentation/src/test/java/org/hibernate/userguide/collections/MapKeyTypeTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/collections/MapKeyTypeTest.java @@ -140,8 +140,10 @@ public class MapKeyTypeTest extends BaseEntityManagerFunctionalTestCase { joinColumns = @JoinColumn(name = "person_id") ) @MapKeyJdbcTypeCode(Types.BIGINT) + //end::collections-map-custom-key-type-mapping-example[] // todo (6.0) : figure out why `@MapKeyTemporal` did not work. imo it should // @MapKeyTemporal(TemporalType.TIMESTAMP) + //tag::collections-map-custom-key-type-mapping-example[] @MapKeyJavaType(JdbcTimestampJavaType.class) @MapKeyColumn(name = "call_timestamp_epoch") @Column(name = "phone_number") diff --git a/documentation/src/test/java/org/hibernate/userguide/events/ListenerTest.java b/documentation/src/test/java/org/hibernate/userguide/events/ListenerTest.java new file mode 100644 index 0000000000..34681a7e89 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/events/ListenerTest.java @@ -0,0 +1,179 @@ +/* + * 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 . + */ +package org.hibernate.userguide.events; + +import java.io.Serializable; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.PostLoad; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; +import jakarta.persistence.Transient; + +import org.hibernate.HibernateException; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.event.service.spi.EventListenerRegistry; +import org.hibernate.event.spi.EventType; +import org.hibernate.event.spi.LoadEvent; +import org.hibernate.event.spi.LoadEventListener; +import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertTrue; + +/** + * @author Vlad Mihalcea + */ +public class ListenerTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Person.class, + Customer.class + }; + } + + @Test(expected = SecurityException.class) + public void testLoadListener() { + Serializable customerId = 1L; + + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::events-interceptors-load-listener-example-part1[] + EntityManagerFactory entityManagerFactory = entityManagerFactory(); + SessionFactoryImplementor sessionFactory = entityManagerFactory.unwrap( SessionFactoryImplementor.class ); + sessionFactory + .getServiceRegistry() + .getService( EventListenerRegistry.class ) + .prependListeners( EventType.LOAD, new SecuredLoadEntityListener() ); + + Customer customer = entityManager.find( Customer.class, customerId ); + //end::events-interceptors-load-listener-example-part1[] + } ); + } + + @Test + public void testJPACallback() { + Long personId = 1L; + + doInJPA( this::entityManagerFactory, entityManager -> { + Person person = new Person(); + person.id = personId; + person.name = "John Doe"; + person.dateOfBirth = Timestamp.valueOf(LocalDateTime.of( 2000, 1, 1, 0, 0, 0 )); + entityManager.persist( person ); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + Person person = entityManager.find( Person.class, personId ); + assertTrue(person.age > 0); + } ); + } + + @Entity(name = "Customer") + public static class Customer { + + @Id + @GeneratedValue + private Long id; + + private String name; + + public Customer() { + } + + public Customer(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + //tag::events-jpa-callbacks-example[] + @Entity(name = "Person") + @EntityListeners( LastUpdateListener.class ) + public static class Person { + + @Id + private Long id; + + private String name; + + private Date dateOfBirth; + + @Transient + private long age; + + private Date lastUpdate; + + public void setLastUpdate(Date lastUpdate) { + this.lastUpdate = lastUpdate; + } + + /** + * Set the transient property at load time based on a calculation. + * Note that a native Hibernate formula mapping is better for this purpose. + */ + @PostLoad + public void calculateAge() { + age = ChronoUnit.YEARS.between( LocalDateTime.ofInstant( + Instant.ofEpochMilli( dateOfBirth.getTime()), ZoneOffset.UTC), + LocalDateTime.now() + ); + } + } + + public static class LastUpdateListener { + + @PreUpdate + @PrePersist + public void setLastUpdate( Person p ) { + p.setLastUpdate( new Date() ); + } + } + //end::events-jpa-callbacks-example[] + + //tag::events-interceptors-load-listener-example-part2[] + public static class SecuredLoadEntityListener implements LoadEventListener { + // this is the single method defined by the LoadEventListener interface + public void onLoad(LoadEvent event, LoadType loadType) + throws HibernateException { + if ( !Principal.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) { + throw new SecurityException( "Unauthorized access" ); + } + } + } + //end::events-interceptors-load-listener-example-part2[] + + public static class Principal { + public static boolean isAuthorized(String clazz, Object id) { + return false; + } + } + +} diff --git a/documentation/src/test_legacy/org/hibernate/userguide/spatial/SpatialTest.java b/documentation/src/test/java/org/hibernate/userguide/spatial/SpatialTest.java similarity index 92% rename from documentation/src/test_legacy/org/hibernate/userguide/spatial/SpatialTest.java rename to documentation/src/test/java/org/hibernate/userguide/spatial/SpatialTest.java index b10942d37d..cd32d893b2 100644 --- a/documentation/src/test_legacy/org/hibernate/userguide/spatial/SpatialTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/spatial/SpatialTest.java @@ -9,9 +9,8 @@ package org.hibernate.userguide.spatial; import jakarta.persistence.Entity; import jakarta.persistence.Id; -import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; -import org.hibernate.spatial.dialect.postgis.PostgisDialect; -import org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; import org.hibernate.testing.RequiresDialect; import org.junit.Test; @@ -31,10 +30,10 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; /** * @author Vlad Mihalcea */ -@RequiresDialect(PostgisPG95Dialect.class) +@RequiresDialect(PostgreSQLDialect.class) public class SpatialTest extends BaseEntityManagerFunctionalTestCase { - private GeometryFactory geometryFactory = new GeometryFactory(); + private final GeometryFactory geometryFactory = new GeometryFactory(); @Override protected Class[] getAnnotatedClasses() {