Merge remote-tracking branch 'upstream5/master' into wip/6.0_merged_8

This commit is contained in:
Andrea Boriero 2019-10-17 09:18:56 +01:00
commit 39afae5462
21 changed files with 3593 additions and 98 deletions

View File

@ -62,10 +62,10 @@ public class MetadataSources implements Serializable {
private XmlMappingBinderAccess xmlMappingBinderAccess; private XmlMappingBinderAccess xmlMappingBinderAccess;
private List<Binding> xmlBindings = new ArrayList<>(); private List<Binding> xmlBindings;
private LinkedHashSet<Class<?>> annotatedClasses = new LinkedHashSet<>(); private LinkedHashSet<Class<?>> annotatedClasses;
private LinkedHashSet<String> annotatedClassNames = new LinkedHashSet<>(); private LinkedHashSet<String> annotatedClassNames;
private LinkedHashSet<String> annotatedPackages = new LinkedHashSet<>(); private LinkedHashSet<String> annotatedPackages;
private Map<String,Class<?>> extraQueryImports; private Map<String,Class<?>> extraQueryImports;
@ -81,14 +81,15 @@ public class MetadataSources implements Serializable {
public MetadataSources(ServiceRegistry serviceRegistry) { public MetadataSources(ServiceRegistry serviceRegistry) {
// service registry really should be either BootstrapServiceRegistry or StandardServiceRegistry type... // service registry really should be either BootstrapServiceRegistry or StandardServiceRegistry type...
if ( ! isExpectedServiceRegistryType( serviceRegistry ) ) { if ( ! isExpectedServiceRegistryType( serviceRegistry ) ) {
LOG.debugf( if ( LOG.isDebugEnabled() ) {
"Unexpected ServiceRegistry type [%s] encountered during building of MetadataSources; may cause " + LOG.debugf(
"problems later attempting to construct MetadataBuilder", "Unexpected ServiceRegistry type [%s] encountered during building of MetadataSources; may cause " +
serviceRegistry.getClass().getName() "problems later attempting to construct MetadataBuilder",
); serviceRegistry.getClass().getName()
);
}
} }
this.serviceRegistry = serviceRegistry; this.serviceRegistry = serviceRegistry;
this.xmlMappingBinderAccess = new XmlMappingBinderAccess( serviceRegistry );
} }
protected static boolean isExpectedServiceRegistryType(ServiceRegistry serviceRegistry) { protected static boolean isExpectedServiceRegistryType(ServiceRegistry serviceRegistry) {
@ -97,23 +98,26 @@ public class MetadataSources implements Serializable {
} }
public XmlMappingBinderAccess getXmlMappingBinderAccess() { public XmlMappingBinderAccess getXmlMappingBinderAccess() {
if ( xmlMappingBinderAccess == null ) {
xmlMappingBinderAccess = new XmlMappingBinderAccess( serviceRegistry );
}
return xmlMappingBinderAccess; return xmlMappingBinderAccess;
} }
public List<Binding> getXmlBindings() { public List<Binding> getXmlBindings() {
return xmlBindings; return xmlBindings == null ? Collections.emptyList() : xmlBindings;
} }
public Collection<String> getAnnotatedPackages() { public Collection<String> getAnnotatedPackages() {
return annotatedPackages; return annotatedPackages == null ? Collections.emptySet() : annotatedPackages;
} }
public Collection<Class<?>> getAnnotatedClasses() { public Collection<Class<?>> getAnnotatedClasses() {
return annotatedClasses; return annotatedClasses == null ? Collections.emptySet() : annotatedClasses;
} }
public Collection<String> getAnnotatedClassNames() { public Collection<String> getAnnotatedClassNames() {
return annotatedClassNames; return annotatedClassNames == null ? Collections.emptySet() : annotatedClassNames;
} }
public Map<String,Class<?>> getExtraQueryImports() { public Map<String,Class<?>> getExtraQueryImports() {
@ -201,6 +205,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining) * @return this (for method chaining)
*/ */
public MetadataSources addAnnotatedClass(Class annotatedClass) { public MetadataSources addAnnotatedClass(Class annotatedClass) {
if ( annotatedClasses == null ) {
annotatedClasses = new LinkedHashSet<>();
}
annotatedClasses.add( annotatedClass ); annotatedClasses.add( annotatedClass );
return this; return this;
} }
@ -225,6 +232,9 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining) * @return this (for method chaining)
*/ */
public MetadataSources addAnnotatedClassName(String annotatedClassName) { public MetadataSources addAnnotatedClassName(String annotatedClassName) {
if ( annotatedClassNames == null ) {
annotatedClassNames = new LinkedHashSet<>();
}
annotatedClassNames.add( annotatedClassName ); annotatedClassNames.add( annotatedClassName );
return this; return this;
} }
@ -265,11 +275,17 @@ public class MetadataSources implements Serializable {
packageName = packageName.substring( 0, packageName.length() - 1 ); packageName = packageName.substring( 0, packageName.length() - 1 );
} }
annotatedPackages.add( packageName ); addPackageInternal( packageName );
return this; return this;
} }
private void addPackageInternal(String packageName) {
if ( annotatedPackages == null ) {
annotatedPackages = new LinkedHashSet<>();
}
annotatedPackages.add( packageName );
}
/** /**
* Read package-level metadata. * Read package-level metadata.
* *
@ -278,7 +294,7 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining) * @return this (for method chaining)
*/ */
public MetadataSources addPackage(Package packageRef) { public MetadataSources addPackage(Package packageRef) {
annotatedPackages.add( packageRef.getName() ); addPackageInternal( packageRef.getName() );
return this; return this;
} }
@ -297,7 +313,9 @@ public class MetadataSources implements Serializable {
if ( entityClass == null ) { if ( entityClass == null ) {
throw new IllegalArgumentException( "The specified class cannot be null" ); throw new IllegalArgumentException( "The specified class cannot be null" );
} }
LOG.debugf( "adding resource mappings from class convention : %s", entityClass.getName() ); if ( LOG.isDebugEnabled() ) {
LOG.debugf( "adding resource mappings from class convention : %s", entityClass.getName() );
}
final String mappingResourceName = entityClass.getName().replace( '.', '/' ) + ".hbm.xml"; final String mappingResourceName = entityClass.getName().replace( '.', '/' ) + ".hbm.xml";
addResource( mappingResourceName ); addResource( mappingResourceName );
return this; return this;
@ -311,7 +329,7 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addResource(String name) { public MetadataSources addResource(String name) {
xmlBindings.add( getXmlMappingBinderAccess().bind( name ) ); getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( name ) );
return this; return this;
} }
@ -337,7 +355,7 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addFile(File file) { public MetadataSources addFile(File file) {
xmlBindings.add( getXmlMappingBinderAccess().bind( file ) ); getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( file ) );
return this; return this;
} }
@ -357,7 +375,7 @@ public class MetadataSources implements Serializable {
} }
private void addCacheableFile(Origin origin, File file) { private void addCacheableFile(Origin origin, File file) {
xmlBindings.add( new CacheableFileXmlSource( origin, file, false ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) ); getXmlBindingsForWrite().add( new CacheableFileXmlSource( origin, file, false ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
} }
/** /**
@ -394,7 +412,7 @@ public class MetadataSources implements Serializable {
*/ */
public MetadataSources addCacheableFileStrictly(File file) throws SerializationException, FileNotFoundException { public MetadataSources addCacheableFileStrictly(File file) throws SerializationException, FileNotFoundException {
final Origin origin = new Origin( SourceType.FILE, file.getAbsolutePath() ); final Origin origin = new Origin( SourceType.FILE, file.getAbsolutePath() );
xmlBindings.add( new CacheableFileXmlSource( origin, file, true ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) ); getXmlBindingsForWrite().add( new CacheableFileXmlSource( origin, file, true ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
return this; return this;
} }
@ -406,7 +424,7 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addInputStream(InputStreamAccess xmlInputStreamAccess) { public MetadataSources addInputStream(InputStreamAccess xmlInputStreamAccess) {
xmlBindings.add( getXmlMappingBinderAccess().bind( xmlInputStreamAccess ) ); getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( xmlInputStreamAccess ) );
return this; return this;
} }
@ -418,7 +436,7 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addInputStream(InputStream xmlInputStream) { public MetadataSources addInputStream(InputStream xmlInputStream) {
xmlBindings.add( getXmlMappingBinderAccess().bind( xmlInputStream ) ); getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( xmlInputStream ) );
return this; return this;
} }
@ -430,7 +448,7 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addURL(URL url) { public MetadataSources addURL(URL url) {
xmlBindings.add( getXmlMappingBinderAccess().bind( url ) ); getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( url ) );
return this; return this;
} }
@ -446,7 +464,7 @@ public class MetadataSources implements Serializable {
@Deprecated @Deprecated
public MetadataSources addDocument(Document document) { public MetadataSources addDocument(Document document) {
final Origin origin = new Origin( SourceType.DOM, Origin.UNKNOWN_FILE_PATH ); final Origin origin = new Origin( SourceType.DOM, Origin.UNKNOWN_FILE_PATH );
xmlBindings.add( new JaxpSourceXmlSource( origin, new DOMSource( document ) ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) ); getXmlBindingsForWrite().add( new JaxpSourceXmlSource( origin, new DOMSource( document ) ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
return this; return this;
} }
@ -460,17 +478,22 @@ public class MetadataSources implements Serializable {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addJar(File jar) { public MetadataSources addJar(File jar) {
LOG.debugf( "Seeking mapping documents in jar file : %s", jar.getName() ); if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Seeking mapping documents in jar file : %s", jar.getName() );
}
final Origin origin = new Origin( SourceType.JAR, jar.getAbsolutePath() ); final Origin origin = new Origin( SourceType.JAR, jar.getAbsolutePath() );
try { try {
JarFile jarFile = new JarFile( jar ); JarFile jarFile = new JarFile( jar );
final boolean TRACE = LOG.isTraceEnabled();
try { try {
Enumeration jarEntries = jarFile.entries(); Enumeration jarEntries = jarFile.entries();
while ( jarEntries.hasMoreElements() ) { while ( jarEntries.hasMoreElements() ) {
final ZipEntry zipEntry = (ZipEntry) jarEntries.nextElement(); final ZipEntry zipEntry = (ZipEntry) jarEntries.nextElement();
if ( zipEntry.getName().endsWith( ".hbm.xml" ) ) { if ( zipEntry.getName().endsWith( ".hbm.xml" ) ) {
LOG.tracef( "found mapping document : %s", zipEntry.getName() ); if ( TRACE ) {
xmlBindings.add( LOG.tracef( "found mapping document : %s", zipEntry.getName() );
}
getXmlBindingsForWrite().add(
new JarFileEntryXmlSource( origin, jarFile, zipEntry ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) new JarFileEntryXmlSource( origin, jarFile, zipEntry ).doBind( getXmlMappingBinderAccess().getMappingBinder() )
); );
} }
@ -490,6 +513,13 @@ public class MetadataSources implements Serializable {
return this; return this;
} }
private <Binding> List getXmlBindingsForWrite() {
if ( xmlBindings == null ) {
xmlBindings = new ArrayList<>();
}
return xmlBindings;
}
/** /**
* Read all mapping documents from a directory tree. * Read all mapping documents from a directory tree.
* <p/> * <p/>

View File

@ -437,7 +437,7 @@ public class MapBinder extends CollectionBinder {
referencedEntityColumns = referencedProperty.getColumnIterator(); referencedEntityColumns = referencedProperty.getColumnIterator();
} }
fromAndWhere = getFromAndWhereFormula( fromAndWhere = getFromAndWhereFormula(
associatedClass.getTable().getName(), associatedClass.getTable().getQualifiedTableName().toString(),
element.getColumnIterator(), element.getColumnIterator(),
referencedEntityColumns referencedEntityColumns
); );

View File

@ -332,6 +332,7 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
|| "getTransaction".equals( methodName ) || "getTransaction".equals( methodName )
|| "isTransactionInProgress".equals( methodName ) || "isTransactionInProgress".equals( methodName )
|| "setFlushMode".equals( methodName ) || "setFlushMode".equals( methodName )
|| "setHibernateFlushMode".equals( methodName )
|| "getFactory".equals( methodName ) || "getFactory".equals( methodName )
|| "getSessionFactory".equals( methodName ) || "getSessionFactory".equals( methodName )
|| "getTenantIdentifier".equals( methodName ) ) { || "getTenantIdentifier".equals( methodName ) ) {

View File

@ -260,15 +260,6 @@ public interface SharedSessionContractImplementor
Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable) Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable)
throws HibernateException; throws HibernateException;
default Object internalLoad(
String entityName,
Serializable id,
boolean eager,
boolean nullable,
Boolean unwrapProxy) throws HibernateException {
return internalLoad( entityName, id, eager, nullable );
}
/** /**
* Load an instance immediately. This method is only called when lazily initializing a proxy. * Load an instance immediately. This method is only called when lazily initializing a proxy.
* Do not return the proxy. * Do not return the proxy.

View File

@ -299,15 +299,18 @@ public class DefaultLoadEventListener implements LoadEventListener {
return createProxy( event, persister, keyToLoad, persistenceContext ); return createProxy( event, persister, keyToLoad, persistenceContext );
} }
} }
if ( !entityMetamodel.hasSubclasses() ) {
if ( keyToLoad.isBatchLoadable() ) {
// Add a batch-fetch entry into the queue for this entity
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( keyToLoad );
}
if ( keyToLoad.isBatchLoadable() ) { // This is the crux of HHH-11147
// Add a batch-fetch entry into the queue for this entity // create the (uninitialized) entity instance - has only id set
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( keyToLoad ); return persister.getBytecodeEnhancementMetadata().createEnhancedProxy( keyToLoad, true, session );
} }
// If we get here, then the entity class has subclasses and there is no HibernateProxy factory.
// This is the crux of HHH-11147 // The entity will get loaded below.
// create the (uninitialized) entity instance - has only id set
return persister.getBytecodeEnhancementMetadata().createEnhancedProxy( keyToLoad, true, session );
} }
else { else {
if ( persister.hasProxy() ) { if ( persister.hasProxy() ) {

View File

@ -975,18 +975,7 @@ public final class SessionImpl
String entityName, String entityName,
Serializable id, Serializable id,
boolean eager, boolean eager,
boolean nullable) throws HibernateException { boolean nullable) {
return internalLoad( entityName, id, eager, nullable, null );
}
@Override
public final Object internalLoad(
String entityName,
Serializable id,
boolean eager,
boolean nullable,
Boolean unwrapProxy) {
final EffectiveEntityGraph effectiveEntityGraph = getLoadQueryInfluencers().getEffectiveEntityGraph(); final EffectiveEntityGraph effectiveEntityGraph = getLoadQueryInfluencers().getEffectiveEntityGraph();
final GraphSemantic semantic = effectiveEntityGraph.getSemantic(); final GraphSemantic semantic = effectiveEntityGraph.getSemantic();
final RootGraphImplementor<?> graph = effectiveEntityGraph.getGraph(); final RootGraphImplementor<?> graph = effectiveEntityGraph.getGraph();

View File

@ -298,23 +298,48 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
final BytecodeEnhancementMetadata bytecodeEnhancementMetadata = entityMetamodel.getBytecodeEnhancementMetadata(); final BytecodeEnhancementMetadata bytecodeEnhancementMetadata = entityMetamodel.getBytecodeEnhancementMetadata();
if ( allowBytecodeProxy && bytecodeEnhancementMetadata.isEnhancedForLazyLoading() ) { if ( allowBytecodeProxy && bytecodeEnhancementMetadata.isEnhancedForLazyLoading() ) {
// we cannot use bytecode proxy for entities with subclasses // if the entity defines a HibernateProxy factory, see if there is an
if ( !entityMetamodel.hasSubclasses() ) { // existing proxy associated with the PC - and if so, use it
if ( persister.getEntityMetamodel().getTuplizer().getProxyFactory() != null ) {
final PersistenceContext persistenceContext = getPersistenceContext();
final Object proxy = persistenceContext.getProxy( entityKey );
if ( proxy != null ) {
if ( LOG.isTraceEnabled() ) {
LOG.trace( "Entity proxy found in session cache" );
}
if ( LOG.isDebugEnabled() && ( (HibernateProxy) proxy ).getHibernateLazyInitializer().isUnwrap() ) {
LOG.debug( "Ignoring NO_PROXY to honor laziness" );
}
return persistenceContext.narrowProxy( proxy, persister, entityKey, null );
}
// specialized handling for entities with subclasses with a HibernateProxy factory
if ( entityMetamodel.hasSubclasses() ) {
// entities with subclasses that define a ProxyFactory can create
// a HibernateProxy.
LOG.debugf( "Creating a HibernateProxy for to-one association with subclasses to honor laziness" );
return createProxy( entityKey );
}
return bytecodeEnhancementMetadata.createEnhancedProxy( entityKey, false, this ); return bytecodeEnhancementMetadata.createEnhancedProxy( entityKey, false, this );
} }
} else if ( !entityMetamodel.hasSubclasses() ) {
return bytecodeEnhancementMetadata.createEnhancedProxy( entityKey, false, this );
// we could not use bytecode proxy, check to see if we can use HibernateProxy
if ( persister.hasProxy() ) {
final PersistenceContext persistenceContext = getPersistenceContext();
final Object existingProxy = persistenceContext.getProxy( entityKey );
if ( existingProxy != null ) {
return persistenceContext.narrowProxy( existingProxy, persister, entityKey, null );
} }
else { // If we get here, then the entity class has subclasses and there is no HibernateProxy factory.
final Object proxy = persister.createProxy( id, this ); // The entity will get loaded below.
persistenceContext.addProxy( entityKey, proxy ); }
return proxy; else {
if ( persister.hasProxy() ) {
final PersistenceContext persistenceContext = getPersistenceContext();
final Object existingProxy = persistenceContext.getProxy( entityKey );
if ( existingProxy != null ) {
return persistenceContext.narrowProxy( existingProxy, persister, entityKey, null );
}
else {
return createProxy( entityKey );
}
} }
} }
} }
@ -323,6 +348,12 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
return get( entityName, id ); return get( entityName, id );
} }
private Object createProxy(EntityKey entityKey) {
final Object proxy = entityKey.getPersister().createProxy( entityKey.getIdentifier(), this );
getPersistenceContext().addProxy( entityKey, proxy );
return proxy;
}
@Override @Override
public boolean isAutoCloseSessionEnabled() { public boolean isAutoCloseSessionEnabled() {
return getFactory().getSessionFactoryOptions().isAutoCloseSessionEnabled(); return getFactory().getSessionFactoryOptions().isAutoCloseSessionEnabled();

View File

@ -1733,16 +1733,21 @@ public abstract class Loader {
// see if the entity defines reference caching, and if so use the cached reference (if one). // see if the entity defines reference caching, and if so use the cached reference (if one).
if ( session.getCacheMode().isGetEnabled() && persister.canUseReferenceCacheEntries() ) { if ( session.getCacheMode().isGetEnabled() && persister.canUseReferenceCacheEntries() ) {
final EntityDataAccess cache = persister.getCacheAccessStrategy(); final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey( if ( cache != null ) {
key.getIdentifier(), final Object ck = cache.generateCacheKey(
persister, key.getIdentifier(),
session.getFactory(), persister,
session.getTenantIdentifier() session.getFactory(),
session.getTenantIdentifier()
);
final Object cachedEntry = CacheHelper.fromSharedCache( session, ck, cache );
if ( cachedEntry != null ) {
CacheEntry entry = (CacheEntry) persister.getCacheEntryStructure().destructure(
cachedEntry,
factory
); );
final Object cachedEntry = CacheHelper.fromSharedCache( session, ck, cache ); return ( (ReferenceCacheEntryImpl) entry ).getReference();
if ( cachedEntry != null ) { }
CacheEntry entry = (CacheEntry) persister.getCacheEntryStructure().destructure( cachedEntry, factory );
return ( (ReferenceCacheEntryImpl) entry ).getReference();
} }
} }

View File

@ -655,8 +655,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
getAssociatedEntityName(), getAssociatedEntityName(),
id, id,
eager, eager,
isNullable(), isNullable()
unwrapProxy
); );
if ( proxyOrEntity instanceof HibernateProxy ) { if ( proxyOrEntity instanceof HibernateProxy ) {

View File

@ -0,0 +1,306 @@
/*
* 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.test.bytecode.enhancement.lazy;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.Hibernate;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
import org.hibernate.annotations.LazyToOne;
import org.hibernate.annotations.LazyToOneOption;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.query.Query;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Andrea Boriero
*/
@RunWith(BytecodeEnhancerRunner.class)
public class QueryScrollingWithInheritanceTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
super.configureStandardServiceRegistryBuilder( ssrb );
}
@Override
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
super.configureSessionFactoryBuilder( sfb );
sfb.applyStatisticsSupport( true );
sfb.applySecondLevelCacheSupport( false );
sfb.applyQueryCacheSupport( false );
}
@Override
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( EmployeeParent.class );
sources.addAnnotatedClass( Employee.class );
sources.addAnnotatedClass( OtherEntity.class );
}
@Test
public void testScrollableWithStatelessSession() {
final StatisticsImplementor stats = sessionFactory().getStatistics();
stats.clear();
ScrollableResults scrollableResults = null;
final StatelessSession statelessSession = sessionFactory().openStatelessSession();
try {
statelessSession.beginTransaction();
Query<Employee> query = statelessSession.createQuery(
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
Employee.class
);
if ( getDialect() instanceof DB2Dialect ) {
/*
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
set type of TYPE_FORWARD_ONLY and db2 does not support it.
*/
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
}
else {
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
}
while ( scrollableResults.next() ) {
final Employee employee = (Employee) scrollableResults.get( 0 );
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
if ( "ENG1".equals( employee.getDept() ) ) {
assertThat( employee.getOtherEntities().size(), is( 2 ) );
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( false ) );
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( false ) );
}
}
else {
assertThat( employee.getOtherEntities().size(), is( 0 ) );
}
}
statelessSession.getTransaction().commit();
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
}
finally {
if ( scrollableResults != null ) {
scrollableResults.close();
}
if ( statelessSession.getTransaction().isActive() ) {
statelessSession.getTransaction().rollback();
}
statelessSession.close();
}
}
@Test
public void testScrollableWithSession() {
final StatisticsImplementor stats = sessionFactory().getStatistics();
stats.clear();
ScrollableResults scrollableResults = null;
final Session session = sessionFactory().openSession();
try {
session.beginTransaction();
Query<Employee> query = session.createQuery(
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
Employee.class
);
if ( getDialect() instanceof DB2Dialect ) {
/*
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
set type of TYPE_FORWARD_ONLY and db2 does not support it.
*/
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
}
else {
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
}
while ( scrollableResults.next() ) {
final Employee employee = (Employee) scrollableResults.get( 0 );
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
if ( "ENG1".equals( employee.getDept() ) ) {
assertThat( employee.getOtherEntities().size(), is( 2 ) );
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( false ) );
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( false ) );
}
}
else {
assertThat( employee.getOtherEntities().size(), is( 0 ) );
}
}
session.getTransaction().commit();
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
}
finally {
if ( scrollableResults != null ) {
scrollableResults.close();
}
if ( session.getTransaction().isActive() ) {
session.getTransaction().rollback();
}
session.close();
}
}
@Before
public void prepareTestData() {
inTransaction(
session -> {
Employee e1 = new Employee( "ENG1" );
Employee e2 = new Employee( "ENG2" );
OtherEntity other1 = new OtherEntity( "test1" );
OtherEntity other2 = new OtherEntity( "test2" );
e1.getOtherEntities().add( other1 );
e1.getOtherEntities().add( other2 );
e1.getParentOtherEntities().add( other1 );
e1.getParentOtherEntities().add( other2 );
other1.employee = e1;
other2.employee = e1;
other1.employeeParent = e1;
other2.employeeParent = e2;
session.persist( other1 );
session.persist( other2 );
session.persist( e1 );
session.persist( e2 );
}
);
}
@After
public void cleanUpTestData() {
inTransaction(
session -> {
session.createQuery( "delete from OtherEntity" ).executeUpdate();
session.createQuery( "delete from Employee" ).executeUpdate();
session.createQuery( "delete from EmployeeParent" ).executeUpdate();
}
);
}
@Entity(name = "EmployeeParent")
@Table(name = "EmployeeParent")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public static abstract class EmployeeParent {
@Id
private String dept;
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employeeParent", fetch = FetchType.LAZY)
protected Set<OtherEntity> parentOtherEntities = new HashSet<>();
public Set<OtherEntity> getParentOtherEntities() {
if ( parentOtherEntities == null ) {
parentOtherEntities = new LinkedHashSet();
}
return parentOtherEntities;
}
public void setOtherEntities(Set<OtherEntity> pParentOtherEntites) {
parentOtherEntities = pParentOtherEntites;
}
public String getDept() {
return dept;
}
protected void setDept(String dept) {
this.dept = dept;
}
}
@Entity(name = "Employee")
@Table(name = "Employee")
public static class Employee extends EmployeeParent {
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employee", fetch = FetchType.LAZY)
protected Set<OtherEntity> otherEntities = new HashSet<>();
public Employee(String dept) {
this();
setDept( dept );
}
protected Employee() {
// this form used by Hibernate
}
public Set<OtherEntity> getOtherEntities() {
if ( otherEntities == null ) {
otherEntities = new LinkedHashSet();
}
return otherEntities;
}
public void setOtherEntities(Set<OtherEntity> pOtherEntites) {
otherEntities = pOtherEntites;
}
}
@Entity(name = "OtherEntity")
@Table(name = "OtherEntity")
public static class OtherEntity {
@Id
private String id;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
@JoinColumn(name = "Employee_Id")
protected Employee employee = null;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
@JoinColumn(name = "EmployeeParent_Id")
protected EmployeeParent employeeParent = null;
protected OtherEntity() {
// this form used by Hibernate
}
public OtherEntity(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
}

View File

@ -0,0 +1,476 @@
/*
* 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.test.bytecode.enhancement.lazy.proxy;
import java.io.Serializable;
import java.util.Map;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.EntityMode;
import org.hibernate.EntityNameResolver;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.annotations.LazyToOne;
import org.hibernate.annotations.LazyToOneOption;
import org.hibernate.annotations.Tuplizer;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.ProxyFactory;
import org.hibernate.stat.Statistics;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.tuple.entity.PojoEntityTuplizer;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-13640" )
@RunWith(BytecodeEnhancerRunner.class)
public class LazyToOnesNoProxyFactoryWithSubclassesStatefulTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
super.configureStandardServiceRegistryBuilder( ssrb );
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
}
@Override
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
super.configureSessionFactoryBuilder( sfb );
sfb.applyStatisticsSupport( true );
sfb.applySecondLevelCacheSupport( false );
sfb.applyQueryCacheSupport( false );
}
@Override
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( Animal.class );
sources.addAnnotatedClass( Primate.class );
sources.addAnnotatedClass( Human.class );
sources.addAnnotatedClass( OtherEntity.class );
}
@Test
public void testNewEnhancedProxyAssociation() {
inTransaction(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.human = human;
session.persist( human );
session.persist( otherEntity );
}
);
inSession(
session -> {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.animal ) );
assertEquals( 1, stats.getPrepareStatementCount() );
}
);
}
@Test
public void testExistingInitializedAssociationLeafSubclass() {
inTransaction(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.animal = human;
otherEntity.primate = human;
otherEntity.human = human;
session.persist( human );
session.persist( otherEntity );
}
);
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
inSession(
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
assertTrue( Hibernate.isInitialized( otherEntity.animal ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.animal ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
assertTrue( Hibernate.isInitialized( otherEntity.primate ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.primate ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertTrue( Hibernate.isInitialized( otherEntity.human ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
assertSame( otherEntity.human, otherEntity.animal );
assertSame( otherEntity.human, otherEntity.primate );
assertEquals( 2, stats.getPrepareStatementCount() );
}
);
assertEquals( 2, stats.getPrepareStatementCount() );
}
@Test
public void testExistingEnhancedProxyAssociationLeafSubclassOnly() {
inTransaction(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.human = human;
otherEntity.otherHuman = human;
session.persist( human );
session.persist( otherEntity );
}
);
inSession(
session -> {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertNull( otherEntity.animal );
assertNull( otherEntity.primate );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "otherHuman" ) );
assertFalse( Hibernate.isInitialized( otherEntity.otherHuman ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.otherHuman ) );
assertSame( otherEntity.human, otherEntity.otherHuman );
assertEquals( 1, stats.getPrepareStatementCount() );
}
);
}
@After
public void cleanUpTestData() {
inTransaction(
session -> {
session.createQuery( "delete from OtherEntity" ).executeUpdate();
session.createQuery( "delete from Human" ).executeUpdate();
session.createQuery( "delete from Primate" ).executeUpdate();
session.createQuery( "delete from Animal" ).executeUpdate();
}
);
}
@Entity(name = "Animal")
@Table(name = "Animal")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Tuplizer(impl=NoProxyFactoryPojoEntityTuplizer.class)
public static abstract class Animal {
@Id
private String name;
private int age;
public String getName() {
return name;
}
protected void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Entity(name = "Primate")
@Table(name = "Primate")
public static class Primate extends Animal {
public Primate(String name) {
this();
setName( name );
}
protected Primate() {
// this form used by Hibernate
}
}
@Entity(name = "Human")
@Table(name = "Human")
public static class Human extends Primate {
private String sex;
public Human(String name) {
this();
setName( name );
}
protected Human() {
// this form used by Hibernate
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
@Entity(name = "OtherEntity")
@Table(name = "OtherEntity")
public static class OtherEntity {
@Id
private String id;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Animal animal = null;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Primate primate = null;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Human human = null;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Human otherHuman = null;
protected OtherEntity() {
// this form used by Hibernate
}
public OtherEntity(String id) {
this.id = id;
}
public String getId() {
return id;
}
public Human getHuman() {
return human;
}
public void setHuman(Human human) {
this.human = human;
}
}
public static class NoProxyFactoryPojoEntityTuplizer implements EntityTuplizer {
private final PojoEntityTuplizer pojoEntityTuplizer;
public NoProxyFactoryPojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
pojoEntityTuplizer = new PojoEntityTuplizer( entityMetamodel, mappedEntity );
}
@Override
public EntityMode getEntityMode() {
return pojoEntityTuplizer.getEntityMode();
}
@Override
public Object instantiate(Serializable id) throws HibernateException {
return pojoEntityTuplizer.instantiate( id );
}
@Override
public Object instantiate(Serializable id, SharedSessionContractImplementor session) {
return pojoEntityTuplizer.instantiate( id, session );
}
@Override
public Serializable getIdentifier(Object entity) throws HibernateException {
return pojoEntityTuplizer.getIdentifier( entity );
}
@Override
public Serializable getIdentifier(Object entity, SharedSessionContractImplementor session) {
return pojoEntityTuplizer.getIdentifier( entity, session );
}
@Override
public void setIdentifier(Object entity, Serializable id) throws HibernateException {
pojoEntityTuplizer.setIdentifier( entity, id );
}
@Override
public void setIdentifier(Object entity, Serializable id, SharedSessionContractImplementor session) {
pojoEntityTuplizer.setIdentifier( entity, id, session );
}
@Override
public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion) {
pojoEntityTuplizer.resetIdentifier( entity, currentId, currentVersion );
}
@Override
public void resetIdentifier(
Object entity,
Serializable currentId,
Object currentVersion,
SharedSessionContractImplementor session) {
pojoEntityTuplizer.resetIdentifier( entity, currentId, currentVersion, session );
}
@Override
public Object getVersion(Object entity) throws HibernateException {
return pojoEntityTuplizer.getVersion( entity );
}
@Override
public void setPropertyValue(Object entity, int i, Object value) throws HibernateException {
pojoEntityTuplizer. setPropertyValue( entity, i, value );
}
@Override
public void setPropertyValue(Object entity, String propertyName, Object value) throws HibernateException {
pojoEntityTuplizer.setPropertyValue( entity, propertyName, value );
}
@Override
public Object[] getPropertyValuesToInsert(
Object entity,
Map mergeMap,
SharedSessionContractImplementor session) throws HibernateException {
return pojoEntityTuplizer.getPropertyValuesToInsert( entity, mergeMap, session );
}
@Override
public Object getPropertyValue(Object entity, String propertyName) throws HibernateException {
return pojoEntityTuplizer.getPropertyValue( entity, propertyName );
}
@Override
public void afterInitialize(Object entity, SharedSessionContractImplementor session) {
pojoEntityTuplizer.afterInitialize( entity, session );
}
@Override
public boolean hasProxy() {
return pojoEntityTuplizer.hasProxy();
}
@Override
public Object createProxy(Serializable id, SharedSessionContractImplementor session) throws HibernateException {
return pojoEntityTuplizer.createProxy( id, session );
}
@Override
public boolean isLifecycleImplementor() {
return pojoEntityTuplizer.isLifecycleImplementor();
}
@Override
public Class getConcreteProxyClass() {
return pojoEntityTuplizer.getConcreteProxyClass();
}
@Override
public EntityNameResolver[] getEntityNameResolvers() {
return pojoEntityTuplizer.getEntityNameResolvers();
}
@Override
public String determineConcreteSubclassEntityName(
Object entityInstance, SessionFactoryImplementor factory) {
return pojoEntityTuplizer.determineConcreteSubclassEntityName( entityInstance, factory );
}
@Override
public Getter getIdentifierGetter() {
return pojoEntityTuplizer.getIdentifierGetter();
}
@Override
public Getter getVersionGetter() {
return pojoEntityTuplizer.getVersionGetter();
}
@Override
public ProxyFactory getProxyFactory() {
return null;
}
@Override
public Object[] getPropertyValues(Object entity) {
return pojoEntityTuplizer.getPropertyValues( entity );
}
@Override
public void setPropertyValues(Object entity, Object[] values) {
pojoEntityTuplizer.setPropertyValues( entity, values );
}
@Override
public Object getPropertyValue(Object entity, int i) {
return pojoEntityTuplizer.getPropertyValue( entity, i );
}
@Override
public Object instantiate() {
return pojoEntityTuplizer.instantiate();
}
@Override
public boolean isInstance(Object object) {
return pojoEntityTuplizer.isInstance( object );
}
@Override
public Class getMappedClass() {
return pojoEntityTuplizer.getMappedClass();
}
@Override
public Getter getGetter(int i) {
return pojoEntityTuplizer.getGetter( i );
}
}
}

View File

@ -0,0 +1,476 @@
/*
* 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.test.bytecode.enhancement.lazy.proxy;
import java.io.Serializable;
import java.util.Map;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.EntityMode;
import org.hibernate.EntityNameResolver;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.annotations.LazyToOne;
import org.hibernate.annotations.LazyToOneOption;
import org.hibernate.annotations.Tuplizer;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.ProxyFactory;
import org.hibernate.stat.Statistics;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.tuple.entity.PojoEntityTuplizer;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-13640" )
@RunWith(BytecodeEnhancerRunner.class)
public class LazyToOnesNoProxyFactoryWithSubclassesStatelessTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
super.configureStandardServiceRegistryBuilder( ssrb );
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
}
@Override
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
super.configureSessionFactoryBuilder( sfb );
sfb.applyStatisticsSupport( true );
sfb.applySecondLevelCacheSupport( false );
sfb.applyQueryCacheSupport( false );
}
@Override
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( Animal.class );
sources.addAnnotatedClass( Primate.class );
sources.addAnnotatedClass( Human.class );
sources.addAnnotatedClass( OtherEntity.class );
}
@Test
public void testNewEnhancedProxyAssociation() {
inStatelessTransaction(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.human = human;
session.insert( human );
session.insert( otherEntity );
}
);
inStatelessSession(
session -> {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.animal ) );
assertEquals( 1, stats.getPrepareStatementCount() );
}
);
}
@Test
public void testExistingInitializedAssociationLeafSubclass() {
inStatelessSession(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.animal = human;
otherEntity.primate = human;
otherEntity.human = human;
session.insert( human );
session.insert( otherEntity );
}
);
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
inStatelessSession(
session -> {
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
assertTrue( Hibernate.isInitialized( otherEntity.animal ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.animal ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
assertTrue( Hibernate.isInitialized( otherEntity.primate ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.primate ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertTrue( Hibernate.isInitialized( otherEntity.human ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
assertSame( otherEntity.human, otherEntity.animal );
assertSame( otherEntity.human, otherEntity.primate );
assertEquals( 2, stats.getPrepareStatementCount() );
}
);
assertEquals( 2, stats.getPrepareStatementCount() );
}
@Test
public void testExistingEnhancedProxyAssociationLeafSubclassOnly() {
inStatelessSession(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.human = human;
otherEntity.otherHuman = human;
session.insert( human );
session.insert( otherEntity );
}
);
inStatelessSession(
session -> {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
assertNull( otherEntity.animal );
assertNull( otherEntity.primate );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "otherHuman" ) );
assertFalse( Hibernate.isInitialized( otherEntity.otherHuman ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.otherHuman ) );
assertSame( otherEntity.human, otherEntity.otherHuman );
assertEquals( 1, stats.getPrepareStatementCount() );
}
);
}
@After
public void cleanUpTestData() {
inTransaction(
session -> {
session.createQuery( "delete from OtherEntity" ).executeUpdate();
session.createQuery( "delete from Human" ).executeUpdate();
session.createQuery( "delete from Primate" ).executeUpdate();
session.createQuery( "delete from Animal" ).executeUpdate();
}
);
}
@Entity(name = "Animal")
@Table(name = "Animal")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Tuplizer(impl=NoProxyFactoryPojoEntityTuplizer.class)
public static abstract class Animal {
@Id
private String name;
private int age;
public String getName() {
return name;
}
protected void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Entity(name = "Primate")
@Table(name = "Primate")
public static class Primate extends Animal {
public Primate(String name) {
this();
setName( name );
}
protected Primate() {
// this form used by Hibernate
}
}
@Entity(name = "Human")
@Table(name = "Human")
public static class Human extends Primate {
private String sex;
public Human(String name) {
this();
setName( name );
}
protected Human() {
// this form used by Hibernate
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
@Entity(name = "OtherEntity")
@Table(name = "OtherEntity")
public static class OtherEntity {
@Id
private String id;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Animal animal = null;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Primate primate = null;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Human human = null;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Human otherHuman = null;
protected OtherEntity() {
// this form used by Hibernate
}
public OtherEntity(String id) {
this.id = id;
}
public String getId() {
return id;
}
public Human getHuman() {
return human;
}
public void setHuman(Human human) {
this.human = human;
}
}
public static class NoProxyFactoryPojoEntityTuplizer implements EntityTuplizer {
private final PojoEntityTuplizer pojoEntityTuplizer;
public NoProxyFactoryPojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
pojoEntityTuplizer = new PojoEntityTuplizer( entityMetamodel, mappedEntity );
}
@Override
public EntityMode getEntityMode() {
return pojoEntityTuplizer.getEntityMode();
}
@Override
public Object instantiate(Serializable id) throws HibernateException {
return pojoEntityTuplizer.instantiate( id );
}
@Override
public Object instantiate(Serializable id, SharedSessionContractImplementor session) {
return pojoEntityTuplizer.instantiate( id, session );
}
@Override
public Serializable getIdentifier(Object entity) throws HibernateException {
return pojoEntityTuplizer.getIdentifier( entity );
}
@Override
public Serializable getIdentifier(Object entity, SharedSessionContractImplementor session) {
return pojoEntityTuplizer.getIdentifier( entity, session );
}
@Override
public void setIdentifier(Object entity, Serializable id) throws HibernateException {
pojoEntityTuplizer.setIdentifier( entity, id );
}
@Override
public void setIdentifier(Object entity, Serializable id, SharedSessionContractImplementor session) {
pojoEntityTuplizer.setIdentifier( entity, id, session );
}
@Override
public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion) {
pojoEntityTuplizer.resetIdentifier( entity, currentId, currentVersion );
}
@Override
public void resetIdentifier(
Object entity,
Serializable currentId,
Object currentVersion,
SharedSessionContractImplementor session) {
pojoEntityTuplizer.resetIdentifier( entity, currentId, currentVersion, session );
}
@Override
public Object getVersion(Object entity) throws HibernateException {
return pojoEntityTuplizer.getVersion( entity );
}
@Override
public void setPropertyValue(Object entity, int i, Object value) throws HibernateException {
pojoEntityTuplizer. setPropertyValue( entity, i, value );
}
@Override
public void setPropertyValue(Object entity, String propertyName, Object value) throws HibernateException {
pojoEntityTuplizer.setPropertyValue( entity, propertyName, value );
}
@Override
public Object[] getPropertyValuesToInsert(
Object entity,
Map mergeMap,
SharedSessionContractImplementor session) throws HibernateException {
return pojoEntityTuplizer.getPropertyValuesToInsert( entity, mergeMap, session );
}
@Override
public Object getPropertyValue(Object entity, String propertyName) throws HibernateException {
return pojoEntityTuplizer.getPropertyValue( entity, propertyName );
}
@Override
public void afterInitialize(Object entity, SharedSessionContractImplementor session) {
pojoEntityTuplizer.afterInitialize( entity, session );
}
@Override
public boolean hasProxy() {
return pojoEntityTuplizer.hasProxy();
}
@Override
public Object createProxy(Serializable id, SharedSessionContractImplementor session) throws HibernateException {
return pojoEntityTuplizer.createProxy( id, session );
}
@Override
public boolean isLifecycleImplementor() {
return pojoEntityTuplizer.isLifecycleImplementor();
}
@Override
public Class getConcreteProxyClass() {
return pojoEntityTuplizer.getConcreteProxyClass();
}
@Override
public EntityNameResolver[] getEntityNameResolvers() {
return pojoEntityTuplizer.getEntityNameResolvers();
}
@Override
public String determineConcreteSubclassEntityName(
Object entityInstance, SessionFactoryImplementor factory) {
return pojoEntityTuplizer.determineConcreteSubclassEntityName( entityInstance, factory );
}
@Override
public Getter getIdentifierGetter() {
return pojoEntityTuplizer.getIdentifierGetter();
}
@Override
public Getter getVersionGetter() {
return pojoEntityTuplizer.getVersionGetter();
}
@Override
public ProxyFactory getProxyFactory() {
return null;
}
@Override
public Object[] getPropertyValues(Object entity) {
return pojoEntityTuplizer.getPropertyValues( entity );
}
@Override
public void setPropertyValues(Object entity, Object[] values) {
pojoEntityTuplizer.setPropertyValues( entity, values );
}
@Override
public Object getPropertyValue(Object entity, int i) {
return pojoEntityTuplizer.getPropertyValue( entity, i );
}
@Override
public Object instantiate() {
return pojoEntityTuplizer.instantiate();
}
@Override
public boolean isInstance(Object object) {
return pojoEntityTuplizer.isInstance( object );
}
@Override
public Class getMappedClass() {
return pojoEntityTuplizer.getMappedClass();
}
@Override
public Getter getGetter(int i) {
return pojoEntityTuplizer.getGetter( i );
}
}
}

View File

@ -0,0 +1,865 @@
/*
* 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.test.bytecode.enhancement.lazy.proxy;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.Hibernate;
import org.hibernate.annotations.LazyToOne;
import org.hibernate.annotations.LazyToOneOption;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.stat.Statistics;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-13640" )
@RunWith(BytecodeEnhancerRunner.class )
@EnhancementOptions(lazyLoading = true)
public class LazyToOnesProxyMergeWithSubclassesTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
super.configureStandardServiceRegistryBuilder( ssrb );
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
}
@Override
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
super.configureSessionFactoryBuilder( sfb );
sfb.applyStatisticsSupport( true );
sfb.applySecondLevelCacheSupport( false );
sfb.applyQueryCacheSupport( false );
}
@Override
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( Animal.class );
sources.addAnnotatedClass( Primate.class );
sources.addAnnotatedClass( Human.class );
sources.addAnnotatedClass( OtherEntity.class );
}
@Test
public void mergeUpdatedHibernateProxy() {
checkAgeInNewSession( 1 );
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity withInitializedHibernateProxy = doInHibernate(
this::sessionFactory,
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
otherEntity.getHuman().getSex();
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertEquals( 2, stats.getPrepareStatementCount() );
return otherEntity;
}
);
assertEquals( 2, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 1 );
stats.clear();
// merge updated HibernateProxy to updated HibernateProxy
withInitializedHibernateProxy.getHuman().setAge( 2 );
doInHibernate(
this::sessionFactory,
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
otherEntity.getHuman().setAge( 3 );
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertEquals( 2, stats.getPrepareStatementCount() );
final Human humanImpl = (Human) ( (HibernateProxy) otherEntity.getHuman() )
.getHibernateLazyInitializer()
.getImplementation();
session.merge( withInitializedHibernateProxy );
// TODO: Reference to associated HibernateProxy is changed
// to the HibernateProxy's implementation.
assertSame( humanImpl, otherEntity.getHuman() );
assertEquals( 2, otherEntity.getHuman().getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 2 );
stats.clear();
// merge updated HibernateProxy to updated enhanced entity
withInitializedHibernateProxy.getHuman().setAge( 4 );
doInHibernate(
this::sessionFactory,
session -> {
final Human human = session.getReference( Human.class, "A Human" );
assertFalse( Hibernate.isInitialized( human ) );
assertFalse( HibernateProxy.class.isInstance( human ) );
assertEquals( 0, stats.getPrepareStatementCount() );
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertSame( human, otherEntity.getHuman() );
assertEquals( 1, stats.getPrepareStatementCount() );
human.setAge( 5 );
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertEquals( 2, stats.getPrepareStatementCount() );
session.merge( withInitializedHibernateProxy );
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertSame( human, otherEntity.getHuman() );
assertEquals( 4, human.getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 4 );
stats.clear();
// merge updated HibernateProxy to uninitialized HibernateProxy
withInitializedHibernateProxy.getHuman().setAge( 6 );
doInHibernate(
this::sessionFactory,
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
final Human humanHibernateProxy = otherEntity.getHuman();
session.merge( withInitializedHibernateProxy );
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
// TODO: Reference to associated HibernateProxy is changed
// reference to the HibernateProxy's implementation.
assertFalse( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
assertSame(
otherEntity.getHuman(),
( (HibernateProxy) humanHibernateProxy ).getHibernateLazyInitializer().getImplementation()
);
assertEquals( 6, otherEntity.getHuman().getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 6 );
stats.clear();
// merge updated HibernateProxy To uninitialized enhanced proxy
withInitializedHibernateProxy.getHuman().setAge( 7 );
doInHibernate(
this::sessionFactory,
session -> {
final Human human = session.getReference( Human.class, "A Human" );
assertFalse( Hibernate.isInitialized( human ) );
assertFalse( HibernateProxy.class.isInstance( human ) );
assertEquals( 0, stats.getPrepareStatementCount() );
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertSame( human, otherEntity.getHuman() );
assertFalse( Hibernate.isInitialized( human ) );
session.merge( withInitializedHibernateProxy );
assertSame( human, otherEntity.getHuman() );
assertTrue( Hibernate.isInitialized( human ) );
assertEquals( 7, otherEntity.getHuman().getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 7 );
}
@Test
public void mergeUpdatedEnhancedProxy() {
checkAgeInNewSession( 1 );
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity withInitializedEnhancedProxy = doInHibernate(
this::sessionFactory,
session -> {
final Human human = session.getReference( Human.class, "A Human" );
assertFalse( Hibernate.isInitialized( human ) );
assertFalse( HibernateProxy.class.isInstance( human ) );
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertSame( human, otherEntity.getHuman() );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
otherEntity.getHuman().getSex();
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertEquals( 2, stats.getPrepareStatementCount() );
return otherEntity;
}
);
assertEquals( 2, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 1 );
stats.clear();
// merge updated enhanced proxy to updated HibernateProxy
withInitializedEnhancedProxy.getHuman().setAge( 2 );
doInHibernate(
this::sessionFactory,
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
otherEntity.getHuman().setAge( 3 );
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertEquals( 2, stats.getPrepareStatementCount() );
final Human humanImpl = (Human) ( (HibernateProxy) otherEntity.getHuman() )
.getHibernateLazyInitializer()
.getImplementation();
session.merge( withInitializedEnhancedProxy );
// TODO: Reference to HibernateProxy is changed
// to the HibernateProxy's implementation.
assertSame( humanImpl, otherEntity.getHuman() );
assertEquals( 2, otherEntity.getHuman().getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 2 );
stats.clear();
// merge updated enhanced proxy to updated enhanced proxy
withInitializedEnhancedProxy.getHuman().setAge( 4 );
doInHibernate(
this::sessionFactory,
session -> {
final Human human = session.getReference( Human.class, "A Human" );
assertFalse( Hibernate.isInitialized( human ) );
assertFalse( HibernateProxy.class.isInstance( human ) );
assertEquals( 0, stats.getPrepareStatementCount() );
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertSame( human, otherEntity.getHuman() );
assertEquals( 1, stats.getPrepareStatementCount() );
human.setAge( 5 );
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertEquals( 2, stats.getPrepareStatementCount() );
session.merge( withInitializedEnhancedProxy );
assertEquals( 4, human.getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 4 );
stats.clear();
// merge updated enhanced proxy to uninitialized HibernateProxy
withInitializedEnhancedProxy.getHuman().setAge( 6 );
doInHibernate(
this::sessionFactory,
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
session.merge( withInitializedEnhancedProxy );
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
// TODO: Reference in managed entity gets changed from a HibernateProxy
// to an initialized entity. This happens without enhancement as well.
//assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
assertEquals( 6, otherEntity.getHuman().getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 6 );
stats.clear();
// merge updated enhanced proxy to uninitialized enhanced proxy
withInitializedEnhancedProxy.getHuman().setAge( 7 );
doInHibernate(
this::sessionFactory,
session -> {
final Human human = session.getReference( Human.class, "A Human" );
assertFalse( Hibernate.isInitialized( human ) );
assertFalse( HibernateProxy.class.isInstance( human ) );
assertEquals( 0, stats.getPrepareStatementCount() );
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertSame( human, otherEntity.getHuman() );
assertFalse( Hibernate.isInitialized( human ) );
session.merge( withInitializedEnhancedProxy );
assertSame( human, otherEntity.getHuman() );
assertTrue( Hibernate.isInitialized( human ) );
assertEquals( 7, otherEntity.getHuman().getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 7 );
}
@Test
public void mergeUninitializedHibernateProxy() {
checkAgeInNewSession( 1 );
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity withUninitializedHibernateProxy = doInHibernate(
this::sessionFactory,
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
return otherEntity;
}
);
assertEquals( 1, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 1 );
stats.clear();
// merge uninitialized HibernateProxy to updated HibernateProxy
doInHibernate(
this::sessionFactory,
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
otherEntity.getHuman().setAge( 3 );
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertEquals( 2, stats.getPrepareStatementCount() );
final Human humanImpl = (Human) ( (HibernateProxy) otherEntity.getHuman() )
.getHibernateLazyInitializer()
.getImplementation();
session.merge( withUninitializedHibernateProxy );
//assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
// TODO: Reference to HibernateProxy is changed
// to the HibernateProxy's implementation.
assertSame( humanImpl, otherEntity.getHuman() );
assertEquals( 3, otherEntity.getHuman().getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 3 );
stats.clear();
// merge uninitialized HibernateProxy to updated enhanced proxy
doInHibernate(
this::sessionFactory,
session -> {
final Human human = session.getReference( Human.class, "A Human" );
assertFalse( Hibernate.isInitialized( human ) );
assertFalse( HibernateProxy.class.isInstance( human ) );
assertEquals( 0, stats.getPrepareStatementCount() );
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertSame( human, otherEntity.getHuman() );
assertEquals( 1, stats.getPrepareStatementCount() );
human.setAge( 5 );
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertEquals( 2, stats.getPrepareStatementCount() );
session.merge( withUninitializedHibernateProxy );
assertEquals( 5, human.getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 5 );
stats.clear();
// merge uninitialized HibernateProxy to uninitialized HibernateProxy
doInHibernate(
this::sessionFactory,
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
session.merge( withUninitializedHibernateProxy );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
}
);
assertEquals( 1, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 5 );
stats.clear();
// merge uninitialized HibernateProxy to uninitialized enhanced proxy
doInHibernate(
this::sessionFactory,
session -> {
final Human human = session.getReference( Human.class, "A Human" );
assertFalse( Hibernate.isInitialized( human ) );
assertFalse( HibernateProxy.class.isInstance( human ) );
assertEquals( 0, stats.getPrepareStatementCount() );
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertSame( human, otherEntity.getHuman() );
assertFalse( Hibernate.isInitialized( human ) );
session.merge( withUninitializedHibernateProxy );
assertSame( human, otherEntity.getHuman() );
assertFalse( Hibernate.isInitialized( human ) );
}
);
assertEquals( 1, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 5 );
}
@Test
public void testmergeUninitializedEnhancedProxy() {
checkAgeInNewSession( 1 );
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity withUninitializedEnhancedProxy = doInHibernate(
this::sessionFactory,
session -> {
final Human human = session.getReference( Human.class, "A Human" );
assertFalse( Hibernate.isInitialized( human ) );
assertFalse( HibernateProxy.class.isInstance( human ) );
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertSame( human, otherEntity.getHuman() );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
return otherEntity;
}
);
assertEquals( 1, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 1 );
stats.clear();
// merge uninitialized enhanced proxy to updated HibernateProxy
doInHibernate(
this::sessionFactory,
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
otherEntity.getHuman().setAge( 3 );
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertEquals( 2, stats.getPrepareStatementCount() );
final Human humanImpl = (Human) ( (HibernateProxy) otherEntity.getHuman() )
.getHibernateLazyInitializer()
.getImplementation();
session.merge( withUninitializedEnhancedProxy );
// TODO: Reference to HibernateProxy is changed
// to the HibernateProxy's implementation.
assertSame( humanImpl, otherEntity.getHuman() );
assertEquals( 3, otherEntity.getHuman().getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 3 );
stats.clear();
// merge uninitialized enhanced proxy to updated enhanced entity
doInHibernate(
this::sessionFactory,
session -> {
final Human human = session.getReference( Human.class, "A Human" );
assertFalse( Hibernate.isInitialized( human ) );
assertFalse( HibernateProxy.class.isInstance( human ) );
assertEquals( 0, stats.getPrepareStatementCount() );
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertSame( human, otherEntity.getHuman() );
assertEquals( 1, stats.getPrepareStatementCount() );
human.setAge( 5 );
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertEquals( 2, stats.getPrepareStatementCount() );
session.merge( withUninitializedEnhancedProxy );
assertEquals( 5, human.getAge() );
}
);
assertEquals( 3, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 5 );
stats.clear();
// merge uninitialized enhanced proxy to uninitialized HibernateProxy
doInHibernate(
this::sessionFactory,
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
session.merge( withUninitializedEnhancedProxy );
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
}
);
assertEquals( 1, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 5 );
stats.clear();
// merge uninitialized enhanced proxy to uninitialized enhanced proxy
doInHibernate(
this::sessionFactory,
session -> {
final Human human = session.getReference( Human.class, "A Human" );
assertFalse( Hibernate.isInitialized( human ) );
assertFalse( HibernateProxy.class.isInstance( human ) );
assertEquals( 0, stats.getPrepareStatementCount() );
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertEquals( 1, stats.getPrepareStatementCount() );
assertSame( human, otherEntity.getHuman() );
assertFalse( Hibernate.isInitialized( human ) );
session.merge( withUninitializedEnhancedProxy );
assertSame( human, otherEntity.getHuman() );
assertFalse( Hibernate.isInitialized( human ) );
}
);
assertEquals( 1, stats.getPrepareStatementCount() );
stats.clear();
checkAgeInNewSession( 5 );
}
private void checkAgeInNewSession(int expectedAge) {
doInHibernate(
this::sessionFactory,
session -> {
final Human human = session.get( Human.class, "A Human" );
assertEquals( expectedAge, human.getAge() );
}
);
}
@Before
public void setupData() {
inTransaction(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.animal = human;
otherEntity.primate = human;
otherEntity.human = human;
otherEntity.human.setAge( 1 );
session.persist( human );
session.persist( otherEntity );
}
);
}
@After
public void cleanUpTestData() {
inTransaction(
session -> {
session.createQuery( "delete from OtherEntity" ).executeUpdate();
session.createQuery( "delete from Human" ).executeUpdate();
session.createQuery( "delete from Primate" ).executeUpdate();
session.createQuery( "delete from Animal" ).executeUpdate();
}
);
}
@Entity(name = "Animal")
@Table(name = "Animal")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public static abstract class Animal {
@Id
private String name;
private int age;
public String getName() {
return name;
}
protected void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Entity(name = "Primate")
@Table(name = "Primate")
public static class Primate extends Animal {
public Primate(String name) {
this();
setName( name );
}
protected Primate() {
// this form used by Hibernate
}
}
@Entity(name = "Human")
@Table(name = "Human")
public static class Human extends Primate {
private String sex;
public Human(String name) {
this();
setName( name );
}
protected Human() {
// this form used by Hibernate
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
@Entity(name = "OtherEntity")
@Table(name = "OtherEntity")
public static class OtherEntity {
@Id
private String id;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Animal animal = null;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Primate primate = null;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Human human = null;
protected OtherEntity() {
// this form used by Hibernate
}
public OtherEntity(String id) {
this.id = id;
}
public String getId() {
return id;
}
public Human getHuman() {
return human;
}
public void setHuman(Human human) {
this.human = human;
}
}
}

View File

@ -0,0 +1,332 @@
/*
* 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.test.bytecode.enhancement.lazy.proxy;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.Hibernate;
import org.hibernate.annotations.LazyToOne;
import org.hibernate.annotations.LazyToOneOption;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.stat.Statistics;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-13640" )
@RunWith(BytecodeEnhancerRunner.class)
public class LazyToOnesProxyWithSubclassesStatelessTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
super.configureStandardServiceRegistryBuilder( ssrb );
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
}
@Override
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
super.configureSessionFactoryBuilder( sfb );
sfb.applyStatisticsSupport( true );
sfb.applySecondLevelCacheSupport( false );
sfb.applyQueryCacheSupport( false );
}
@Override
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( Animal.class );
sources.addAnnotatedClass( Primate.class );
sources.addAnnotatedClass( Human.class );
sources.addAnnotatedClass( OtherEntity.class );
}
@Test
public void testNewHibernateProxyAssociation() {
inStatelessTransaction(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.animal = human;
session.insert( human );
session.insert( otherEntity );
}
);
inStatelessSession(
session -> {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
assertEquals( 1, stats.getPrepareStatementCount() );
}
);
}
@Test
public void testNewEnhancedProxyAssociation() {
inStatelessTransaction(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.human = human;
session.insert( human );
session.insert( otherEntity );
}
);
inStatelessSession(
session -> {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.animal ) );
assertEquals( 1, stats.getPrepareStatementCount() );
}
);
}
@Test
public void testExistingProxyAssociation() {
inStatelessTransaction(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.animal = human;
otherEntity.primate = human;
session.insert( human );
session.insert( otherEntity );
}
);
inStatelessSession(
session -> {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
assertFalse( Hibernate.isInitialized( otherEntity.primate ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) );
assertEquals( 1, stats.getPrepareStatementCount() );
}
);
}
@Test
public void testExistingHibernateProxyAssociationLeafSubclass() {
inStatelessSession(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.animal = human;
otherEntity.primate = human;
otherEntity.human = human;
session.insert( human );
session.insert( otherEntity );
}
);
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
inStatelessSession(
session -> {
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
assertFalse( Hibernate.isInitialized( otherEntity.primate ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
assertEquals( 1, stats.getPrepareStatementCount() );
}
);
assertEquals( 1, stats.getPrepareStatementCount() );
}
@Test
public void testExistingEnhancedProxyAssociationLeafSubclassOnly() {
inStatelessSession(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.human = human;
session.insert( human );
session.insert( otherEntity );
}
);
inStatelessSession(
session -> {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
assertNull( otherEntity.animal );
assertNull( otherEntity.primate );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
assertEquals( 1, stats.getPrepareStatementCount() );
}
);
}
@After
public void cleanUpTestData() {
inTransaction(
session -> {
session.createQuery( "delete from OtherEntity" ).executeUpdate();
session.createQuery( "delete from Human" ).executeUpdate();
session.createQuery( "delete from Primate" ).executeUpdate();
session.createQuery( "delete from Animal" ).executeUpdate();
}
);
}
@Entity(name = "Animal")
@Table(name = "Animal")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public static abstract class Animal {
@Id
private String name;
private int age;
public String getName() {
return name;
}
protected void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Entity(name = "Primate")
@Table(name = "Primate")
public static class Primate extends Animal {
public Primate(String name) {
this();
setName( name );
}
protected Primate() {
// this form used by Hibernate
}
}
@Entity(name = "Human")
@Table(name = "Human")
public static class Human extends Primate {
private String sex;
public Human(String name) {
this();
setName( name );
}
protected Human() {
// this form used by Hibernate
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
@Entity(name = "OtherEntity")
@Table(name = "OtherEntity")
public static class OtherEntity {
@Id
private String id;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Animal animal = null;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Primate primate = null;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
private Human human = null;
protected OtherEntity() {
// this form used by Hibernate
}
public OtherEntity(String id) {
this.id = id;
}
public String getId() {
return id;
}
public Human getHuman() {
return human;
}
public void setHuman(Human human) {
this.human = human;
}
}
}

View File

@ -31,8 +31,10 @@ import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
/** /**
@ -154,7 +156,7 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
} }
@Test @Test
public void testExistingProxyAssociationLeafSubclass() { public void testExistingHibernateProxyAssociationLeafSubclass() {
inTransaction( inTransaction(
session -> { session -> {
Human human = new Human( "A Human" ); Human human = new Human( "A Human" );
@ -167,10 +169,11 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
} }
); );
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
inSession( inSession(
session -> { session -> {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" ); final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) ); assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
@ -181,18 +184,101 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) ); assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) ); assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.human ) ); assertFalse( Hibernate.isInitialized( otherEntity.human ) );
// TODO: Should otherEntity.human be a narrowed HibernateProxy or
// an uninitialized non-HibernateProxy proxy?
assertEquals( 1, stats.getPrepareStatementCount() ); assertEquals( 1, stats.getPrepareStatementCount() );
Human human = otherEntity.getHuman(); // Make sure human can still get loaded and not initialized.
final Human human = session.getReference( Human.class, "A Human" );
assertTrue( HibernateProxy.class.isInstance( otherEntity.human ) );
assertFalse( Hibernate.isInitialized( human ) );
human.getName(); human.getName();
assertEquals( 1, stats.getPrepareStatementCount() ); assertEquals( 1, stats.getPrepareStatementCount() );
assertFalse( Hibernate.isInitialized( human ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.human ) );
human.getSex(); human.getSex();
assertTrue( Hibernate.isInitialized( human ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.human ) );
assertEquals( 2, stats.getPrepareStatementCount() ); assertEquals( 2, stats.getPrepareStatementCount() );
} }
); );
assertEquals( 2, stats.getPrepareStatementCount() );
stats.clear();
inSession(
session -> {
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
assertFalse( Hibernate.isInitialized( otherEntity.primate ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
assertEquals( 1, stats.getPrepareStatementCount() );
// Make sure human can still get loaded
final Human human = session.get( Human.class, "A Human" );
assertTrue( !HibernateProxy.class.isInstance( human ) );
assertTrue( Hibernate.isInitialized( human ) );
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
assertEquals( 2, stats.getPrepareStatementCount() );
}
);
assertEquals( 2, stats.getPrepareStatementCount() );
}
@Test
public void testExistingEnhancedProxyAssociationLeafSubclassOnly() {
inTransaction(
session -> {
Human human = new Human( "A Human" );
OtherEntity otherEntity = new OtherEntity( "test1" );
otherEntity.human = human;
session.persist( human );
session.persist( otherEntity );
}
);
doInHibernate(
this::sessionFactory, session -> {
final Statistics stats = sessionFactory().getStatistics();
stats.clear();
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
assertNull( otherEntity.animal );
assertNull( otherEntity.primate );
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
assertEquals( 1, stats.getPrepareStatementCount() );
// Make sure human can still get loaded and not initialized.
final Human human = session.getReference( Human.class, "A Human" );
assertFalse( Hibernate.isInitialized( human ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
human.getName();
assertEquals( 1, stats.getPrepareStatementCount() );
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
human.getSex();
assertTrue( Hibernate.isInitialized( otherEntity.human ) );
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
assertEquals( 2, stats.getPrepareStatementCount() );
return otherEntity;
}
);
} }
@After @After
@ -215,6 +301,8 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
@Id @Id
private String name; private String name;
private int age;
public String getName() { public String getName() {
return name; return name;
} }
@ -223,6 +311,13 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
this.name = name; this.name = name;
} }
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
} }
@Entity(name = "Primate") @Entity(name = "Primate")
@ -272,15 +367,15 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY) @LazyToOne(LazyToOneOption.NO_PROXY)
protected Animal animal = null; private Animal animal = null;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY) @LazyToOne(LazyToOneOption.NO_PROXY)
protected Primate primate = null; private Primate primate = null;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY) @LazyToOne(LazyToOneOption.NO_PROXY)
protected Human human = null; private Human human = null;
protected OtherEntity() { protected OtherEntity() {
// this form used by Hibernate // this form used by Hibernate

View File

@ -27,6 +27,7 @@ import org.junit.runner.RunWith;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
/** /**
@ -155,7 +156,8 @@ public class ProxyInitializeAndUpdateTest extends BaseNonConfigCoreFunctionalTes
session -> { session -> {
final Animal animal = session.load( Animal.class, "animal" ); final Animal animal = session.load( Animal.class, "animal" );
assertFalse( Hibernate.isInitialized( animal ) ); assertFalse( Hibernate.isInitialized( animal ) );
session.merge( animalInitialized ); final Animal animalMerged = (Animal) session.merge( animalInitialized );
assertSame( animal, animalMerged );
assertTrue( Hibernate.isInitialized( animal ) ); assertTrue( Hibernate.isInitialized( animal ) );
assertEquals( 4, animal.getAge() ); assertEquals( 4, animal.getAge() );
assertEquals( "other", animal.getSex() ); assertEquals( "other", animal.getSex() );
@ -204,7 +206,8 @@ public class ProxyInitializeAndUpdateTest extends BaseNonConfigCoreFunctionalTes
assertTrue( Hibernate.isInitialized( animal ) ); assertTrue( Hibernate.isInitialized( animal ) );
animal.setAge( 5 ); animal.setAge( 5 );
animal.setSex( "male" ); animal.setSex( "male" );
session.merge( animalInitialized ); final Animal animalMerged = (Animal) session.merge( animalInitialized );
assertSame( animal, animalMerged );
assertEquals( 4, animal.getAge() ); assertEquals( 4, animal.getAge() );
assertEquals( "other", animal.getSex() ); assertEquals( "other", animal.getSex() );
} }
@ -245,7 +248,8 @@ public class ProxyInitializeAndUpdateTest extends BaseNonConfigCoreFunctionalTes
session -> { session -> {
final Animal animal = session.load( Animal.class, "animal" ); final Animal animal = session.load( Animal.class, "animal" );
assertFalse( Hibernate.isInitialized( animal ) ); assertFalse( Hibernate.isInitialized( animal ) );
session.merge( animalUninitialized ); final Animal animalMerged = (Animal) session.merge( animalUninitialized );
assertSame( animal, animalMerged );
assertFalse( Hibernate.isInitialized( animal ) ); assertFalse( Hibernate.isInitialized( animal ) );
} }
); );
@ -283,11 +287,13 @@ public class ProxyInitializeAndUpdateTest extends BaseNonConfigCoreFunctionalTes
inTransaction( inTransaction(
session -> { session -> {
final Animal animal = session.get( Animal.class, "animal" ); final Animal animal = session.load( Animal.class, "animal" );
assertTrue( Hibernate.isInitialized( animal ) ); assertFalse( Hibernate.isInitialized( animal ) );
animal.setSex( "other" ); animal.setSex( "other" );
assertTrue( Hibernate.isInitialized( animal ) );
animal.setAge( 4 ); animal.setAge( 4 );
session.merge( animalUninitialized ); final Animal animalMerged = (Animal) session.merge( animalUninitialized );
assertSame( animal, animalMerged );
assertTrue( Hibernate.isInitialized( animal ) ); assertTrue( Hibernate.isInitialized( animal ) );
assertEquals( "other", animal.getSex() ); assertEquals( "other", animal.getSex() );
assertEquals( 4, animal.getAge() ); assertEquals( 4, animal.getAge() );

View File

@ -0,0 +1,327 @@
/*
* 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.test.bytecode.enhancement.lazy.proxy;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.Hibernate;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
import org.hibernate.annotations.LazyToOne;
import org.hibernate.annotations.LazyToOneOption;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.query.Query;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Andrea Boriero
*/
@RunWith(BytecodeEnhancerRunner.class)
public class QueryScrollingWithInheritanceProxyTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
super.configureStandardServiceRegistryBuilder( ssrb );
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
}
@Override
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
super.configureSessionFactoryBuilder( sfb );
sfb.applyStatisticsSupport( true );
sfb.applySecondLevelCacheSupport( false );
sfb.applyQueryCacheSupport( false );
}
@Override
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( EmployeeParent.class );
sources.addAnnotatedClass( Employee.class );
sources.addAnnotatedClass( OtherEntity.class );
}
@Test
public void testScrollableWithStatelessSession() {
final StatisticsImplementor stats = sessionFactory().getStatistics();
stats.clear();
ScrollableResults scrollableResults = null;
final StatelessSession statelessSession = sessionFactory().openStatelessSession();
try {
statelessSession.beginTransaction();
Query<Employee> query = statelessSession.createQuery(
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
Employee.class
);
if ( getDialect() instanceof DB2Dialect ) {
/*
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
set type of TYPE_FORWARD_ONLY and db2 does not support it.
*/
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
}
else {
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
}
while ( scrollableResults.next() ) {
final Employee employee = (Employee) scrollableResults.get( 0 );
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
if ( "ENG1".equals( employee.getDept() ) ) {
assertThat( employee.getOtherEntities().size(), is( 2 ) );
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
if ( "test1".equals( otherEntity.id ) ) {
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
assertThat( otherEntity.employee, is( employee ) );
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
assertThat( otherEntity.employeeParent, is( employee ) );
}
else {
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
assertThat( otherEntity.employee, is( employee ) );
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
assertThat( Hibernate.isInitialized( otherEntity.employeeParent ), is( false ) );
}
}
}
else {
assertThat( employee.getOtherEntities().size(), is( 0 ) );
}
}
statelessSession.getTransaction().commit();
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
}
finally {
if ( scrollableResults != null ) {
scrollableResults.close();
}
if ( statelessSession.getTransaction().isActive() ) {
statelessSession.getTransaction().rollback();
}
statelessSession.close();
}
}
@Test
public void testScrollableWithSession() {
final StatisticsImplementor stats = sessionFactory().getStatistics();
stats.clear();
ScrollableResults scrollableResults = null;
final Session session = sessionFactory().openSession();
try {
session.beginTransaction();
Query<Employee> query = session.createQuery(
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
Employee.class
);
if ( getDialect() instanceof DB2Dialect ) {
/*
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
set type of TYPE_FORWARD_ONLY and db2 does not support it.
*/
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
}
else {
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
}
while ( scrollableResults.next() ) {
final Employee employee = (Employee) scrollableResults.get( 0 );
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
if ( "ENG1".equals( employee.getDept() ) ) {
assertThat( employee.getOtherEntities().size(), is( 2 ) );
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
if ( "test1".equals( otherEntity.id ) ) {
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
assertThat( otherEntity.employee, is( employee ) );
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
assertThat( otherEntity.employeeParent, is( employee ) );
}
else {
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
assertThat( otherEntity.employee, is( employee ) );
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
assertThat( Hibernate.isInitialized( otherEntity.employeeParent ), is( false ) );
}
}
}
else {
assertThat( employee.getOtherEntities().size(), is( 0 ) );
}
}
session.getTransaction().commit();
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
}
finally {
if ( scrollableResults != null ) {
scrollableResults.close();
}
if ( session.getTransaction().isActive() ) {
session.getTransaction().rollback();
}
session.close();
}
}
@Before
public void prepareTestData() {
inTransaction(
session -> {
Employee e1 = new Employee( "ENG1" );
Employee e2 = new Employee( "ENG2" );
OtherEntity other1 = new OtherEntity( "test1" );
OtherEntity other2 = new OtherEntity( "test2" );
e1.getOtherEntities().add( other1 );
e1.getOtherEntities().add( other2 );
e1.getParentOtherEntities().add( other1 );
e1.getParentOtherEntities().add( other2 );
other1.employee = e1;
other2.employee = e1;
other1.employeeParent = e1;
other2.employeeParent = e2;
session.persist( other1 );
session.persist( other2 );
session.persist( e1 );
session.persist( e2 );
}
);
}
@After
public void cleanUpTestData() {
inTransaction(
session -> {
session.createQuery( "delete from OtherEntity" ).executeUpdate();
session.createQuery( "delete from Employee" ).executeUpdate();
session.createQuery( "delete from EmployeeParent" ).executeUpdate();
}
);
}
@Entity(name = "EmployeeParent")
@Table(name = "EmployeeParent")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public static abstract class EmployeeParent {
@Id
private String dept;
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employeeParent", fetch = FetchType.LAZY)
protected Set<OtherEntity> parentOtherEntities = new HashSet<>();
public Set<OtherEntity> getParentOtherEntities() {
if ( parentOtherEntities == null ) {
parentOtherEntities = new LinkedHashSet();
}
return parentOtherEntities;
}
public void setOtherEntities(Set<OtherEntity> pParentOtherEntites) {
parentOtherEntities = pParentOtherEntites;
}
public String getDept() {
return dept;
}
protected void setDept(String dept) {
this.dept = dept;
}
}
@Entity(name = "Employee")
@Table(name = "Employee")
public static class Employee extends EmployeeParent {
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employee", fetch = FetchType.LAZY)
protected Set<OtherEntity> otherEntities = new HashSet<>();
public Employee(String dept) {
this();
setDept( dept );
}
protected Employee() {
// this form used by Hibernate
}
public Set<OtherEntity> getOtherEntities() {
if ( otherEntities == null ) {
otherEntities = new LinkedHashSet();
}
return otherEntities;
}
public void setOtherEntities(Set<OtherEntity> pOtherEntites) {
otherEntities = pOtherEntites;
}
}
@Entity(name = "OtherEntity")
@Table(name = "OtherEntity")
public static class OtherEntity {
@Id
private String id;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
@JoinColumn(name = "Employee_Id")
protected Employee employee = null;
@ManyToOne(fetch = FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
@JoinColumn(name = "EmployeeParent_Id")
protected EmployeeParent employeeParent = null;
protected OtherEntity() {
// this form used by Hibernate
}
public OtherEntity(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
}

View File

@ -0,0 +1,72 @@
/*
* 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.test.cfg.cache;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Immutable;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Before;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
/**
* @author Andrea Boriero
*/
@TestForIssue(jiraKey = "HHH-13665")
public class DirectReferenceCacheEntriesTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { TheEntity.class };
}
@Override
protected void configure(Configuration configuration) {
configuration.setProperty( AvailableSettings.USE_DIRECT_REFERENCE_CACHE_ENTRIES, "true" );
}
@Before
public void setUp() {
doInHibernate( this::sessionFactory, session -> {
TheEntity theEntity = new TheEntity();
theEntity.setId( 1L );
session.persist( theEntity );
} );
}
@Test
public void testSelectANonCachablenEntity() {
doInHibernate( this::sessionFactory, session -> {
session.createQuery( "select t from TheEntity t", TheEntity.class ).getResultList();
} );
}
@Entity(name = "TheEntity")
@Table(name = "THE_ENTITY")
@Immutable
public static class TheEntity {
@Id
public Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
}

View File

@ -0,0 +1,38 @@
/*
* 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.test.flush;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
/**
* Test for issue https://hibernate.atlassian.net/browse/HHH-13663
*
* @author Luca Domenichini
*/
@TestForIssue(jiraKey = "HHH-13663")
public class TestHibernateFlushModeOnThreadLocalInactiveTransaction extends BaseCoreFunctionalTestCase {
@Override
protected void configure(Configuration configuration) {
configuration.setProperty( AvailableSettings.CURRENT_SESSION_CONTEXT_CLASS, "thread" );
}
@Test
public void testHibernateFlushModeOnInactiveTransaction() {
try ( Session s = sessionFactory().getCurrentSession() ) {
//s.setFlushMode( FlushMode.AUTO ); // this does not throw (API is deprecated)
s.setHibernateFlushMode( FlushMode.AUTO ); // this should not throw even within an inactive transaction
}
}
}

View File

@ -0,0 +1,318 @@
/*
* 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.test.hqlfetchscroll;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.Hibernate;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.query.Query;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Andrea Boriero
*/
public class QueryScrollingWithInheritanceTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
super.configureStandardServiceRegistryBuilder( ssrb );
}
@Override
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
super.configureSessionFactoryBuilder( sfb );
sfb.applyStatisticsSupport( true );
sfb.applySecondLevelCacheSupport( false );
sfb.applyQueryCacheSupport( false );
}
@Override
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( EmployeeParent.class );
sources.addAnnotatedClass( Employee.class );
sources.addAnnotatedClass( OtherEntity.class );
}
@Test
public void testScrollableWithStatelessSession() {
final StatisticsImplementor stats = sessionFactory().getStatistics();
stats.clear();
ScrollableResults scrollableResults = null;
final StatelessSession statelessSession = sessionFactory().openStatelessSession();
try {
statelessSession.beginTransaction();
Query<Employee> query = statelessSession.createQuery(
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
Employee.class
);
if ( getDialect() instanceof DB2Dialect ) {
/*
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
set type of TYPE_FORWARD_ONLY and db2 does not support it.
*/
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
}
else {
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
}
while ( scrollableResults.next() ) {
final Employee employee = (Employee) scrollableResults.get( 0 );
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
if ( "ENG1".equals( employee.getDept() ) ) {
assertThat( employee.getOtherEntities().size(), is( 2 ) );
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
if ( "test1".equals( otherEntity.id ) ) {
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
assertThat( otherEntity.employee, is( employee ) );
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
assertThat( otherEntity.employeeParent, is( employee ) );
}
else {
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
assertThat( otherEntity.employee, is( employee ) );
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
assertThat( Hibernate.isInitialized( otherEntity.employeeParent ), is( false ) );
}
}
}
else {
assertThat( employee.getOtherEntities().size(), is( 0 ) );
}
}
statelessSession.getTransaction().commit();
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
}
finally {
if ( scrollableResults != null ) {
scrollableResults.close();
}
if ( statelessSession.getTransaction().isActive() ) {
statelessSession.getTransaction().rollback();
}
statelessSession.close();
}
}
@Test
public void testScrollableWithSession() {
final StatisticsImplementor stats = sessionFactory().getStatistics();
stats.clear();
ScrollableResults scrollableResults = null;
final Session session = sessionFactory().openSession();
try {
session.beginTransaction();
Query<Employee> query = session.createQuery(
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
Employee.class
);
if ( getDialect() instanceof DB2Dialect ) {
/*
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
set type of TYPE_FORWARD_ONLY and db2 does not support it.
*/
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
}
else {
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
}
while ( scrollableResults.next() ) {
final Employee employee = (Employee) scrollableResults.get( 0 );
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
if ( "ENG1".equals( employee.getDept() ) ) {
assertThat( employee.getOtherEntities().size(), is( 2 ) );
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
if ( "test1".equals( otherEntity.id ) ) {
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
assertThat( otherEntity.employee, is( employee ) );
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
assertThat( otherEntity.employeeParent, is( employee ) );
}
else {
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
assertThat( otherEntity.employee, is( employee ) );
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
assertThat( Hibernate.isInitialized( otherEntity.employeeParent ), is( false ) );
}
}
}
else {
assertThat( employee.getOtherEntities().size(), is( 0 ) );
}
}
session.getTransaction().commit();
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
}
finally {
if ( scrollableResults != null ) {
scrollableResults.close();
}
if ( session.getTransaction().isActive() ) {
session.getTransaction().rollback();
}
session.close();
}
}
@Before
public void prepareTestData() {
inTransaction(
session -> {
Employee e1 = new Employee( "ENG1" );
Employee e2 = new Employee( "ENG2" );
OtherEntity other1 = new OtherEntity( "test1" );
OtherEntity other2 = new OtherEntity( "test2" );
e1.getOtherEntities().add( other1 );
e1.getOtherEntities().add( other2 );
e1.getParentOtherEntities().add( other1 );
e1.getParentOtherEntities().add( other2 );
other1.employee = e1;
other2.employee = e1;
other1.employeeParent = e1;
other2.employeeParent = e2;
session.persist( other1 );
session.persist( other2 );
session.persist( e1 );
session.persist( e2 );
}
);
}
@After
public void cleanUpTestData() {
inTransaction(
session -> {
session.createQuery( "delete from OtherEntity" ).executeUpdate();
session.createQuery( "delete from Employee" ).executeUpdate();
session.createQuery( "delete from EmployeeParent" ).executeUpdate();
}
);
}
@Entity(name = "EmployeeParent")
@Table(name = "EmployeeParent")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public static abstract class EmployeeParent {
@Id
private String dept;
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employeeParent", fetch = FetchType.LAZY)
protected Set<OtherEntity> parentOtherEntities = new HashSet<>();
public Set<OtherEntity> getParentOtherEntities() {
if ( parentOtherEntities == null ) {
parentOtherEntities = new LinkedHashSet();
}
return parentOtherEntities;
}
public void setOtherEntities(Set<OtherEntity> pParentOtherEntites) {
parentOtherEntities = pParentOtherEntites;
}
public String getDept() {
return dept;
}
protected void setDept(String dept) {
this.dept = dept;
}
}
@Entity(name = "Employee")
@Table(name = "Employee")
public static class Employee extends EmployeeParent {
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employee", fetch = FetchType.LAZY)
protected Set<OtherEntity> otherEntities = new HashSet<>();
public Employee(String dept) {
this();
setDept( dept );
}
protected Employee() {
// this form used by Hibernate
}
public Set<OtherEntity> getOtherEntities() {
if ( otherEntities == null ) {
otherEntities = new LinkedHashSet();
}
return otherEntities;
}
public void setOtherEntities(Set<OtherEntity> pOtherEntites) {
otherEntities = pOtherEntites;
}
}
@Entity(name = "OtherEntity")
@Table(name = "OtherEntity")
public static class OtherEntity {
@Id
private String id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "Employee_Id")
protected Employee employee = null;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "EmployeeParent_Id")
protected EmployeeParent employeeParent = null;
protected OtherEntity() {
// this form used by Hibernate
}
public OtherEntity(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
}

