Fix postLoad callback method not called

This commit is contained in:
Andrea Boriero 2022-01-10 12:03:40 +01:00 committed by Steve Ebersole
parent 8d43be4b78
commit b8114bad31
4 changed files with 241 additions and 27 deletions

View File

@ -425,6 +425,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|| entityDescriptor.getJavaTypeDescriptor().getJavaTypeClass().isInstance( proxy ) ) ) {
if ( this instanceof EntityResultInitializer && entityInstanceFromExecutionContext != null ) {
this.entityInstance = entityInstanceFromExecutionContext;
registerLoadingEntity( rowProcessingState, entityInstance );
}
else {
this.entityInstance = proxy;
@ -435,9 +436,11 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
if ( existingEntity != null ) {
this.entityInstance = existingEntity;
registerLoadingEntity( rowProcessingState, entityInstance );
}
else if ( this instanceof EntityResultInitializer && entityInstanceFromExecutionContext != null ) {
this.entityInstance = entityInstanceFromExecutionContext;
registerLoadingEntity( rowProcessingState, entityInstance );
}
else {
// look to see if another initializer from a parent load context or an earlier
@ -578,6 +581,12 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
}
}
registerLoadingEntity( rowProcessingState, instance );
return instance;
}
private void registerLoadingEntity(RowProcessingState rowProcessingState, Object instance) {
final LoadingEntityEntry loadingEntry = new LoadingEntityEntry(
this,
entityKey,
@ -588,8 +597,6 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
entityKey,
loadingEntry
);
return instance;
}
@Override
@ -625,6 +632,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
}
notifyResolutionListeners( entityInstanceForNotify );
isInitialized = true;
}

View File

@ -21,7 +21,6 @@ import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PostLoadEventListener;
import org.hibernate.event.spi.PreLoadEvent;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.results.graph.Initializer;

View File

@ -28,32 +28,26 @@ public class PostLoadTest {
*/
@Test
public void testAccessAssociatedSetInPostLoad(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
Child child = new Child();
child.setId( 1 );
Parent daddy = new Parent();
daddy.setId( 1 );
child.setDaddy( daddy );
Set<Child> children = new HashSet<>();
children.add( child );
daddy.setChildren( children );
entityManager.persist( daddy );
}
);
scope.inEntityManager(
entityManager -> {
try {
Child child = new Child();
child.setId( 1 );
Parent daddy = new Parent();
daddy.setId( 1 );
child.setDaddy( daddy );
Set<Child> children = new HashSet<>();
children.add( child );
daddy.setChildren( children );
entityManager.getTransaction().begin();
entityManager.persist( daddy );
entityManager.getTransaction().commit();
entityManager.clear();
daddy = entityManager.find( Parent.class, 1 );
assertEquals( 1, daddy.getNrOfChildren() );
}
catch (Exception e) {
if ( entityManager.getTransaction().isActive() ) {
entityManager.getTransaction().rollback();
}
throw e;
}
Parent daddy = entityManager.find( Parent.class, 1 );
assertEquals( 1, daddy.getNrOfChildren() );
}
);
}

View File

@ -0,0 +1,213 @@
/*
* 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.orm.test.jpa.compliance.callback;
import java.math.BigDecimal;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.junit.jupiter.api.Test;
import jakarta.persistence.DiscriminatorColumn;
import jakarta.persistence.DiscriminatorType;
import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.Id;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.PostLoad;
import jakarta.persistence.PostPersist;
import jakarta.persistence.PrePersist;
import jakarta.persistence.Query;
import static org.junit.jupiter.api.Assertions.fail;
@Jpa(
annotatedClasses = {
PostLoadCallbackTest.Account.class,
PostLoadCallbackTest.DebitAccount.class,
PostLoadCallbackTest.CreditAccount.class,
PostLoadCallbackTest.Person.class
}
)
public class PostLoadCallbackTest {
@Test
public void testEntityListenerPostLoadMethodIsCalled(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
CreditAccount account = new CreditAccount(
1,
"drea",
BigDecimal.valueOf( 190 ),
BigDecimal.valueOf( 10000 )
);
entityManager.persist( account );
entityManager.flush();
entityManager.refresh( account );
Query query = entityManager.createQuery( "select ca from CreditAccount ca" );
query.getResultList();
if ( !account.isPostLoadCalled() ) {
fail( "PostLoad has not been called" );
}
}
);
}
@Test
public void testPostLoadMethodIsCalled(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
Person person = new Person( 1, "Fab" );
entityManager.persist( person );
entityManager.flush();
entityManager.refresh( person );
Query query = entityManager
.createQuery( "select p from Person p" );
query.getResultList();
if ( person.isPostLoadCalled() ) {
fail( "PostLoad has not been called" );
}
}
);
}
@MappedSuperclass
public static class PersonCallback {
boolean isPrePersistCalled;
boolean isPostPersistCalled;
@PrePersist
public void prePersist() {
isPrePersistCalled = true;
}
@PostPersist
public void postPersist() {
if ( !isPrePersistCalled ) {
throw new IllegalStateException(
"The prePersist method has not been called." );
}
this.isPostPersistCalled = true;
}
public boolean isPostLoadCalled() {
return isPostPersistCalled;
}
}
@Entity(name = "Person")
public static class Person extends PersonCallback {
Person() {
}
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
@Id
private Integer id;
private String name;
}
@Entity(name = "Account")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "ACCOUNT_TYPE", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("Account")
@EntityListeners(AccountListener.class)
public static class Account extends CallbackStatus {
@Id
private Integer id;
private String owner;
private BigDecimal balance;
public Account() {
}
public Account(Integer id, String owner, BigDecimal balance) {
this.id = id;
this.owner = owner;
this.balance = balance;
}
public Integer getId() {
return id;
}
}
@Entity(name = "DebitAccount")
@DiscriminatorValue("DebitAccount")
@EntityListeners(AccountListener.class)
public static class DebitAccount extends Account {
private BigDecimal overdraftFee;
public DebitAccount(Integer id, String owner, BigDecimal balance, BigDecimal overdraftFee) {
super( id, owner, balance );
this.overdraftFee = overdraftFee;
}
}
@Entity(name = "CreditAccount")
@DiscriminatorValue("CreditAccount")
@EntityListeners(AccountListener.class)
public static class CreditAccount extends Account {
private BigDecimal creditLimit;
public CreditAccount(Integer id, String owner, BigDecimal balance, BigDecimal creditLimit) {
super( id, owner, balance );
this.creditLimit = creditLimit;
}
}
public static class AccountListener {
@PostPersist
public void postPersist(CallbackStatus callbackStatus) {
callbackStatus.setPostPersistCall();
}
@PostLoad
public void postLoad(CallbackStatus callbackStatus) {
callbackStatus.setPostLoadCalled();
}
}
public static class CallbackStatus {
private boolean postPersistCalled;
private boolean postLoadCalled;
public boolean isPostLoadCalled() {
return postLoadCalled;
}
public void setPostLoadCalled() {
postLoadCalled = true;
}
public void setPostPersistCall() {
postPersistCalled = true;
}
}
}