HHH-11076 - Lazy collections ignore filters when allowLoadOutsideTransaction is true

Roll back fix since it got rejected due to some corner cases that are now added to ProxyPreservingFiltersOutsideInitialSessionTest
This commit is contained in:
Vlad Mihalcea 2016-09-28 17:18:18 +03:00
parent 23326608f7
commit 8201c69103
2 changed files with 183 additions and 5 deletions

View File

@ -10,7 +10,6 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@ -18,7 +17,6 @@ import java.util.ListIterator;
import java.util.Map;
import org.hibernate.AssertionFailure;
import org.hibernate.Filter;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LazyInitializationException;
@ -75,7 +73,6 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
private String sessionFactoryUuid;
private boolean allowLoadOutsideTransaction;
private Map<String, Filter> enabledFilters;
/**
* Not called by Hibernate, but used by non-JDK serialization,
@ -86,7 +83,6 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
protected AbstractPersistentCollection(SharedSessionContractImplementor session) {
this.session = session;
enabledFilters = new HashMap<>( session.getLoadQueryInfluencers().getEnabledFilters() );
}
@Override
@ -279,7 +275,6 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
final SharedSessionContractImplementor session = (SharedSessionContractImplementor) sf.openSession();
session.getPersistenceContext().setDefaultReadOnly( true );
session.setFlushMode( FlushMode.MANUAL );
session.getLoadQueryInfluencers().getEnabledFilters().putAll( enabledFilters );
return session;
}

View File

@ -8,12 +8,16 @@ package org.hibernate.jpa.test.hibernateFilters;
import java.util.Map;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.FailureExpected;
import org.junit.Test;
import org.jboss.logging.Logger;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
@ -22,6 +26,9 @@ import static org.junit.Assert.assertEquals;
*/
public class ProxyPreservingFiltersOutsideInitialSessionTest
extends BaseEntityManagerFunctionalTestCase {
private static final Logger log = Logger.getLogger( ProxyPreservingFiltersOutsideInitialSessionTest.class );
@Override
public Class[] getAnnotatedClasses() {
return new Class[] {
@ -38,6 +45,7 @@ public class ProxyPreservingFiltersOutsideInitialSessionTest
}
@Test
@FailureExpected( jiraKey = "HHH-11076", message = "Fix rejected, we need another approach to fix this issue!" )
public void testPreserveFilters() {
doInJPA( this::entityManagerFactory, entityManager -> {
@ -71,4 +79,179 @@ public class ProxyPreservingFiltersOutsideInitialSessionTest
assertEquals(1, group.getAccounts().size());
}
@Test
public void testChangeFilterBeforeInitializeInSameSession() {
doInJPA(
this::entityManagerFactory, entityManager -> {
AccountGroup accountGroup = new AccountGroup();
accountGroup.setId( 1L );
entityManager.persist( accountGroup );
Account account = new Account();
account.setName( "A1" );
account.setRegionCode( "Europe" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
account = new Account();
account.setName( "A2" );
account.setRegionCode( "Europe" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
account = new Account();
account.setName( "A3" );
account.setRegionCode( "US" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
}
);
doInJPA( this::entityManagerFactory, entityManager -> {
entityManager.unwrap( Session.class ).enableFilter( "byRegion" ).setParameter( "region", "US" );
AccountGroup accountGroup = entityManager.find( AccountGroup.class, 1L );
// Change the filter
entityManager.unwrap( Session.class ).enableFilter( "byRegion" ).setParameter( "region", "Europe" );
Hibernate.initialize( accountGroup.getAccounts() );
// will contain accounts with regionCode "Europe"
assertEquals( 2, accountGroup.getAccounts().size() );
return accountGroup;
} );
}
@Test
@FailureExpected( jiraKey = "HHH-11076", message = "Fix rejected, we need another approach to fix this issue!" )
public void testChangeFilterBeforeInitializeInTempSession() {
doInJPA(
this::entityManagerFactory, entityManager -> {
AccountGroup accountGroup = new AccountGroup();
accountGroup.setId( 1L );
entityManager.persist( accountGroup );
Account account = new Account();
account.setName( "A1" );
account.setRegionCode( "Europe" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
account = new Account();
account.setName( "A2" );
account.setRegionCode( "Europe" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
account = new Account();
account.setName( "A3" );
account.setRegionCode( "US" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
}
);
AccountGroup group = doInJPA( this::entityManagerFactory, entityManager -> {
entityManager.unwrap( Session.class ).enableFilter( "byRegion" ).setParameter( "region", "US" );
AccountGroup accountGroup = entityManager.find( AccountGroup.class, 1L );
// Change the filter.
entityManager.unwrap( Session.class ).enableFilter( "byRegion" ).setParameter( "region", "Europe" );
return accountGroup;
} );
log.info( "Initialize accounts collection" );
// What should group.getAccounts() contain? Should it be accounts with regionCode "Europe"
// because that was the most recent filter used in the session?
Hibernate.initialize( group.getAccounts() );
// The following will fail because the collection will only contain accounts with regionCode "US"
assertEquals(2, group.getAccounts().size());
}
@Test
public void testMergeNoFilterThenInitializeTempSession() {
doInJPA(
this::entityManagerFactory, entityManager -> {
AccountGroup accountGroup = new AccountGroup();
accountGroup.setId( 1L );
entityManager.persist( accountGroup );
Account account = new Account();
account.setName( "A1" );
account.setRegionCode( "Europe" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
account = new Account();
account.setName( "A2" );
account.setRegionCode( "Europe" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
account = new Account();
account.setName( "A3" );
account.setRegionCode( "US" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
}
);
final AccountGroup group = doInJPA( this::entityManagerFactory, entityManager -> {
entityManager.unwrap( Session.class ).enableFilter( "byRegion" ).setParameter( "region", "US" );
return entityManager.find( AccountGroup.class, 1L );
} );
final AccountGroup mergedGroup = doInJPA( this::entityManagerFactory, entityManager -> {
return entityManager.merge( group );
} );
// group.getAccounts() will be unfiltered because merge cleared AbstractCollectionPersister#enabledFilters
Hibernate.initialize( mergedGroup.getAccounts() );
assertEquals(3, mergedGroup.getAccounts().size());
}
@Test
public void testSaveOrUpdateNoFilterThenInitializeTempSession() {
doInJPA(
this::entityManagerFactory, entityManager -> {
AccountGroup accountGroup = new AccountGroup();
accountGroup.setId( 1L );
entityManager.persist( accountGroup );
Account account = new Account();
account.setName( "A1" );
account.setRegionCode( "Europe" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
account = new Account();
account.setName( "A2" );
account.setRegionCode( "Europe" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
account = new Account();
account.setName( "A3" );
account.setRegionCode( "US" );
entityManager.persist( account );
accountGroup.getAccounts().add( account );
}
);
final AccountGroup group = doInJPA( this::entityManagerFactory, entityManager -> {
entityManager.unwrap( Session.class ).enableFilter( "byRegion" ).setParameter( "region", "US" );
return entityManager.find( AccountGroup.class, 1L );
} );
final AccountGroup savedGroup = doInJPA( this::entityManagerFactory, entityManager -> {
// saveOrUpdate adds the PersistenceCollection to the session "as is"
return (AccountGroup) entityManager.unwrap( Session.class ).merge( group );
} );
Hibernate.initialize( savedGroup.getAccounts() );
// group.getAccounts() should not be filtered.
// the following fails because AbstractCollectionPersister#enabledFilters is still intact.
assertEquals(3, savedGroup.getAccounts().size());
}
}