View File

@ -0,0 +1,135 @@
/*
* 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>.
*/
/*
* 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.test.manytomany.mapkey;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.MapKey;
import javax.persistence.Table;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
/**
* @author Andrea Boriero
*/
@TestForIssue(jiraKey = "HHH-4235")
@RequiresDialectFeature(DialectChecks.SupportSchemaCreation.class)
public class ManyToManyWithMaykeyAndSchemaDefinitionTest extends BaseCoreFunctionalTestCase {
@Override
protected void configure(Configuration configuration) {
configuration.setProperty( AvailableSettings.HBM2DDL_CREATE_SCHEMAS, "true" );
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { EntityA.class, EntityB.class };
}
@Before
public void setUp() {
inTransaction(
session -> {
EntityA entityA = new EntityA();
entityA.setId( 1L );
EntityB entityB = new EntityB();
entityB.setId( 1L );
entityA.setEntityBs( "B", entityB );
session.persist( entityB );
session.persist( entityA );
}
);
}
@Test
public void testRetrievingTheMapGeneratesACorrectlyQuery() {
inTransaction(
session -> {
EntityA entityA = session.get( EntityA.class, 1L );
Collection<EntityB> values = entityA.getEntityBMap().values();
assertThat( values.size(), is( 1 ) );
}
);
}
@Entity(name = "EntityA")
@Table(name = "entitya", schema = "myschema")
public static class EntityA {
@Id
private Long id;
private String name;
@ManyToMany
@MapKey(name = "id")
@JoinTable(name = "entitya_entityb", schema = "myschema", joinColumns = @JoinColumn(name = "entitya_pk"), inverseJoinColumns = @JoinColumn(name = "entityb_pk"))
private Map<String, EntityB> entityBMap = new HashMap<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setEntityBs(String key, EntityB entityB) {
this.entityBMap.put( key, entityB );
}
public Map<String, EntityB> getEntityBMap() {
return entityBMap;
}
}
@Entity(name = "EntityB")
@Table(name = "entityb", schema = "myschema")
public static class EntityB {
@Id
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
}