diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java index afec054ed1..f3b7b95b10 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java @@ -132,8 +132,7 @@ public abstract class AbstractEntityInsertAction extends EntityAction { LockMode.WRITE, isExecuted, getPersister(), - isVersionIncrementDisabled, - false + isVersionIncrementDisabled ); } diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/LazyGroup.java b/hibernate-core/src/main/java/org/hibernate/annotations/LazyGroup.java new file mode 100644 index 0000000000..cc683c0a6d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/LazyGroup.java @@ -0,0 +1,27 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * For use with bytecode-enhanced lazy-loading support. + *

+ * Identifies grouping for performing lazy attribute loading. By default all + * non-collection attributes are loaded in one group named {@code "DEFAULT"}. + * This annotation allows defining different groups of attributes to be + * initialized together when access one attribute in the group. + * + * @author Steve Ebersole + */ +@java.lang.annotation.Target({ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface LazyGroup { + String value(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/LazyPropertyInitializer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/LazyPropertyInitializer.java index fec68f021c..145d24b222 100755 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/LazyPropertyInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/LazyPropertyInitializer.java @@ -7,6 +7,7 @@ package org.hibernate.bytecode.enhance.spi; import java.io.Serializable; +import java.util.Set; import org.hibernate.engine.spi.SessionImplementor; @@ -20,7 +21,7 @@ public interface LazyPropertyInitializer { /** * Marker value for uninitialized properties. */ - public static final Serializable UNFETCHED_PROPERTY = new Serializable() { + Serializable UNFETCHED_PROPERTY = new Serializable() { @Override public String toString() { return ""; @@ -31,6 +32,11 @@ public interface LazyPropertyInitializer { } }; + interface InterceptorImplementor { + Set getInitializedLazyAttributeNames(); + void attributeInitialized(String name); + } + /** * Initialize the property, and return its new value. * @@ -40,6 +46,6 @@ public interface LazyPropertyInitializer { * * @return ? */ - public Object initializeLazyProperty(String fieldName, Object entity, SessionImplementor session); + Object initializeLazyProperty(String fieldName, Object entity, SessionImplementor session); } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeDescriptor.java new file mode 100644 index 0000000000..53dd06d9e6 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeDescriptor.java @@ -0,0 +1,102 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.bytecode.enhance.spi.interceptor; + +import org.hibernate.mapping.Property; +import org.hibernate.type.Type; + +/** + * Descriptor for an attribute which is enabled for bytecode lazy fetching + * + * @author Steve Ebersole + */ +public class LazyAttributeDescriptor { + public static LazyAttributeDescriptor from( + Property property, + int attributeIndex, + int lazyIndex) { + String fetchGroupName = property.getLazyGroup(); + if ( fetchGroupName == null ) { + fetchGroupName = property.getType().isCollectionType() + ? property.getName() + : "DEFAULT"; + } + + return new LazyAttributeDescriptor( + attributeIndex, + lazyIndex, + property.getName(), + property.getType(), + fetchGroupName + ); + } + + private final int attributeIndex; + private final int lazyIndex; + private final String name; + private final Type type; + private final String fetchGroupName; + + private LazyAttributeDescriptor( + int attributeIndex, + int lazyIndex, + String name, + Type type, + String fetchGroupName) { + assert attributeIndex >= lazyIndex; + this.attributeIndex = attributeIndex; + this.lazyIndex = lazyIndex; + this.name = name; + this.type = type; + this.fetchGroupName = fetchGroupName; + } + + /** + * Access to the index of the attribute in terms of its position in the entity persister + * + * @return The persister attribute index + */ + public int getAttributeIndex() { + return attributeIndex; + } + + /** + * Access to the index of the attribute in terms of its position withing the lazy attributes of the persister + * + * @return The persister lazy attribute index + */ + public int getLazyIndex() { + return lazyIndex; + } + + /** + * Access to the name of the attribute + * + * @return The attribute name + */ + public String getName() { + return name; + } + + /** + * Access to the attribute's type + * + * @return The attribute type + */ + public Type getType() { + return type; + } + + /** + * Access to the name of the fetch group to which the attribute belongs + * + * @return The name of the fetch group the attribute belongs to + */ + public String getFetchGroupName() { + return fetchGroupName; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java index 71168f762c..47b6c3e3af 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java @@ -9,14 +9,16 @@ package org.hibernate.bytecode.enhance.spi.interceptor; import java.io.Serializable; import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.Set; import org.hibernate.LockMode; -import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker; import org.hibernate.bytecode.enhance.spi.CollectionTracker; +import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; +import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer.InterceptorImplementor; import org.hibernate.bytecode.enhance.spi.interceptor.Helper.Consumer; import org.hibernate.bytecode.enhance.spi.interceptor.Helper.LazyInitializationWork; -import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.SelfDirtinessTracker; import org.hibernate.engine.spi.SessionImplementor; @@ -29,29 +31,30 @@ import org.jboss.logging.Logger; * Interceptor that loads attributes lazily * * @author Luis Barreiro + * @author Steve Ebersole */ -public class LazyAttributeLoadingInterceptor implements PersistentAttributeInterceptor, Consumer { +public class LazyAttributeLoadingInterceptor + implements PersistentAttributeInterceptor, Consumer, InterceptorImplementor { private static final Logger log = Logger.getLogger( LazyAttributeLoadingInterceptor.class ); - private transient SessionImplementor session; - - private final Set lazyFields; private final String entityName; + private final Set lazyFields; - private String sessionFactoryUuid; + private Set initializedLazyFields; + + private transient SessionImplementor session; private boolean allowLoadOutsideTransaction; + private String sessionFactoryUuid; - private final SimpleFieldTracker initializedFields = new SimpleFieldTracker(); - public LazyAttributeLoadingInterceptor(SessionImplementor session, Set lazyFields, String entityName) { - this.session = session; - this.lazyFields = lazyFields; + public LazyAttributeLoadingInterceptor( + String entityName, + Set lazyFields, + SessionImplementor session) { this.entityName = entityName; + this.lazyFields = lazyFields; - this.allowLoadOutsideTransaction = session.getFactory().getSessionFactoryOptions().isInitializeLazyStateOutsideTransactionsEnabled(); - if ( this.allowLoadOutsideTransaction ) { - this.sessionFactoryUuid = session.getFactory().getUuid(); - } + setSession( session ); } protected final Object intercept(Object target, String attributeName, Object value) { @@ -77,8 +80,6 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter final Object[] loadedState = null; // 2) does a row exist in the db for this entity? final boolean existsInDb = true; - // NOTE2: the final boolean is 'lazyPropertiesAreUnfetched' which is another - // place where a "single lazy fetch group" shows up session.getPersistenceContext().addEntity( target, Status.READ_ONLY, @@ -88,7 +89,6 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter LockMode.NONE, existsInDb, persister, - true, true ); } @@ -100,7 +100,6 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter session ); - initializedFields.add( attributeName ); takeCollectionSizeSnapshot( target, attributeName, loadedValue ); return loadedValue; } @@ -120,6 +119,12 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter public final void setSession(SessionImplementor session) { this.session = session; + if ( session != null && !allowLoadOutsideTransaction ) { + this.allowLoadOutsideTransaction = session.getFactory().getSessionFactoryOptions().isInitializeLazyStateOutsideTransactionsEnabled(); + if ( this.allowLoadOutsideTransaction ) { + this.sessionFactoryUuid = session.getFactory().getUuid(); + } + } } public final void unsetSession() { @@ -127,28 +132,35 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter } public boolean isAttributeLoaded(String fieldName) { - return lazyFields == null || !lazyFields.contains( fieldName ) || initializedFields.contains( fieldName ); + return !isLazyAttribute( fieldName ) || isInitializedLazyField( fieldName ); + } + + private boolean isLazyAttribute(String fieldName) { + return lazyFields == null || lazyFields.contains( fieldName ); + } + + private boolean isInitializedLazyField(String fieldName) { + return initializedLazyFields != null && initializedLazyFields.contains( fieldName ); } public boolean hasAnyUninitializedAttributes() { - if ( lazyFields != null ) { - for ( String fieldName : lazyFields ) { - if ( !initializedFields.contains( fieldName ) ) { - return true; - } + if ( lazyFields == null ) { + return false; + } + + if ( initializedLazyFields == null ) { + return true; + } + + for ( String fieldName : lazyFields ) { + if ( !initializedLazyFields.contains( fieldName ) ) { + return true; } } + return false; } - public void setLoaded(String attributeName) { - initializedFields.add( attributeName ); - } - - public String[] getiInitializedFields() { - return initializedFields.get(); - } - @Override public String toString() { return "LazyAttributeLoader(entityName=" + entityName + " ,lazyFields=" + lazyFields + ')'; @@ -174,7 +186,7 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter @Override public boolean writeBoolean(Object obj, String name, boolean oldValue, boolean newValue) { if ( lazyFields != null && lazyFields.contains( name ) ) { - initializedFields.add( name ); + attributeInitialized( name ); } return newValue; } @@ -187,7 +199,7 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter @Override public byte writeByte(Object obj, String name, byte oldValue, byte newValue) { if ( lazyFields != null && lazyFields.contains( name ) ) { - initializedFields.add( name ); + attributeInitialized( name ); } return newValue; } @@ -200,7 +212,7 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter @Override public char writeChar(Object obj, String name, char oldValue, char newValue) { if ( lazyFields != null && lazyFields.contains( name ) ) { - initializedFields.add( name ); + attributeInitialized( name ); } return newValue; } @@ -213,7 +225,7 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter @Override public short writeShort(Object obj, String name, short oldValue, short newValue) { if ( lazyFields != null && lazyFields.contains( name ) ) { - initializedFields.add( name ); + attributeInitialized( name ); } return newValue; } @@ -226,7 +238,7 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter @Override public int writeInt(Object obj, String name, int oldValue, int newValue) { if ( lazyFields != null && lazyFields.contains( name ) ) { - initializedFields.add( name ); + attributeInitialized( name ); } return newValue; } @@ -239,7 +251,7 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter @Override public float writeFloat(Object obj, String name, float oldValue, float newValue) { if ( lazyFields != null && lazyFields.contains( name ) ) { - initializedFields.add( name ); + attributeInitialized( name ); } return newValue; } @@ -252,7 +264,7 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter @Override public double writeDouble(Object obj, String name, double oldValue, double newValue) { if ( lazyFields != null && lazyFields.contains( name ) ) { - initializedFields.add( name ); + attributeInitialized( name ); } return newValue; } @@ -265,7 +277,7 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter @Override public long writeLong(Object obj, String name, long oldValue, long newValue) { if ( lazyFields != null && lazyFields.contains( name ) ) { - initializedFields.add( name ); + attributeInitialized( name ); } return newValue; } @@ -278,7 +290,7 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter @Override public Object writeObject(Object obj, String name, Object oldValue, Object newValue) { if ( lazyFields != null && lazyFields.contains( name ) ) { - initializedFields.add( name ); + attributeInitialized( name ); } return newValue; } @@ -297,4 +309,21 @@ public class LazyAttributeLoadingInterceptor implements PersistentAttributeInter public String getSessionFactoryUuid() { return sessionFactoryUuid; } + + @Override + public void attributeInitialized(String name) { + if ( !isLazyAttribute( name ) ) { + return; + } + if ( initializedLazyFields == null ) { + initializedLazyFields = new HashSet(); + } + initializedLazyFields.add( name ); + } + + @Override + public Set getInitializedLazyAttributeNames() { + return initializedLazyFields == null ? Collections.emptySet() : initializedLazyFields; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java new file mode 100644 index 0000000000..8480cd83f0 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java @@ -0,0 +1,141 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.bytecode.enhance.spi.interceptor; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; + +/** + * Information about all of the bytecode lazy attributes for an entity + * + * @author Steve Ebersole + */ +public class LazyAttributesMetadata implements Serializable { + /** + * Build a LazyFetchGroupMetadata based on the attributes defined for the + * PersistentClass + * + * @param mappedEntity The entity definition + * + * @return The built LazyFetchGroupMetadata + */ + public static LazyAttributesMetadata from(PersistentClass mappedEntity) { + final Map lazyAttributeDescriptorMap = new LinkedHashMap(); + final Map> fetchGroupToAttributesMap = new HashMap>(); + + int i = -1; + int x = 0; + final Iterator itr = mappedEntity.getPropertyClosureIterator(); + while ( itr.hasNext() ) { + i++; + final Property property = (Property) itr.next(); + if ( property.isLazy() ) { + final LazyAttributeDescriptor lazyAttributeDescriptor = LazyAttributeDescriptor.from( property, i, x++ ); + lazyAttributeDescriptorMap.put( lazyAttributeDescriptor.getName(), lazyAttributeDescriptor ); + + Set attributeSet = fetchGroupToAttributesMap.get( lazyAttributeDescriptor.getFetchGroupName() ); + if ( attributeSet == null ) { + attributeSet = new LinkedHashSet(); + fetchGroupToAttributesMap.put( lazyAttributeDescriptor.getFetchGroupName(), attributeSet ); + } + attributeSet.add( lazyAttributeDescriptor.getName() ); + } + } + + if ( lazyAttributeDescriptorMap.isEmpty() ) { + return new LazyAttributesMetadata( mappedEntity.getEntityName() ); + } + + for ( Map.Entry> entry : fetchGroupToAttributesMap.entrySet() ) { + entry.setValue( Collections.unmodifiableSet( entry.getValue() ) ); + } + + return new LazyAttributesMetadata( + mappedEntity.getEntityName(), + Collections.unmodifiableMap( lazyAttributeDescriptorMap ), + Collections.unmodifiableMap( fetchGroupToAttributesMap ) + ); + } + + public static LazyAttributesMetadata nonEnhanced(String entityName) { + return new LazyAttributesMetadata( entityName ); + } + + private final String entityName; + + private final Map lazyAttributeDescriptorMap; + private final Map> fetchGroupToAttributeMap; + + public LazyAttributesMetadata(String entityName) { + this( entityName, Collections.emptyMap(), Collections.>emptyMap() ); + } + + public LazyAttributesMetadata( + String entityName, + Map lazyAttributeDescriptorMap, + Map> fetchGroupToAttributeMap) { + this.entityName = entityName; + this.lazyAttributeDescriptorMap = lazyAttributeDescriptorMap; + this.fetchGroupToAttributeMap = fetchGroupToAttributeMap; + } + + public String getEntityName() { + return entityName; + } + + public boolean hasLazyAttributes() { + return !lazyAttributeDescriptorMap.isEmpty(); + } + + public int lazyAttributeCount() { + return lazyAttributeDescriptorMap.size(); + } + + public Set getLazyAttributeNames() { + return lazyAttributeDescriptorMap.keySet(); + } + + public Set getFetchGroupNames() { + return fetchGroupToAttributeMap.keySet(); + } + + public boolean isLazyAttribute(String attributeName) { + return lazyAttributeDescriptorMap.containsKey( attributeName ); + } + + public String getFetchGroupName(String attributeName) { + return lazyAttributeDescriptorMap.get( attributeName ).getFetchGroupName(); + } + + public Set getAttributesInFetchGroup(String fetchGroupName) { + return fetchGroupToAttributeMap.get( fetchGroupName ); + } + + public List getFetchGroupAttributeDescriptors(String groupName) { + final List list = new ArrayList(); + for ( String attributeName : fetchGroupToAttributeMap.get( groupName ) ) { + list.add( lazyAttributeDescriptorMap.get( attributeName ) ); + } + return list; + } + + public Set getAttributesInSameFetchGroup(String attributeName) { + final String fetchGroupName = getFetchGroupName( attributeName ); + return getAttributesInFetchGroup( fetchGroupName ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyFetchGroupMetadata.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyFetchGroupMetadata.java new file mode 100644 index 0000000000..f0a468d1f9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyFetchGroupMetadata.java @@ -0,0 +1,21 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.bytecode.enhance.spi.interceptor; + +/** + * Information about a particular bytecode lazy attribute grouping. + * + * @author Steve Ebersole + */ +public interface LazyFetchGroupMetadata { + /** + * Access to the name of the fetch group. + * + * @return The fetch group name + */ + String getName(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/BytecodeEnhancementMetadata.java b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/BytecodeEnhancementMetadata.java index 76bb75203f..055e152ef4 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/BytecodeEnhancementMetadata.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/BytecodeEnhancementMetadata.java @@ -9,6 +9,7 @@ package org.hibernate.bytecode.spi; import java.util.Set; import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributesMetadata; import org.hibernate.engine.spi.SessionImplementor; /** @@ -32,11 +33,12 @@ public interface BytecodeEnhancementMetadata { */ boolean isEnhancedForLazyLoading(); + LazyAttributesMetadata getLazyAttributesMetadata(); + /** * Build and inject an interceptor instance into the enhanced entity. * * @param entity The entity into which built interceptor should be injected - * @param uninitializedFieldNames The name of fields marked as lazy * @param session The session to which the entity instance belongs. * * @return The built and injected interceptor @@ -45,7 +47,6 @@ public interface BytecodeEnhancementMetadata { */ LazyAttributeLoadingInterceptor injectInterceptor( Object entity, - Set uninitializedFieldNames, SessionImplementor session) throws NotInstrumentedException; /** @@ -58,4 +59,6 @@ public interface BytecodeEnhancementMetadata { * @throws NotInstrumentedException Thrown if {@link #isEnhancedForLazyLoading()} returns {@code false} */ LazyAttributeLoadingInterceptor extractInterceptor(Object entity) throws NotInstrumentedException; + + boolean hasUnFetchedAttributes(Object entity); } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/CacheEntry.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/CacheEntry.java index 5ba7666b17..dc2ac5de93 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/CacheEntry.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/CacheEntry.java @@ -20,7 +20,7 @@ public interface CacheEntry extends Serializable { * * @return true/false */ - public boolean isReferenceEntry(); + boolean isReferenceEntry(); /** * Hibernate stores all entries pertaining to a given entity hierarchy in a single region. This attribute @@ -28,21 +28,14 @@ public interface CacheEntry extends Serializable { * * @return The entry's exact entity type. */ - public String getSubclass(); + String getSubclass(); /** * Retrieves the version (optimistic locking) associated with this cache entry. * * @return The version of the entity represented by this entry */ - public Object getVersion(); - - /** - * Does the represented data contain any un-fetched attribute values? - * - * @return true/false - */ - public boolean areLazyPropertiesUnfetched(); + Object getVersion(); /** * Get the underlying disassembled state @@ -53,6 +46,5 @@ public interface CacheEntry extends Serializable { * * @return The disassembled state */ - public Serializable[] getDisassembledState(); - + Serializable[] getDisassembledState(); } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/ReferenceCacheEntryImpl.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/ReferenceCacheEntryImpl.java index c66bdf02f3..b1cca8e3a2 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/ReferenceCacheEntryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/ReferenceCacheEntryImpl.java @@ -60,12 +60,6 @@ public class ReferenceCacheEntryImpl implements CacheEntry { return null; } - @Override - public boolean areLazyPropertiesUnfetched() { - // reference data cannot define lazy attributes - return false; - } - @Override public Serializable[] getDisassembledState() { // reference data is not disassembled into the cache diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/StandardCacheEntryImpl.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/StandardCacheEntryImpl.java index e10ba3a9ff..a539cb64fc 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/StandardCacheEntryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/StandardCacheEntryImpl.java @@ -7,6 +7,7 @@ package org.hibernate.cache.spi.entry; import java.io.Serializable; +import java.util.Set; import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; @@ -19,6 +20,7 @@ import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.PreLoadEvent; import org.hibernate.event.spi.PreLoadEventListener; import org.hibernate.internal.util.collections.ArrayHelper; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.type.TypeHelper; @@ -30,7 +32,6 @@ import org.hibernate.type.TypeHelper; public class StandardCacheEntryImpl implements CacheEntry { private final Serializable[] disassembledState; private final String subclass; - private final boolean lazyPropertiesAreUnfetched; private final Object version; /** @@ -38,7 +39,6 @@ public class StandardCacheEntryImpl implements CacheEntry { * * @param state The extracted state * @param persister The entity persister - * @param unfetched Are any values present in state unfetched? * @param version The current version (if versioned) * @param session The originating session * @param owner The owner @@ -48,11 +48,9 @@ public class StandardCacheEntryImpl implements CacheEntry { public StandardCacheEntryImpl( final Object[] state, final EntityPersister persister, - final boolean unfetched, final Object version, final SessionImplementor session, - final Object owner) - throws HibernateException { + final Object owner) throws HibernateException { // disassembled state gets put in a new array (we write to cache by value!) this.disassembledState = TypeHelper.disassemble( state, @@ -62,14 +60,12 @@ public class StandardCacheEntryImpl implements CacheEntry { owner ); subclass = persister.getEntityName(); - lazyPropertiesAreUnfetched = unfetched || !persister.isLazyPropertiesCacheable(); this.version = version; } - StandardCacheEntryImpl(Serializable[] state, String subclass, boolean unfetched, Object version) { + StandardCacheEntryImpl(Serializable[] state, String subclass, Object version) { this.disassembledState = state; this.subclass = subclass; - this.lazyPropertiesAreUnfetched = unfetched; this.version = version; } @@ -93,11 +89,6 @@ public class StandardCacheEntryImpl implements CacheEntry { return subclass; } - @Override - public boolean areLazyPropertiesUnfetched() { - return lazyPropertiesAreUnfetched; - } - @Override public Object getVersion() { return version; diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/StructuredCacheEntry.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/StructuredCacheEntry.java index a81d62eddc..d62cf299f2 100755 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/StructuredCacheEntry.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/StructuredCacheEntry.java @@ -9,6 +9,7 @@ package org.hibernate.cache.spi.entry; import java.io.Serializable; import java.util.HashMap; import java.util.Map; +import java.util.Set; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.persister.entity.EntityPersister; @@ -21,6 +22,9 @@ import org.hibernate.persister.entity.EntityPersister; * @author Steve Ebersole */ public class StructuredCacheEntry implements CacheEntryStructure { + public static final String SUBCLASS_KEY = "_subclass"; + public static final String VERSION_KEY = "_version"; + private EntityPersister persister; /** @@ -33,18 +37,18 @@ public class StructuredCacheEntry implements CacheEntryStructure { } @Override + @SuppressWarnings("unchecked") public Object destructure(Object structured, SessionFactoryImplementor factory) { final Map map = (Map) structured; - final boolean lazyPropertiesUnfetched = (Boolean) map.get( "_lazyPropertiesUnfetched" ); - final String subclass = (String) map.get( "_subclass" ); - final Object version = map.get( "_version" ); + final String subclass = (String) map.get( SUBCLASS_KEY ); + final Object version = map.get( VERSION_KEY ); final EntityPersister subclassPersister = factory.getEntityPersister( subclass ); final String[] names = subclassPersister.getPropertyNames(); final Serializable[] state = new Serializable[names.length]; for ( int i = 0; i < names.length; i++ ) { state[i] = (Serializable) map.get( names[i] ); } - return new StandardCacheEntryImpl( state, subclass, lazyPropertiesUnfetched, version ); + return new StandardCacheEntryImpl( state, subclass, version ); } @Override @@ -53,9 +57,8 @@ public class StructuredCacheEntry implements CacheEntryStructure { final CacheEntry entry = (CacheEntry) item; final String[] names = persister.getPropertyNames(); final Map map = new HashMap( names.length + 3, 1f ); - map.put( "_subclass", entry.getSubclass() ); - map.put( "_version", entry.getVersion() ); - map.put( "_lazyPropertiesUnfetched", entry.areLazyPropertiesUnfetched() ); + map.put( SUBCLASS_KEY, entry.getSubclass() ); + map.put( VERSION_KEY, entry.getVersion() ); for ( int i=0; i */ public final class MutableEntityEntry extends AbstractEntityEntry { - /** * @deprecated the tenantId and entityMode parameters where removed: this constructor accepts but ignores them. * Use the other constructor! @@ -45,10 +44,10 @@ public final class MutableEntityEntry extends AbstractEntityEntry { final EntityMode entityMode, final String tenantId, final boolean disableVersionIncrement, - final boolean lazyPropertiesAreUnfetched, final PersistenceContext persistenceContext) { this( status, loadedState, rowId, id, version, lockMode, existsInDatabase, - persister,disableVersionIncrement, lazyPropertiesAreUnfetched, persistenceContext ); + persister,disableVersionIncrement, persistenceContext + ); } public MutableEntityEntry( @@ -61,11 +60,10 @@ public final class MutableEntityEntry extends AbstractEntityEntry { final boolean existsInDatabase, final EntityPersister persister, final boolean disableVersionIncrement, - final boolean lazyPropertiesAreUnfetched, final PersistenceContext persistenceContext) { - super( status, loadedState, rowId, id, version, lockMode, existsInDatabase, persister, - disableVersionIncrement, lazyPropertiesAreUnfetched, persistenceContext ); + disableVersionIncrement, persistenceContext + ); } /** @@ -84,15 +82,12 @@ public final class MutableEntityEntry extends AbstractEntityEntry { final LockMode lockMode, final boolean existsInDatabase, final boolean isBeingReplicated, - final boolean loadedWithLazyPropertiesUnfetched, final PersistenceContext persistenceContext) { - super( factory, entityName, id, status, previousStatus, loadedState, deletedState, - version, lockMode, existsInDatabase, isBeingReplicated, loadedWithLazyPropertiesUnfetched, - persistenceContext ); + version, lockMode, existsInDatabase, isBeingReplicated, persistenceContext + ); } - /** * Custom deserialization routine used during deserialization of a * Session/PersistenceContext for increased performance. @@ -124,7 +119,6 @@ public final class MutableEntityEntry extends AbstractEntityEntry { LockMode.valueOf( (String) ois.readObject() ), ois.readBoolean(), ois.readBoolean(), - ois.readBoolean(), persistenceContext ); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/MutableEntityEntryFactory.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/MutableEntityEntryFactory.java index 34b6cf0488..909a2f2f04 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/MutableEntityEntryFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/MutableEntityEntryFactory.java @@ -8,6 +8,7 @@ package org.hibernate.engine.internal; import java.io.Serializable; +import java.util.Set; import org.hibernate.LockMode; import org.hibernate.engine.spi.EntityEntry; @@ -43,7 +44,6 @@ public class MutableEntityEntryFactory implements EntityEntryFactory { boolean existsInDatabase, EntityPersister persister, boolean disableVersionIncrement, - boolean lazyPropertiesAreUnfetched, PersistenceContext persistenceContext) { return new MutableEntityEntry( status, @@ -55,7 +55,6 @@ public class MutableEntityEntryFactory implements EntityEntryFactory { existsInDatabase, persister, disableVersionIncrement, - lazyPropertiesAreUnfetched, persistenceContext ); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java index a04c712a37..185629f469 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java @@ -455,8 +455,7 @@ public class StatefulPersistenceContext implements PersistenceContext { final LockMode lockMode, final boolean existsInDatabase, final EntityPersister persister, - final boolean disableVersionIncrement, - boolean lazyPropertiesAreUnfetched) { + final boolean disableVersionIncrement) { addEntity( entityKey, entity ); return addEntry( entity, @@ -468,8 +467,7 @@ public class StatefulPersistenceContext implements PersistenceContext { lockMode, existsInDatabase, persister, - disableVersionIncrement, - lazyPropertiesAreUnfetched + disableVersionIncrement ); } @@ -484,9 +482,7 @@ public class StatefulPersistenceContext implements PersistenceContext { final LockMode lockMode, final boolean existsInDatabase, final EntityPersister persister, - final boolean disableVersionIncrement, - boolean lazyPropertiesAreUnfetched) { - + final boolean disableVersionIncrement) { final EntityEntry e; if( (entity instanceof ManagedEntity) && ((ManagedEntity) entity).$$_hibernate_getEntityEntry() != null && status == Status.READ_ONLY) { @@ -505,7 +501,6 @@ public class StatefulPersistenceContext implements PersistenceContext { existsInDatabase, persister, disableVersionIncrement, - lazyPropertiesAreUnfetched, this ); } @@ -1382,8 +1377,7 @@ public class StatefulPersistenceContext implements PersistenceContext { oldEntry.getLockMode(), oldEntry.isExistsInDatabase(), oldEntry.getPersister(), - oldEntry.isBeingReplicated(), - oldEntry.isLoadedWithLazyPropertiesUnfetched() + oldEntry.isBeingReplicated() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java index ac486ddbe6..bae3915841 100755 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java @@ -67,7 +67,6 @@ public final class TwoPhaseLoad { * @param rowId The rowId for the entity * @param object An optional instance for the entity being loaded * @param lockMode The lock mode - * @param lazyPropertiesAreUnFetched Whether properties defined as lazy are yet un-fetched * @param session The Session */ public static void postHydrate( @@ -77,7 +76,6 @@ public final class TwoPhaseLoad { final Object rowId, final Object object, final LockMode lockMode, - final boolean lazyPropertiesAreUnFetched, final SessionImplementor session) { final Object version = Versioning.getVersion( values, persister ); session.getPersistenceContext().addEntry( @@ -90,8 +88,7 @@ public final class TwoPhaseLoad { lockMode, true, persister, - false, - lazyPropertiesAreUnFetched + false ); if ( version != null && LOG.isTraceEnabled() ) { @@ -264,11 +261,7 @@ public final class TwoPhaseLoad { persistenceContext.setEntryStatus( entityEntry, Status.MANAGED ); } - persister.afterInitialize( - entity, - entityEntry.isLoadedWithLazyPropertiesUnfetched(), - session - ); + persister.afterInitialize( entity, session ); if ( debugEnabled ) { LOG.debugf( @@ -317,11 +310,13 @@ public final class TwoPhaseLoad { } private static boolean useMinimalPuts(SessionImplementor session, EntityEntry entityEntry) { - return ( session.getFactory().getSettings().isMinimalPutsEnabled() - && session.getCacheMode()!=CacheMode.REFRESH ) - || ( entityEntry.getPersister().hasLazyProperties() - && entityEntry.isLoadedWithLazyPropertiesUnfetched() - && entityEntry.getPersister().isLazyPropertiesCacheable() ); + if ( session.getFactory().getSessionFactoryOptions().isMinimalPutsEnabled() ) { + return session.getCacheMode() != CacheMode.REFRESH; + } + else { + return entityEntry.getPersister().hasLazyProperties() + && entityEntry.getPersister().isLazyPropertiesCacheable(); + } } /** @@ -335,7 +330,6 @@ public final class TwoPhaseLoad { * @param object The entity instance * @param persister The entity persister * @param lockMode The lock mode - * @param lazyPropertiesAreUnFetched Are lazy properties still un-fetched? * @param session The Session */ public static void addUninitializedEntity( @@ -343,7 +337,6 @@ public final class TwoPhaseLoad { final Object object, final EntityPersister persister, final LockMode lockMode, - final boolean lazyPropertiesAreUnFetched, final SessionImplementor session) { session.getPersistenceContext().addEntity( object, @@ -354,8 +347,7 @@ public final class TwoPhaseLoad { lockMode, true, persister, - false, - lazyPropertiesAreUnFetched + false ); } @@ -366,7 +358,6 @@ public final class TwoPhaseLoad { * @param object The entity instance * @param persister The entity persister * @param lockMode The lock mode - * @param lazyPropertiesAreUnFetched Are lazy properties still un-fetched? * @param version The version * @param session The Session */ @@ -375,7 +366,6 @@ public final class TwoPhaseLoad { final Object object, final EntityPersister persister, final LockMode lockMode, - final boolean lazyPropertiesAreUnFetched, final Object version, final SessionImplementor session) { session.getPersistenceContext().addEntity( @@ -387,8 +377,7 @@ public final class TwoPhaseLoad { lockMode, true, persister, - false, - lazyPropertiesAreUnFetched - ); + false + ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntry.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntry.java index ede196d01c..fadbfc1bf3 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntry.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntry.java @@ -9,6 +9,7 @@ package org.hibernate.engine.spi; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.util.Set; import org.hibernate.LockMode; import org.hibernate.persister.entity.EntityPersister; @@ -124,8 +125,6 @@ public interface EntityEntry { @Override String toString(); - boolean isLoadedWithLazyPropertiesUnfetched(); - /** * Custom serialization routine used during serialization of a * Session/PersistenceContext for increased performance. diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntryFactory.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntryFactory.java index eb1ae498f2..8d75f371e2 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntryFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntryFactory.java @@ -31,6 +31,5 @@ public interface EntityEntryFactory extends Serializable { final boolean existsInDatabase, final EntityPersister persister, final boolean disableVersionIncrement, - final boolean lazyPropertiesAreUnfetched, final PersistenceContext persistenceContext); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java index e9415d36cc..a99f10a694 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java @@ -10,6 +10,7 @@ import java.io.Serializable; import java.util.Collection; import java.util.HashSet; import java.util.Map; +import java.util.Set; import org.hibernate.HibernateException; import org.hibernate.LockMode; @@ -235,7 +236,7 @@ public interface PersistenceContext { /** * Adds an entity to the internal caches. */ - public EntityEntry addEntity( + EntityEntry addEntity( final Object entity, final Status status, final Object[] loadedState, @@ -244,8 +245,7 @@ public interface PersistenceContext { final LockMode lockMode, final boolean existsInDatabase, final EntityPersister persister, - final boolean disableVersionIncrement, - boolean lazyPropertiesAreUnfetched); + final boolean disableVersionIncrement); /** * Generates an appropriate EntityEntry instance and adds it @@ -261,8 +261,7 @@ public interface PersistenceContext { final LockMode lockMode, final boolean existsInDatabase, final EntityPersister persister, - final boolean disableVersionIncrement, - boolean lazyPropertiesAreUnfetched); + final boolean disableVersionIncrement); /** * Is the given collection associated with this persistence context? diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistentAttributeInterceptor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistentAttributeInterceptor.java index ca3d2e26c0..38bf8090be 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistentAttributeInterceptor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistentAttributeInterceptor.java @@ -6,10 +6,12 @@ */ package org.hibernate.engine.spi; +import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer.InterceptorImplementor; + /** * @author Steve Ebersole */ -public interface PersistentAttributeInterceptor { +public interface PersistentAttributeInterceptor extends InterceptorImplementor { public boolean readBoolean(Object obj, String name, boolean oldValue); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractReassociateEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractReassociateEventListener.java index aaad4f8933..f4527660f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractReassociateEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractReassociateEventListener.java @@ -76,8 +76,7 @@ public abstract class AbstractReassociateEventListener implements Serializable { LockMode.NONE, true, persister, - false, - true //will be ignored, using the existing Entry instead + false ); new OnLockVisitor( source, id, object ).process( object, persister ); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java index b069f01a6c..f99eaf0728 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java @@ -23,6 +23,7 @@ import org.hibernate.engine.spi.CascadingAction; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityEntryExtraState; import org.hibernate.engine.spi.EntityKey; +import org.hibernate.engine.spi.SelfDirtinessTracker; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.Status; import org.hibernate.event.spi.EventSource; @@ -96,6 +97,10 @@ public abstract class AbstractSaveEventListener extends AbstractReassociateEvent Object anything, EventSource source, boolean requiresImmediateIdAccess) { + if ( entity instanceof SelfDirtinessTracker ) { + ( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes(); + } + EntityPersister persister = source.getEntityPersister( entityName, entity ); Serializable generatedId = persister.getIdentifierGenerator().generate( source, entity ); if ( generatedId == null ) { @@ -241,7 +246,6 @@ public abstract class AbstractSaveEventListener extends AbstractReassociateEvent LockMode.WRITE, useIdentityColumn, persister, - false, false ); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java index 22daba8b95..a8b1665a8c 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java @@ -113,7 +113,6 @@ public class DefaultDeleteEventListener implements DeleteEventListener { LockMode.NONE, true, persister, - false, false ); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java index c5fee134be..74d22a4efd 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java @@ -675,7 +675,6 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i entity, subclassPersister, LockMode.NONE, - entry.areLazyPropertiesUnfetched(), entry.getVersion(), session ); @@ -728,10 +727,9 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i LockMode.NONE, true, subclassPersister, - false, - entry.areLazyPropertiesUnfetched() + false ); - subclassPersister.afterInitialize( entity, entry.areLazyPropertiesUnfetched(), session ); + subclassPersister.afterInitialize( entity, session ); persistenceContext.initializeNonLazyCollections(); //PostLoad is needed for EJB3 @@ -775,7 +773,6 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i result, subclassPersister, LockMode.NONE, - entry.areLazyPropertiesUnfetched(), entry.getVersion(), session ); @@ -822,10 +819,9 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i LockMode.NONE, true, subclassPersister, - false, - entry.areLazyPropertiesUnfetched() + false ); - subclassPersister.afterInitialize( result, entry.areLazyPropertiesUnfetched(), session ); + subclassPersister.afterInitialize( result, session ); persistenceContext.initializeNonLazyCollections(); // upgrade the lock if necessary: //lock(result, lockMode); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultReplicateEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultReplicateEventListener.java index 1fa2cbe23f..684a16e32f 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultReplicateEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultReplicateEventListener.java @@ -191,8 +191,7 @@ public class DefaultReplicateEventListener extends AbstractSaveEventListener imp LockMode.NONE, true, persister, - true, - false + true ); cascadeAfterReplicate( entity, persister, replicationMode, source ); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java index e804ab0917..e37e10b099 100755 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java @@ -313,8 +313,7 @@ public class DefaultSaveOrUpdateEventListener extends AbstractSaveEventListener LockMode.NONE, true, persister, - false, - true // assume true, since we don't really know, and it doesn't matter + false ); persister.afterReassociate( entity, source ); diff --git a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java index 51bc9b9a2b..a5953be1cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -1697,8 +1697,9 @@ public abstract class Loader { final Loadable persister = (Loadable) getFactory().getEntityPersister( instanceEntityName ); if ( LOG.isTraceEnabled() ) { - LOG.tracev( - "Initializing object from ResultSet: {0}", MessageHelper.infoString( + LOG.tracef( + "Initializing object from ResultSet: %s", + MessageHelper.infoString( persister, id, getFactory() @@ -1706,7 +1707,7 @@ public abstract class Loader { ); } - boolean eagerPropertyFetch = isEagerPropertyFetchEnabled( i ); + boolean fetchAllPropertiesRequested = isEagerPropertyFetchEnabled( i ); // add temp entry so that the next step is circular-reference // safe - only needed because some types don't take proper @@ -1716,7 +1717,6 @@ public abstract class Loader { object, persister, lockMode, - !eagerPropertyFetch, session ); @@ -1731,7 +1731,7 @@ public abstract class Loader { object, rootPersister, cols, - eagerPropertyFetch, + fetchAllPropertiesRequested, session ); @@ -1768,7 +1768,6 @@ public abstract class Loader { rowId, object, lockMode, - !eagerPropertyFetch, session ); diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/EntityReferenceInitializerImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/EntityReferenceInitializerImpl.java index a766ce84cb..f757a4ed03 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/EntityReferenceInitializerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/EntityReferenceInitializerImpl.java @@ -296,7 +296,6 @@ public class EntityReferenceInitializerImpl implements EntityReferenceInitialize entityInstance, concreteEntityPersister, lockModeToAcquire, - !context.getLoadPlan().areLazyAttributesForceFetched(), context.getSession() ); @@ -373,7 +372,6 @@ public class EntityReferenceInitializerImpl implements EntityReferenceInitialize rowId, entityInstance, lockModeToAcquire, - !context.getLoadPlan().areLazyAttributesForceFetched(), context.getSession() ); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java index 380c9972db..ebf86b44e9 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java @@ -43,6 +43,7 @@ public class Property implements Serializable, MetaAttributable { private ValueGeneration valueGenerationStrategy; private String propertyAccessorName; private boolean lazy; + private String lazyGroup; private boolean optional; private java.util.Map metaAttributes; private PersistentClass persistentClass; @@ -257,7 +258,15 @@ public class Property implements Serializable, MetaAttributable { } return lazy; } - + + public String getLazyGroup() { + return lazyGroup; + } + + public void setLazyGroup(String lazyGroup) { + this.lazyGroup = lazyGroup; + } + public boolean isOptimisticLocked() { return optimisticLocked; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index ddcf61e043..b252ebbad0 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -33,8 +33,10 @@ import org.hibernate.QueryException; import org.hibernate.Session; import org.hibernate.StaleObjectStateException; import org.hibernate.StaleStateException; -import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeDescriptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributesMetadata; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; @@ -65,6 +67,7 @@ import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.Mapping; import org.hibernate.engine.spi.PersistenceContext.NaturalIdHelper; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.ValueInclusion; @@ -160,8 +163,6 @@ public abstract class AbstractEntityPersister private final boolean hasSubselectLoadableCollections; protected final String rowIdName; - private final Set lazyProperties; - // The optional SQL string defined in the where attribute private final String sqlWhereString; private final String sqlWhereStringTemplate; @@ -227,7 +228,7 @@ public abstract class AbstractEntityPersister // SQL strings private String sqlVersionSelectString; private String sqlSnapshotSelectString; - private String sqlLazySelectString; + private Map sqlLazySelectStringsByFetchGroup; private String sqlIdentityInsertString; private String sqlUpdateByRowIdString; @@ -379,8 +380,8 @@ public abstract class AbstractEntityPersister return sqlSnapshotSelectString; } - protected String getSQLLazySelectString() { - return sqlLazySelectString; + protected String getSQLLazySelectString(String fetchGroup) { + return sqlLazySelectStringsByFetchGroup.get( fetchGroup ); } protected String[] getSQLDeleteStrings() { @@ -590,7 +591,6 @@ public abstract class AbstractEntityPersister propertyColumnInsertable = new boolean[hydrateSpan][]; HashSet thisClassProperties = new HashSet(); - lazyProperties = new HashSet(); ArrayList lazyNames = new ArrayList(); ArrayList lazyNumbers = new ArrayList(); ArrayList lazyTypes = new ArrayList(); @@ -635,7 +635,6 @@ public abstract class AbstractEntityPersister propertyColumnAliases[i] = colAliases; if ( lazyAvailable && prop.isLazy() ) { - lazyProperties.add( prop.getName() ); lazyNames.add( prop.getName() ); lazyNumbers.add( i ); lazyTypes.add( prop.getValue().getType() ); @@ -844,54 +843,68 @@ public abstract class AbstractEntityPersister Template.renderWhereStringTemplate( string, factory.getDialect(), factory.getSqlFunctionRegistry() ); } - protected String generateLazySelectString() { - - if ( !entityMetamodel.hasLazyProperties() ) { - return null; + protected Map generateLazySelectStringsByFetchGroup() { + final BytecodeEnhancementMetadata enhancementMetadata = entityMetamodel.getBytecodeEnhancementMetadata(); + if ( !enhancementMetadata.isEnhancedForLazyLoading() + || !enhancementMetadata.getLazyAttributesMetadata().hasLazyAttributes() ) { + return Collections.emptyMap(); } - HashSet tableNumbers = new HashSet(); - ArrayList columnNumbers = new ArrayList(); - ArrayList formulaNumbers = new ArrayList(); - for ( String lazyPropertyName : lazyPropertyNames ) { - // all this only really needs to consider properties - // of this class, not its subclasses, but since we - // are reusing code used for sequential selects, we - // use the subclass closure - int propertyNumber = getSubclassPropertyIndex( lazyPropertyName ); + Map result = new HashMap(); - int tableNumber = getSubclassPropertyTableNumber( propertyNumber ); - tableNumbers.add( tableNumber ); + final LazyAttributesMetadata lazyAttributesMetadata = enhancementMetadata.getLazyAttributesMetadata(); + for ( String groupName : lazyAttributesMetadata.getFetchGroupNames() ) { + HashSet tableNumbers = new HashSet(); + ArrayList columnNumbers = new ArrayList(); + ArrayList formulaNumbers = new ArrayList(); - int[] colNumbers = subclassPropertyColumnNumberClosure[propertyNumber]; - for ( int colNumber : colNumbers ) { - if ( colNumber != -1 ) { - columnNumbers.add( colNumber ); + for ( LazyAttributeDescriptor lazyAttributeDescriptor : + lazyAttributesMetadata.getFetchGroupAttributeDescriptors( groupName ) ) { + // all this only really needs to consider properties + // of this class, not its subclasses, but since we + // are reusing code used for sequential selects, we + // use the subclass closure + int propertyNumber = getSubclassPropertyIndex( lazyAttributeDescriptor.getName() ); + + int tableNumber = getSubclassPropertyTableNumber( propertyNumber ); + tableNumbers.add( tableNumber ); + + int[] colNumbers = subclassPropertyColumnNumberClosure[propertyNumber]; + for ( int colNumber : colNumbers ) { + if ( colNumber != -1 ) { + columnNumbers.add( colNumber ); + } + } + int[] formNumbers = subclassPropertyFormulaNumberClosure[propertyNumber]; + for ( int formNumber : formNumbers ) { + if ( formNumber != -1 ) { + formulaNumbers.add( formNumber ); + } } } - int[] formNumbers = subclassPropertyFormulaNumberClosure[propertyNumber]; - for ( int formNumber : formNumbers ) { - if ( formNumber != -1 ) { - formulaNumbers.add( formNumber ); - } + + if ( columnNumbers.size() == 0 && formulaNumbers.size() == 0 ) { + // only one-to-one is lazy fetched + continue; } + + result.put( + groupName, + renderSelect( + ArrayHelper.toIntArray( tableNumbers ), + ArrayHelper.toIntArray( columnNumbers ), + ArrayHelper.toIntArray( formulaNumbers ) + ) + ); } - if ( columnNumbers.size() == 0 && formulaNumbers.size() == 0 ) { - // only one-to-one is lazy fetched - return null; - } - - return renderSelect( - ArrayHelper.toIntArray( tableNumbers ), - ArrayHelper.toIntArray( columnNumbers ), - ArrayHelper.toIntArray( formulaNumbers ) - ); - + return result; } public Object initializeLazyProperty(String fieldName, Object entity, SessionImplementor session) { final EntityEntry entry = session.getPersistenceContext().getEntry( entity ); + final InterceptorImplementor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor(); + assert interceptor != null : "Expecting bytecode interceptor to be non-null"; if ( hasCollections() ) { final Type type = getPropertyType( fieldName ); @@ -919,6 +932,7 @@ public abstract class AbstractEntityPersister // Initialize it session.initializeCollection( collection, false ); + interceptor.attributeInitialized( fieldName ); if ( collectionType.isArrayType() ) { session.getPersistenceContext().addCollectionHolder( collection ); @@ -944,16 +958,17 @@ public abstract class AbstractEntityPersister ); } - if ( session.getCacheMode().isGetEnabled() && hasCache() ) { + if ( session.getCacheMode().isGetEnabled() && hasCache() && isLazyPropertiesCacheable() ) { final EntityRegionAccessStrategy cache = getCacheAccessStrategy(); final Object cacheKey = cache.generateCacheKey(id, this, session.getFactory(), session.getTenantIdentifier() ); final Object ce = CacheHelper.fromSharedCache( session, cacheKey, cache ); if ( ce != null ) { final CacheEntry cacheEntry = (CacheEntry) getCacheEntryStructure().destructure( ce, factory ); - if ( !cacheEntry.areLazyPropertiesUnfetched() ) { - //note early exit here: - return initializeLazyPropertiesFromCache( fieldName, entity, session, entry, cacheEntry ); - } + final Object initializedValue = initializeLazyPropertiesFromCache( fieldName, entity, session, entry, cacheEntry ); + interceptor.attributeInitialized( fieldName ); + + // NOTE EARLY EXIT!!! + return initializedValue; } } @@ -993,14 +1008,26 @@ public abstract class AbstractEntityPersister throw new AssertionFailure( "no lazy properties" ); } + final InterceptorImplementor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor(); + assert interceptor != null : "Expecting bytecode interceptor to be non-null"; + LOG.trace( "Initializing lazy properties from datastore" ); - try { + final String fetchGroup = getEntityMetamodel().getBytecodeEnhancementMetadata() + .getLazyAttributesMetadata() + .getFetchGroupName( fieldName ); + final List fetchGroupAttributeDescriptors = getEntityMetamodel().getBytecodeEnhancementMetadata() + .getLazyAttributesMetadata() + .getFetchGroupAttributeDescriptors( fetchGroup ); + final Set initializedLazyAttributeNames = interceptor.getInitializedLazyAttributeNames(); + + final String lazySelect = getSQLLazySelectString( fetchGroup ); + + try { Object result = null; PreparedStatement ps = null; try { - final String lazySelect = getSQLLazySelectString(); ResultSet rs = null; try { if ( lazySelect != null ) { @@ -1015,16 +1042,31 @@ public abstract class AbstractEntityPersister rs.next(); } final Object[] snapshot = entry.getLoadedState(); - for ( int j = 0; j < lazyPropertyNames.length; j++ ) { - Object propValue = lazyPropertyTypes[j].nullSafeGet( + for ( LazyAttributeDescriptor fetchGroupAttributeDescriptor : fetchGroupAttributeDescriptors ) { + final boolean previousInitialized = initializedLazyAttributeNames.contains( fetchGroupAttributeDescriptor.getName() ); + final Object loadedValue = fetchGroupAttributeDescriptor.getType().nullSafeGet( rs, - lazyPropertyColumnAliases[j], + lazyPropertyColumnAliases[fetchGroupAttributeDescriptor.getLazyIndex()], session, entity ); - if ( initializeLazyProperty( fieldName, entity, session, snapshot, j, propValue ) ) { - result = propValue; + final boolean set = initializeLazyProperty( + fieldName, + entity, + session, + snapshot, + fetchGroupAttributeDescriptor.getLazyIndex(), + loadedValue + ); + if ( previousInitialized ) { + // its already been initialized (e.g. by a write) so we don't want to overwrite + continue; } + if ( set ) { + result = loadedValue; + interceptor.attributeInitialized( fetchGroupAttributeDescriptor.getName() ); + } + } } finally { @@ -1048,9 +1090,8 @@ public abstract class AbstractEntityPersister catch (SQLException sqle) { throw getFactory().getSQLExceptionHelper().convert( sqle, - "could not initialize lazy properties: " + - MessageHelper.infoString( this, id, getFactory() ), - getSQLLazySelectString() + "could not initialize lazy properties: " + MessageHelper.infoString( this, id, getFactory() ), + lazySelect ); } } @@ -1060,8 +1101,7 @@ public abstract class AbstractEntityPersister final Object entity, final SessionImplementor session, final EntityEntry entry, - final CacheEntry cacheEntry - ) { + final CacheEntry cacheEntry) { LOG.trace( "Initializing lazy properties from second-level cache" ); @@ -1109,10 +1149,6 @@ public abstract class AbstractEntityPersister return getPropertySpaces(); } - protected Set getLazyProperties() { - return lazyProperties; - } - public boolean isBatchLoadable() { return batchSize > 1; } @@ -3475,8 +3511,8 @@ public abstract class AbstractEntityPersister protected void logStaticSQL() { if ( LOG.isDebugEnabled() ) { LOG.debugf( "Static SQL for entity: %s", getEntityName() ); - if ( sqlLazySelectString != null ) { - LOG.debugf( " Lazy select: %s", sqlLazySelectString ); + for ( Map.Entry entry : sqlLazySelectStringsByFetchGroup.entrySet() ) { + LOG.debugf( " Lazy select (%s) : %s", entry.getKey(), entry.getValue() ); } if ( sqlVersionSelectString != null ) { LOG.debugf( " Version select: %s", sqlVersionSelectString ); @@ -3815,7 +3851,7 @@ public abstract class AbstractEntityPersister //select SQL sqlSnapshotSelectString = generateSnapshotSelectString(); - sqlLazySelectString = generateLazySelectString(); + sqlLazySelectStringsByFetchGroup = generateLazySelectStringsByFetchGroup(); sqlVersionSelectString = generateSelectVersionString(); if ( hasInsertGeneratedProperties() ) { sqlInsertGeneratedValuesSelectString = generateInsertGeneratedValuesSelectString(); @@ -4244,11 +4280,7 @@ public abstract class AbstractEntityPersister if ( getEntityMetamodel().getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) { LazyAttributeLoadingInterceptor interceptor = getEntityMetamodel().getBytecodeEnhancementMetadata().extractInterceptor( entity ); if ( interceptor == null ) { - getEntityMetamodel().getBytecodeEnhancementMetadata().injectInterceptor( - entity, - null, - session - ); + getEntityMetamodel().getBytecodeEnhancementMetadata().injectInterceptor( entity, session ); } else { interceptor.setSession( session ); @@ -4483,8 +4515,9 @@ public abstract class AbstractEntityPersister return isVersioned() && getPropertyInsertability()[getVersionProperty()]; } - public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) { - getEntityTuplizer().afterInitialize( entity, lazyPropertiesAreUnfetched, session ); + @Override + public void afterInitialize(Object entity, SessionImplementor session) { + getEntityTuplizer().afterInitialize( entity, session ); } public String[] getPropertyNames() { @@ -4609,7 +4642,7 @@ public abstract class AbstractEntityPersister @Override public boolean hasUninitializedLazyProperties(Object object) { - return getEntityTuplizer().hasUninitializedLazyProperties( object ); + return entityMetamodel.getBytecodeEnhancementMetadata().hasUnFetchedAttributes( object ); } @Override @@ -5143,7 +5176,6 @@ public abstract class AbstractEntityPersister return new StandardCacheEntryImpl( state, persister, - persister.hasUninitializedLazyProperties( entity ), version, session, entity @@ -5188,7 +5220,6 @@ public abstract class AbstractEntityPersister return new StandardCacheEntryImpl( state, persister, - persister.hasUninitializedLazyProperties( entity ), version, session, entity diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java index f81797a6df..53fe8bfd28 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java @@ -8,6 +8,7 @@ package org.hibernate.persister.entity; import java.io.Serializable; import java.util.Map; +import java.util.Set; import org.hibernate.EntityMode; import org.hibernate.HibernateException; @@ -589,7 +590,7 @@ public interface EntityPersister extends OptimisticCacheSource, EntityDefinition /** * Called just after the entities properties have been initialized */ - public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session); + void afterInitialize(Object entity, SessionImplementor session); /** * Called just after the entity has been reassociated with the session diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessEnhancedImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessEnhancedImpl.java index d8886cf7e1..34d9880c6e 100644 --- a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessEnhancedImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessEnhancedImpl.java @@ -13,7 +13,7 @@ import org.hibernate.PropertyNotFoundException; import org.hibernate.bytecode.enhance.spi.EnhancerConstants; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.property.access.spi.EnhancedGetterMethodImpl; -import org.hibernate.property.access.spi.EnhancedSetterMethodImpl; +import org.hibernate.property.access.spi.EnhancedSetterImpl; import org.hibernate.property.access.spi.Getter; import org.hibernate.property.access.spi.GetterFieldImpl; import org.hibernate.property.access.spi.PropertyAccess; @@ -32,7 +32,6 @@ import org.hibernate.property.access.spi.SetterFieldImpl; */ public class PropertyAccessEnhancedImpl implements PropertyAccess { private final PropertyAccessStrategyEnhancedImpl strategy; - private final Getter getter; private final Setter setter; @@ -42,42 +41,50 @@ public class PropertyAccessEnhancedImpl implements PropertyAccess { String propertyName) { this.strategy = strategy; + // field represents the enhanced field on the entity final Field field = fieldOrNull( containerJavaType, propertyName ); - final Method getterMethod = getterMethodOrNull( containerJavaType, propertyName ); - - final Class propertyJavaType; - - // need one of field or getterMethod to be non-null - if ( field == null && getterMethod == null ) { - String msg = String.format( "Could not locate field nor getter method for property named [%s#%s]", - containerJavaType.getName(), - propertyName ); - throw new PropertyAccessBuildingException( msg ); - } - else if ( field != null ) { - propertyJavaType = field.getType(); - this.getter = resolveGetterForField( containerJavaType, propertyName, field ); - } - else { - propertyJavaType = getterMethod.getReturnType(); - this.getter = new EnhancedGetterMethodImpl( containerJavaType, propertyName, getterMethod ); + if ( field == null ) { + throw new PropertyAccessBuildingException( + String.format( + "Could not locate field for property [%s] on bytecode-enhanced Class [%s]", + propertyName, + containerJavaType.getName() + ) + ); } - final Method setterMethod = setterMethodOrNull( containerJavaType, propertyName, propertyJavaType ); - - // need one of field or setterMethod to be non-null - if ( field == null && setterMethod == null ) { - String msg = String.format( "Could not locate field nor getter method for property named [%s#%s]", - containerJavaType.getName(), - propertyName ); - throw new PropertyAccessBuildingException( msg ); - } - else if ( field != null ) { - this.setter = resolveSetterForField( containerJavaType, propertyName, field ); - } - else { - this.setter = new EnhancedSetterMethodImpl( containerJavaType, propertyName, setterMethod ); - } + this.getter = new GetterFieldImpl( containerJavaType, propertyName, field ); + this.setter = resolveEnhancedSetterForField( containerJavaType, propertyName, field ); +// +// // need one of field or getterMethod to be non-null +// if ( field == null && getterMethod == null ) { +// String msg = ; +// throw new PropertyAccessBuildingException( msg ); +// } +// else if ( field != null ) { +// propertyJavaType = field.getType(); +// this.getter = resolveGetterForField( containerJavaType, propertyName, field ); +// } +// else { +// propertyJavaType = getterMethod.getReturnType(); +// this.getter = new EnhancedGetterMethodImpl( containerJavaType, propertyName, field, getterMethod ); +// } +// +// final Method setterMethod = setterMethodOrNull( containerJavaType, propertyName, propertyJavaType ); +// +// // need one of field or setterMethod to be non-null +// if ( field == null && setterMethod == null ) { +// String msg = String.format( "Could not locate field nor getter method for property named [%s#%s]", +// containerJavaType.getName(), +// propertyName ); +// throw new PropertyAccessBuildingException( msg ); +// } +// else if ( field != null ) { +// this.setter = resolveSetterForField( containerJavaType, propertyName, field ); +// } +// else { +// this.setter = new EnhancedSetterImpl( containerJavaType, propertyName, setterMethod ); +// } } private static Field fieldOrNull(Class containerJavaType, String propertyName) { @@ -107,27 +114,26 @@ public class PropertyAccessEnhancedImpl implements PropertyAccess { } } - // +// +// private static Getter resolveGetterForField(Class containerClass, String propertyName, Field field) { +// try { +// String enhancedGetterName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + propertyName; +// Method enhancedGetter = containerClass.getDeclaredMethod( enhancedGetterName ); +// enhancedGetter.setAccessible( true ); +// return new EnhancedGetterMethodImpl( containerClass, propertyName, field, enhancedGetter ); +// } +// catch (NoSuchMethodException e) { +// // enhancedGetter = null --- field not enhanced: fallback to reflection using the field +// return new GetterFieldImpl( containerClass, propertyName, field ); +// } +// } - private static Getter resolveGetterForField(Class containerClass, String propertyName, Field field) { - try { - String enhancedGetterName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + propertyName; - Method enhancedGetter = containerClass.getDeclaredMethod( enhancedGetterName ); - enhancedGetter.setAccessible( true ); - return new EnhancedGetterMethodImpl( containerClass, propertyName, enhancedGetter ); - } - catch (NoSuchMethodException e) { - // enhancedGetter = null --- field not enhanced: fallback to reflection using the field - return new GetterFieldImpl( containerClass, propertyName, field ); - } - } - - private static Setter resolveSetterForField(Class containerClass, String propertyName, Field field) { + private static Setter resolveEnhancedSetterForField(Class containerClass, String propertyName, Field field) { try { String enhancedSetterName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + propertyName; Method enhancedSetter = containerClass.getDeclaredMethod( enhancedSetterName, field.getType() ); enhancedSetter.setAccessible( true ); - return new EnhancedSetterMethodImpl( containerClass, propertyName, enhancedSetter ); + return new EnhancedSetterImpl( containerClass, propertyName, enhancedSetter ); } catch (NoSuchMethodException e) { // enhancedSetter = null --- field not enhanced: fallback to reflection using the field diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyResolverStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyResolverStandardImpl.java index 269b2e84fa..836da10033 100644 --- a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyResolverStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessStrategyResolverStandardImpl.java @@ -34,11 +34,13 @@ public class PropertyAccessStrategyResolverStandardImpl implements PropertyAcces String explicitAccessStrategyName, EntityMode entityMode) { - if ( ( BuiltInPropertyAccessStrategies.BASIC.getExternalName().equals( explicitAccessStrategyName ) || - BuiltInPropertyAccessStrategies.FIELD.getExternalName().equals( explicitAccessStrategyName ) || - BuiltInPropertyAccessStrategies.MIXED.getExternalName().equals( explicitAccessStrategyName ) ) && - Managed.class.isAssignableFrom( containerClass ) ) { - return PropertyAccessStrategyEnhancedImpl.INSTANCE; + if ( BuiltInPropertyAccessStrategies.BASIC.getExternalName().equals( explicitAccessStrategyName ) + || BuiltInPropertyAccessStrategies.FIELD.getExternalName().equals( explicitAccessStrategyName ) + || BuiltInPropertyAccessStrategies.MIXED.getExternalName().equals( explicitAccessStrategyName ) ) { + if ( Managed.class.isAssignableFrom( containerClass ) ) { + // PROPERTY (BASIC) and MIXED are not valid for bytecode enhanced entities... + return PropertyAccessStrategyEnhancedImpl.INSTANCE; + } } if ( StringHelper.isNotEmpty( explicitAccessStrategyName ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedGetterMethodImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedGetterMethodImpl.java index dc9e21b268..6d97221305 100644 --- a/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedGetterMethodImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedGetterMethodImpl.java @@ -8,6 +8,7 @@ package org.hibernate.property.access.spi; import java.io.ObjectStreamException; import java.io.Serializable; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import java.lang.reflect.Method; @@ -30,44 +31,50 @@ public class EnhancedGetterMethodImpl implements Getter { private final Class containerClass; private final String propertyName; + private final Field field; private final Method getterMethod; - public EnhancedGetterMethodImpl(Class containerClass, String propertyName, Method getterMethod) { + public EnhancedGetterMethodImpl( + Class containerClass, + String propertyName, + Field field, + Method getterMethod) { this.containerClass = containerClass; this.propertyName = propertyName; + this.field = field; this.getterMethod = getterMethod; } - private boolean isAttributeLoaded(Object owner) { - if ( owner instanceof PersistentAttributeInterceptable ) { - PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) owner ).$$_hibernate_getInterceptor(); - if ( interceptor != null && interceptor instanceof LazyAttributeLoadingInterceptor ) { - return ( (LazyAttributeLoadingInterceptor) interceptor ).isAttributeLoaded( propertyName ); - } - } - return true; - } +// private boolean isAttributeLoaded(Object owner) { +// if ( owner instanceof PersistentAttributeInterceptable ) { +// PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) owner ).$$_hibernate_getInterceptor(); +// if ( interceptor != null && interceptor instanceof LazyAttributeLoadingInterceptor ) { +// return ( (LazyAttributeLoadingInterceptor) interceptor ).isAttributeLoaded( propertyName ); +// } +// } +// return true; +// } @Override public Object get(Object owner) { try { + return field.get( owner ); - // We don't want to trigger lazy loading of byte code enhanced attributes - if ( isAttributeLoaded( owner ) ) { - return getterMethod.invoke( owner ); - } - return null; - - } - catch (InvocationTargetException ite) { - throw new PropertyAccessException( - ite, - "Exception occurred inside", - false, - containerClass, - propertyName - ); +// // We don't want to trigger lazy loading of byte code enhanced attributes +// if ( isAttributeLoaded( owner ) ) { +// return getterMethod.invoke( owner ); +// } +// return null; } +// catch (InvocationTargetException ite) { +// throw new PropertyAccessException( +// ite, +// "Exception occurred inside", +// false, +// containerClass, +// propertyName +// ); +// } catch (IllegalAccessException iae) { throw new PropertyAccessException( iae, @@ -134,7 +141,7 @@ public class EnhancedGetterMethodImpl implements Getter { } private Object readResolve() { - return new EnhancedGetterMethodImpl( containerClass, propertyName, resolveMethod() ); + return new EnhancedGetterMethodImpl( containerClass, propertyName, resolveField(), resolveMethod() ); } @SuppressWarnings("unchecked") @@ -148,5 +155,17 @@ public class EnhancedGetterMethodImpl implements Getter { ); } } + + @SuppressWarnings("unchecked") + private Field resolveField() { + try { + return declaringClass.getDeclaredField( propertyName ); + } + catch (NoSuchFieldException e) { + throw new PropertyAccessSerializationException( + "Unable to resolve field on deserialization : " + declaringClass.getName() + "#" + propertyName + ); + } + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterMethodImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterImpl.java similarity index 90% rename from hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterMethodImpl.java rename to hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterImpl.java index ae30c75270..9b4b717624 100644 --- a/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterMethodImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/property/access/spi/EnhancedSetterImpl.java @@ -20,10 +20,15 @@ import org.hibernate.internal.CoreMessageLogger; import static org.hibernate.internal.CoreLogging.messageLogger; /** + * A specialized Setter implementation for handling setting values into + * a into a bytecode-enhanced Class. The reason we need specialized handling + * is to render the fact that the + * * @author Steve Ebersole + * @author Luis Barreiro */ -public class EnhancedSetterMethodImpl implements Setter { - private static final CoreMessageLogger LOG = messageLogger( EnhancedSetterMethodImpl.class ); +public class EnhancedSetterImpl implements Setter { + private static final CoreMessageLogger LOG = messageLogger( EnhancedSetterImpl.class ); private final Class containerClass; private final String propertyName; @@ -31,7 +36,7 @@ public class EnhancedSetterMethodImpl implements Setter { private final boolean isPrimitive; - public EnhancedSetterMethodImpl(Class containerClass, String propertyName, Method setterMethod) { + public EnhancedSetterImpl(Class containerClass, String propertyName, Method setterMethod) { this.containerClass = containerClass; this.propertyName = propertyName; this.setterMethod = setterMethod; @@ -153,7 +158,7 @@ public class EnhancedSetterMethodImpl implements Setter { } private Object readResolve() { - return new EnhancedSetterMethodImpl( containerClass, propertyName, resolveMethod() ); + return new EnhancedSetterImpl( containerClass, propertyName, resolveMethod() ); } @SuppressWarnings("unchecked") diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java b/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java index ed262553fd..c218881e88 100755 --- a/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java @@ -13,34 +13,47 @@ import java.lang.reflect.Constructor; import org.hibernate.InstantiationException; import org.hibernate.PropertyNotFoundException; import org.hibernate.bytecode.spi.ReflectionOptimizer; +import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.mapping.Component; -import org.hibernate.mapping.PersistentClass; - -import org.jboss.logging.Logger; /** * Defines a POJO-based instantiator for use from the tuplizers. */ public class PojoInstantiator implements Instantiator, Serializable { - - private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, PojoInstantiator.class.getName()); + private static final CoreMessageLogger LOG = CoreLogging.messageLogger( PojoInstantiator.class.getName() ); private transient Constructor constructor; private final Class mappedClass; private final transient ReflectionOptimizer.InstantiationOptimizer optimizer; private final boolean embeddedIdentifier; - private final Class proxyInterface; private final boolean isAbstract; + public PojoInstantiator( + Class mappedClass, + ReflectionOptimizer.InstantiationOptimizer optimizer, + boolean embeddedIdentifier) { + this.mappedClass = mappedClass; + this.optimizer = optimizer; + this.embeddedIdentifier = embeddedIdentifier; + this.isAbstract = ReflectHelper.isAbstractClass( mappedClass ); + + try { + constructor = ReflectHelper.getDefaultConstructor(mappedClass); + } + catch ( PropertyNotFoundException pnfe ) { + LOG.noDefaultConstructor( mappedClass.getName() ); + constructor = null; + } + } + public PojoInstantiator(Component component, ReflectionOptimizer.InstantiationOptimizer optimizer) { this.mappedClass = component.getComponentClass(); this.isAbstract = ReflectHelper.isAbstractClass( mappedClass ); this.optimizer = optimizer; - this.proxyInterface = null; this.embeddedIdentifier = false; try { @@ -52,22 +65,6 @@ public class PojoInstantiator implements Instantiator, Serializable { } } - public PojoInstantiator(PersistentClass persistentClass, ReflectionOptimizer.InstantiationOptimizer optimizer) { - this.mappedClass = persistentClass.getMappedClass(); - this.isAbstract = ReflectHelper.isAbstractClass( mappedClass ); - this.proxyInterface = persistentClass.getProxyInterface(); - this.embeddedIdentifier = persistentClass.hasEmbeddedIdentifier(); - this.optimizer = optimizer; - - try { - constructor = ReflectHelper.getDefaultConstructor( mappedClass ); - } - catch ( PropertyNotFoundException pnfe ) { - LOG.noDefaultConstructor(mappedClass.getName()); - constructor = null; - } - } - private void readObject(java.io.ObjectInputStream stream) throws ClassNotFoundException, IOException { stream.defaultReadObject(); constructor = ReflectHelper.getDefaultConstructor( mappedClass ); @@ -85,7 +82,7 @@ public class PojoInstantiator implements Instantiator, Serializable { } else { try { - return constructor.newInstance( (Object[]) null ); + return applyInterception( constructor.newInstance( (Object[]) null ) ); } catch ( Exception e ) { throw new InstantiationException( "Could not instantiate entity: ", mappedClass, e ); @@ -93,6 +90,10 @@ public class PojoInstantiator implements Instantiator, Serializable { } } + protected Object applyInterception(Object entity) { + return entity; + } + public Object instantiate(Serializable id) { final boolean useEmbeddedIdentifierInstanceAsEntity = embeddedIdentifier && id != null && @@ -101,7 +102,6 @@ public class PojoInstantiator implements Instantiator, Serializable { } public boolean isInstance(Object object) { - return mappedClass.isInstance(object) || - ( proxyInterface!=null && proxyInterface.isInstance(object) ); //this one needed only for guessEntityMode() + return mappedClass.isInstance( object ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java index 82bfaf83cf..37ee3312eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java @@ -100,7 +100,7 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { * * @return An appropriate Instantiator instance. */ - protected abstract Instantiator buildInstantiator(PersistentClass mappingInfo); + protected abstract Instantiator buildInstantiator(EntityMetamodel entityMetamodel, PersistentClass mappingInfo); /** * Build an appropriate ProxyFactory for the given mapped entity. @@ -151,7 +151,7 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { } hasCustomAccessors = foundCustomAccessor; - instantiator = buildInstantiator( mappingInfo ); + instantiator = buildInstantiator( entityMetamodel, mappingInfo ); if ( entityMetamodel.isLazy() && !entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) { proxyFactory = buildProxyFactory( mappingInfo, idGetter, idSetter ); @@ -486,7 +486,11 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { } protected boolean shouldGetAllProperties(Object entity) { - return !hasUninitializedLazyProperties( entity ); + if ( !getEntityMetamodel().getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) { + return true; + } + + return !getEntityMetamodel().getBytecodeEnhancementMetadata().hasUnFetchedAttributes( entity ); } @Override @@ -641,13 +645,7 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { } @Override - public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) { - } - - @Override - public boolean hasUninitializedLazyProperties(Object entity) { - // the default is to simply not lazy fetch properties for now... - return false; + public void afterInitialize(Object entity, SessionImplementor session) { } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataNonEnhancedPojoImpl.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataNonEnhancedPojoImpl.java deleted file mode 100644 index ba0c39d1ad..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataNonEnhancedPojoImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.tuple.entity; - -import java.util.Set; - -import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; -import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; -import org.hibernate.bytecode.spi.NotInstrumentedException; -import org.hibernate.engine.spi.SessionImplementor; - -/** - * @author Steve Ebersole - */ -public class BytecodeEnhancementMetadataNonEnhancedPojoImpl implements BytecodeEnhancementMetadata { - private final Class entityClass; - private final String errorMsg; - - public BytecodeEnhancementMetadataNonEnhancedPojoImpl(Class entityClass) { - this.entityClass = entityClass; - this.errorMsg = "Entity class [" + entityClass.getName() + "] is not enhanced"; - } - - @Override - public String getEntityName() { - return entityClass.getName(); - } - - @Override - public boolean isEnhancedForLazyLoading() { - return false; - } - - @Override - public LazyAttributeLoadingInterceptor injectInterceptor( - Object entity, - Set uninitializedFieldNames, - SessionImplementor session) throws NotInstrumentedException { - throw new NotInstrumentedException( errorMsg ); - } - - @Override - public LazyAttributeLoadingInterceptor extractInterceptor(Object entity) throws NotInstrumentedException { - throw new NotInstrumentedException( errorMsg ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataNonPojoImpl.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataNonPojoImpl.java index 9e853e67db..24e4d9617c 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataNonPojoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataNonPojoImpl.java @@ -9,6 +9,7 @@ package org.hibernate.tuple.entity; import java.util.Set; import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributesMetadata; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; import org.hibernate.bytecode.spi.NotInstrumentedException; import org.hibernate.engine.spi.SessionImplementor; @@ -18,10 +19,12 @@ import org.hibernate.engine.spi.SessionImplementor; */ public class BytecodeEnhancementMetadataNonPojoImpl implements BytecodeEnhancementMetadata { private final String entityName; + private final LazyAttributesMetadata lazyAttributesMetadata; private final String errorMsg; public BytecodeEnhancementMetadataNonPojoImpl(String entityName) { this.entityName = entityName; + this.lazyAttributesMetadata = LazyAttributesMetadata.nonEnhanced( entityName ); this.errorMsg = "Entity [" + entityName + "] is non-pojo, and therefore not instrumented"; } @@ -35,10 +38,14 @@ public class BytecodeEnhancementMetadataNonPojoImpl implements BytecodeEnhanceme return false; } + @Override + public LazyAttributesMetadata getLazyAttributesMetadata() { + return lazyAttributesMetadata; + } + @Override public LazyAttributeLoadingInterceptor injectInterceptor( Object entity, - Set uninitializedFieldNames, SessionImplementor session) throws NotInstrumentedException { throw new NotInstrumentedException( errorMsg ); } @@ -47,4 +54,9 @@ public class BytecodeEnhancementMetadataNonPojoImpl implements BytecodeEnhanceme public LazyAttributeLoadingInterceptor extractInterceptor(Object entity) throws NotInstrumentedException { throw new NotInstrumentedException( errorMsg ); } + + @Override + public boolean hasUnFetchedAttributes(Object entity) { + return false; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java index 6c91c9c73f..fa8fa3b8c2 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java @@ -9,27 +9,52 @@ package org.hibernate.tuple.entity; import java.util.Set; import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributesMetadata; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; import org.hibernate.bytecode.spi.NotInstrumentedException; import org.hibernate.engine.spi.PersistentAttributeInterceptable; import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.mapping.PersistentClass; /** * @author Steve Ebersole */ public class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhancementMetadata { + public static BytecodeEnhancementMetadata from(PersistentClass persistentClass) { + final Class mappedClass = persistentClass.getMappedClass(); + final boolean enhancedForLazyLoading = PersistentAttributeInterceptable.class.isAssignableFrom( mappedClass ); + final LazyAttributesMetadata lazyAttributesMetadata = enhancedForLazyLoading + ? LazyAttributesMetadata.from( persistentClass ) + : LazyAttributesMetadata.nonEnhanced( persistentClass.getEntityName() ); + + return new BytecodeEnhancementMetadataPojoImpl( + persistentClass.getEntityName(), + mappedClass, + enhancedForLazyLoading, + lazyAttributesMetadata + ); + } + + private final String entityName; private final Class entityClass; private final boolean enhancedForLazyLoading; + private final LazyAttributesMetadata lazyAttributesMetadata; - public BytecodeEnhancementMetadataPojoImpl(Class entityClass) { + public BytecodeEnhancementMetadataPojoImpl( + String entityName, + Class entityClass, + boolean enhancedForLazyLoading, + LazyAttributesMetadata lazyAttributesMetadata) { + this.entityName = entityName; this.entityClass = entityClass; - this.enhancedForLazyLoading = PersistentAttributeInterceptable.class.isAssignableFrom( entityClass ); + this.enhancedForLazyLoading = enhancedForLazyLoading; + this.lazyAttributesMetadata = lazyAttributesMetadata; } @Override public String getEntityName() { - return entityClass.getName(); + return entityName; } @Override @@ -37,6 +62,19 @@ public class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhancementM return enhancedForLazyLoading; } + @Override + public LazyAttributesMetadata getLazyAttributesMetadata() { + return lazyAttributesMetadata; + } + + @Override + public boolean hasUnFetchedAttributes(Object entity) { + LazyAttributeLoadingInterceptor interceptor = isEnhancedForLazyLoading() + ? extractInterceptor( entity ) + : null; + return interceptor != null && interceptor.hasAnyUninitializedAttributes(); + } + @Override public LazyAttributeLoadingInterceptor extractInterceptor(Object entity) throws NotInstrumentedException { if ( !enhancedForLazyLoading ) { @@ -62,10 +100,7 @@ public class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhancementM } @Override - public LazyAttributeLoadingInterceptor injectInterceptor( - Object entity, - Set uninitializedFieldNames, - SessionImplementor session) throws NotInstrumentedException { + public LazyAttributeLoadingInterceptor injectInterceptor(Object entity, SessionImplementor session) { if ( !enhancedForLazyLoading ) { throw new NotInstrumentedException( "Entity class [" + entityClass.getName() + "] is not enhanced for lazy loading" ); } @@ -80,7 +115,11 @@ public class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhancementM ); } - final LazyAttributeLoadingInterceptor interceptor = new LazyAttributeLoadingInterceptor( session, uninitializedFieldNames, getEntityName() ); + final LazyAttributeLoadingInterceptor interceptor = new LazyAttributeLoadingInterceptor( + getEntityName(), + lazyAttributesMetadata.getLazyAttributeNames(), + session + ); ( (PersistentAttributeInterceptable) entity ).$$_hibernate_setInterceptor( interceptor ); return interceptor; } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java index 0d0cfe62e5..a5e8d026be 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java @@ -16,10 +16,10 @@ import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; -import org.hibernate.property.access.spi.Getter; -import org.hibernate.property.access.spi.Setter; import org.hibernate.property.access.internal.PropertyAccessStrategyMapImpl; +import org.hibernate.property.access.spi.Getter; import org.hibernate.property.access.spi.PropertyAccess; +import org.hibernate.property.access.spi.Setter; import org.hibernate.proxy.ProxyFactory; import org.hibernate.proxy.map.MapProxyFactory; import org.hibernate.tuple.DynamicMapInstantiator; @@ -63,7 +63,7 @@ public class DynamicMapEntityTuplizer extends AbstractEntityTuplizer { } @Override - protected Instantiator buildInstantiator(PersistentClass mappingInfo) { + protected Instantiator buildInstantiator(EntityMetamodel entityMetamodel, PersistentClass mappingInfo) { return new DynamicMapInstantiator( mappingInfo ); } @@ -99,11 +99,6 @@ public class DynamicMapEntityTuplizer extends AbstractEntityTuplizer { return Map.class; } - @Override - public boolean isInstrumented() { - return false; - } - @Override public EntityNameResolver[] getEntityNameResolvers() { return new EntityNameResolver[] {BasicEntityNameResolver.INSTANCE}; diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java index 93b6fc2537..57d6daabf9 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java @@ -143,7 +143,7 @@ public class EntityMetamodel implements Serializable { versioned = persistentClass.isVersioned(); if ( persistentClass.hasPojoRepresentation() ) { - bytecodeEnhancementMetadata = new BytecodeEnhancementMetadataPojoImpl( persistentClass.getMappedClass() ); + bytecodeEnhancementMetadata = BytecodeEnhancementMetadataPojoImpl.from( persistentClass ); } else { bytecodeEnhancementMetadata = new BytecodeEnhancementMetadataNonPojoImpl( persistentClass.getEntityName() ); diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java index 59432a5299..6dc10027f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java @@ -7,6 +7,7 @@ package org.hibernate.tuple.entity; import java.io.Serializable; import java.util.Map; +import java.util.Set; import org.hibernate.EntityMode; import org.hibernate.EntityNameResolver; @@ -188,10 +189,9 @@ public interface EntityTuplizer extends Tuplizer { * Called just after the entities properties have been initialized. * * @param entity The entity being initialized. - * @param lazyPropertiesAreUnfetched Are defined lazy properties currently unfecthed * @param session The session initializing this entity. */ - void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session); + void afterInitialize(Object entity, SessionImplementor session); /** * Does this entity, for this mode, present a possibility for proxying? @@ -228,21 +228,6 @@ public interface EntityTuplizer extends Tuplizer { * @return The java class to which generated proxies will be typed */ Class getConcreteProxyClass(); - - /** - * Does the given entity instance have any currently uninitialized lazy properties? - * - * @param entity The entity to be check for uninitialized lazy properties. - * @return True if uninitialized lazy properties were found; false otherwise. - */ - boolean hasUninitializedLazyProperties(Object entity); - - /** - * Is it an instrumented POJO? - * - * @return {@code true} if the entity class is instrumented; {@code false} otherwise. - */ - boolean isInstrumented(); /** * Get any {@link EntityNameResolver EntityNameResolvers} associated with this {@link Tuplizer}. diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityInstantiator.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityInstantiator.java new file mode 100644 index 0000000000..47bd979d66 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityInstantiator.java @@ -0,0 +1,65 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.tuple.entity; + +import org.hibernate.PropertyNotFoundException; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.spi.ReflectionOptimizer; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; +import org.hibernate.engine.spi.PersistentAttributeInterceptor; +import org.hibernate.internal.util.ReflectHelper; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.tuple.PojoInstantiator; + +/** + * @author Steve Ebersole + */ +public class PojoEntityInstantiator extends PojoInstantiator { + private final EntityMetamodel entityMetamodel; + private final Class proxyInterface; + private final boolean applyBytecodeInterception; + + public PojoEntityInstantiator( + EntityMetamodel entityMetamodel, + PersistentClass persistentClass, + ReflectionOptimizer.InstantiationOptimizer optimizer) { + super( + persistentClass.getMappedClass(), + optimizer, + persistentClass.hasEmbeddedIdentifier() + ); + this.entityMetamodel = entityMetamodel; + + this.proxyInterface = persistentClass.getProxyInterface(); + this.applyBytecodeInterception = PersistentAttributeInterceptable.class.isAssignableFrom( persistentClass.getMappedClass() ); + } + + @Override + protected Object applyInterception(Object entity) { + if ( !applyBytecodeInterception ) { + return entity; + } + + PersistentAttributeInterceptor interceptor = new LazyAttributeLoadingInterceptor( + entityMetamodel.getName(), + entityMetamodel.getBytecodeEnhancementMetadata() + .getLazyAttributesMetadata() + .getLazyAttributeNames(), + null + ); + ( (PersistentAttributeInterceptable) entity ).$$_hibernate_setInterceptor( interceptor ); + return entity; + } + + @Override + public boolean isInstance(Object object) { + return super.isInstance( object ) || + //this one needed only for guessEntityMode() + ( proxyInterface!=null && proxyInterface.isInstance(object) ); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java index 862b9f0dd8..7424651be4 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java @@ -8,8 +8,6 @@ package org.hibernate.tuple.entity; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -53,10 +51,11 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer { private final Class mappedClass; private final Class proxyInterface; private final boolean lifecycleImplementor; - private final Set lazyPropertyNames; private final ReflectionOptimizer optimizer; + private final boolean isBytecodeEnhanced; + public PojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) { super( entityMetamodel, mappedEntity ); this.mappedClass = mappedEntity.getMappedClass(); @@ -64,16 +63,6 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer { this.lifecycleImplementor = Lifecycle.class.isAssignableFrom( mappedClass ); this.isBytecodeEnhanced = entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading(); - Iterator iter = mappedEntity.getPropertyClosureIterator(); - Set tmpLazyPropertyNames = new HashSet( ); - while ( iter.hasNext() ) { - Property property = (Property) iter.next(); - if ( property.isLazy() ) { - tmpLazyPropertyNames.add( property.getName() ); - } - } - lazyPropertyNames = tmpLazyPropertyNames.isEmpty() ? null : Collections.unmodifiableSet( tmpLazyPropertyNames ); - String[] getterNames = new String[propertySpan]; String[] setterNames = new String[propertySpan]; Class[] propTypes = new Class[propertySpan]; @@ -200,12 +189,12 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer { } @Override - protected Instantiator buildInstantiator(PersistentClass persistentClass) { + protected Instantiator buildInstantiator(EntityMetamodel entityMetamodel, PersistentClass persistentClass) { if ( optimizer == null ) { - return new PojoInstantiator( persistentClass, null ); + return new PojoEntityInstantiator( entityMetamodel, persistentClass, null ); } else { - return new PojoInstantiator( persistentClass, optimizer.getInstantiationOptimizer() ); + return new PojoEntityInstantiator( entityMetamodel, persistentClass, optimizer.getInstantiationOptimizer() ); } } @@ -281,38 +270,35 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer { //TODO: need to make the majority of this functionality into a top-level support class for custom impl support @Override - public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) { - // new bytecode enhancement lazy interception + public void afterInitialize(Object entity, SessionImplementor session) { + + // moving to multiple fetch groups, the idea of `lazyPropertiesAreUnfetched` really + // needs to become either: + // 1) the names of all un-fetched fetch groups + // 2) the names of all fetched fetch groups + // probably (2) is best + // + // ultimately this comes from EntityEntry, although usage-search seems to show it is never updated there. + // + // also org.hibernate.persister.entity.AbstractEntityPersister.initializeLazyPropertiesFromDatastore() + // needs to be re-worked + if ( entity instanceof PersistentAttributeInterceptable ) { - if ( lazyPropertiesAreUnfetched && getEntityMetamodel().hasLazyProperties() ) { - PersistentAttributeInterceptor interceptor = new LazyAttributeLoadingInterceptor( session, lazyPropertyNames, getEntityName() ); - ( (PersistentAttributeInterceptable) entity ).$$_hibernate_setInterceptor( interceptor ); + final LazyAttributeLoadingInterceptor interceptor = getEntityMetamodel().getBytecodeEnhancementMetadata().extractInterceptor( entity ); + if ( interceptor == null ) { + getEntityMetamodel().getBytecodeEnhancementMetadata().injectInterceptor( entity, session ); } - } - - // also clear the fields that are marked as dirty in the dirtyness tracker - if ( entity instanceof SelfDirtinessTracker ) { - ( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes(); - } - } - - @Override - public boolean hasUninitializedLazyProperties(Object entity) { - if ( getEntityMetamodel().hasLazyProperties() ) { - if ( entity instanceof PersistentAttributeInterceptable ) { - PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor(); - if ( interceptor != null && interceptor instanceof LazyAttributeLoadingInterceptor ) { - return ( (LazyAttributeLoadingInterceptor) interceptor ).hasAnyUninitializedAttributes(); + else { + if ( interceptor.getLinkedSession() == null ) { + interceptor.setSession( session ); } } } - return false; - } - - @Override - public boolean isInstrumented() { - return isBytecodeEnhanced; + // clear the fields that are marked as dirty in the dirtyness tracker + if ( entity instanceof SelfDirtinessTracker ) { + ( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes(); + } } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/engine/spi/EntityEntryTest.java b/hibernate-core/src/test/java/org/hibernate/engine/spi/EntityEntryTest.java index 0dcc5ac0bb..6da291c62b 100644 --- a/hibernate-core/src/test/java/org/hibernate/engine/spi/EntityEntryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/engine/spi/EntityEntryTest.java @@ -6,10 +6,6 @@ */ package org.hibernate.engine.spi; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; @@ -18,8 +14,13 @@ import java.io.ObjectOutputStream; import org.hibernate.LockMode; import org.hibernate.engine.internal.MutableEntityEntry; + import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + /** * Tests for setting and getting the enum/boolean values stored in the compressed state int. * @@ -35,7 +36,6 @@ public class EntityEntryTest { assertEquals( Status.MANAGED, entityEntry.getStatus() ); assertEquals( true, entityEntry.isExistsInDatabase() ); assertEquals( true, entityEntry.isBeingReplicated() ); - assertEquals( true, entityEntry.isLoadedWithLazyPropertiesUnfetched() ); } @Test @@ -47,7 +47,6 @@ public class EntityEntryTest { assertEquals( Status.MANAGED, entityEntry.getStatus() ); assertEquals( true, entityEntry.isExistsInDatabase() ); assertEquals( true, entityEntry.isBeingReplicated() ); - assertEquals( true, entityEntry.isLoadedWithLazyPropertiesUnfetched() ); // When entityEntry.setLockMode( LockMode.PESSIMISTIC_READ ); @@ -57,7 +56,6 @@ public class EntityEntryTest { assertEquals( Status.MANAGED, entityEntry.getStatus() ); assertEquals( true, entityEntry.isExistsInDatabase() ); assertEquals( true, entityEntry.isBeingReplicated() ); - assertEquals( true, entityEntry.isLoadedWithLazyPropertiesUnfetched() ); } @Test @@ -73,7 +71,6 @@ public class EntityEntryTest { assertEquals( Status.DELETED, entityEntry.getStatus() ); assertEquals( true, entityEntry.isExistsInDatabase() ); assertEquals( true, entityEntry.isBeingReplicated() ); - assertEquals( true, entityEntry.isLoadedWithLazyPropertiesUnfetched() ); } @Test @@ -89,7 +86,6 @@ public class EntityEntryTest { assertEquals( Status.GONE, entityEntry.getStatus() ); assertEquals( false, entityEntry.isExistsInDatabase() ); assertEquals( true, entityEntry.isBeingReplicated() ); - assertEquals( true, entityEntry.isLoadedWithLazyPropertiesUnfetched() ); } @Test @@ -108,23 +104,30 @@ public class EntityEntryTest { assertEquals( Status.MANAGED, deserializedEntry.getStatus() ); assertEquals( true, deserializedEntry.isExistsInDatabase() ); assertEquals( true, deserializedEntry.isBeingReplicated() ); - assertEquals( true, deserializedEntry.isLoadedWithLazyPropertiesUnfetched() ); } private EntityEntry createEntityEntry() { return new MutableEntityEntry( - Status.MANAGED, // status - new Object[]{}, // loadedState - 1L, // rowId - 42L, // id - 23L, // version - LockMode.OPTIMISTIC, // lockMode - true, // existsInDatabase - null, // persister - true, // disableVersionIncrement - true, // lazyPropertiesAreUnfetched - getPersistenceContextMock() // persistenceContext) + // status + Status.MANAGED, + // loadedState + new Object[]{}, + // rowId + 1L, + // id + 42L, + // version + 23L, + // lockMode + LockMode.OPTIMISTIC, + // existsInDatabase + true, + // persister + null, + // disableVersionIncrement + true, + getPersistenceContextMock() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/tuplizer/DynamicEntityTuplizer.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/tuplizer/DynamicEntityTuplizer.java index 4d86de1bf4..9ecf824531 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/tuplizer/DynamicEntityTuplizer.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/tuplizer/DynamicEntityTuplizer.java @@ -19,19 +19,21 @@ import org.hibernate.tuple.entity.PojoEntityTuplizer; */ public class DynamicEntityTuplizer extends PojoEntityTuplizer { - public DynamicEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) { - super( entityMetamodel, mappedEntity ); - } - - protected Instantiator buildInstantiator(PersistentClass persistentClass) { - return new DynamicInstantiator( persistentClass.getEntityName() ); - } - - protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, Getter idGetter, Setter idSetter) { - // allows defining a custom proxy factory, which is responsible for - // generating lazy proxies for a given entity. - // - // Here we simply use the default... - return super.buildProxyFactory( persistentClass, idGetter, idSetter ); - } + public DynamicEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) { + super( entityMetamodel, mappedEntity ); } + + @Override + protected Instantiator buildInstantiator(EntityMetamodel entityMetamodel, PersistentClass persistentClass) { + return new DynamicInstantiator( persistentClass.getEntityName() ); + } + + @Override + protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, Getter idGetter, Setter idSetter) { + // allows defining a custom proxy factory, which is responsible for + // generating lazy proxies for a given entity. + // + // Here we simply use the default... + return super.buildProxyFactory( persistentClass, idGetter, idSetter ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java index c3bb6a2d45..762696fc9a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java @@ -27,6 +27,7 @@ import org.hibernate.test.bytecode.enhancement.lazy.LazyLoadingIntegrationTestTa import org.hibernate.test.bytecode.enhancement.lazy.LazyLoadingTestTask; import org.hibernate.test.bytecode.enhancement.lazy.basic.LazyBasicFieldAccessTestTask; import org.hibernate.test.bytecode.enhancement.lazy.basic.LazyBasicPropertyAccessTestTask; +import org.hibernate.test.bytecode.enhancement.lazy.group.LazyGroupAccessTestTask; import org.hibernate.test.bytecode.enhancement.lazyCache.InitFromCacheTestTask; import org.hibernate.test.bytecode.enhancement.merge.CompositeMergeTestTask; import org.hibernate.test.bytecode.enhancement.pk.EmbeddedPKTestTask; @@ -72,6 +73,12 @@ public class EnhancerTest extends BaseUnitTestCase { EnhancerTestUtils.runEnhancerTestTask( LazyCollectionLoadingTestTask.class ); } + @Test + @TestForIssue( jiraKey = "HHH-10267" ) + public void testLazyGroups() { + EnhancerTestUtils.runEnhancerTestTask( LazyGroupAccessTestTask.class ); + } + @Test(timeout = 10000) @TestForIssue( jiraKey = "HHH-10055" ) @FailureExpected( jiraKey = "HHH-10055" ) diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/ObjectAttributeMarkerInterceptor.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/ObjectAttributeMarkerInterceptor.java index 5df883a183..f499397374 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/ObjectAttributeMarkerInterceptor.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/ObjectAttributeMarkerInterceptor.java @@ -7,6 +7,8 @@ package org.hibernate.test.bytecode.enhancement.basic; +import java.util.Set; + import org.hibernate.engine.spi.PersistentAttributeInterceptor; /** @@ -112,4 +114,14 @@ public class ObjectAttributeMarkerInterceptor implements PersistentAttributeInte public Object writeObject(Object obj, String name, Object oldValue, Object newValue) { return WRITE_MARKER; } + + @Override + public Set getInitializedLazyAttributeNames() { + return null; + } + + @Override + public void attributeInitialized(String name) { + + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Child.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Child.java index b57824d936..99ceeb26ea 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Child.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Child.java @@ -34,6 +34,13 @@ public class Child { @LazyToOne(LazyToOneOption.NO_PROXY) Parent parent; + public Child() { + } + + public Child(String name) { + this.name = name; + } + public Long getId() { return id; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTestTask.java index 9b88d30fd1..3a10023c95 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTestTask.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTestTask.java @@ -18,6 +18,9 @@ import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils; import org.junit.Assert; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + /** * @author Luis Barreiro */ @@ -43,8 +46,9 @@ public class LazyLoadingTestTask extends AbstractEnhancerTestTask { Parent parent = new Parent(); parent.setChildren(new ArrayList()); for ( int i = 0; i < CHILDREN_SIZE; i++ ) { - final Child child = new Child(); + final Child child = new Child( "Child #" + i ); child.setParent( parent ); + parent.getChildren().add( child ); s.persist( child ); lastChildID = child.getId(); } @@ -62,11 +66,17 @@ public class LazyLoadingTestTask extends AbstractEnhancerTestTask { Child loadedChild = s.load( Child.class, lastChildID ); + Object nameByReflection = EnhancerTestUtils.getFieldByReflection( loadedChild, "name" ); + Assert.assertNotNull( "Non-lazy field 'name' was not loaded", nameByReflection ); + Object parentByReflection = EnhancerTestUtils.getFieldByReflection( loadedChild, "parent" ); Assert.assertNull( "Lazy field 'parent' is initialized", parentByReflection ); Assert.assertFalse( loadedChild instanceof HibernateProxy ); Parent loadedParent = loadedChild.getParent(); + assertThat( loadedChild.getName(), notNullValue() ); + assertThat( loadedParent, notNullValue() ); + assertThat( loadedChild.getParent(), notNullValue() ); EnhancerTestUtils.checkDirtyTracking( loadedChild ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/Child.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/Child.java new file mode 100644 index 0000000000..eb3efdd00e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/Child.java @@ -0,0 +1,88 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.lazy.group; + +import javax.persistence.Basic; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +import org.hibernate.annotations.LazyGroup; +import org.hibernate.annotations.LazyToOne; +import org.hibernate.annotations.LazyToOneOption; + +/** + * @author Steve Ebersole + */ +@Entity +public class Child { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + Long id; + String name; + @Basic( fetch = FetchType.LAZY ) + String nickName; + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @LazyToOne(LazyToOneOption.NO_PROXY) + Parent parent; + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @LazyToOne(LazyToOneOption.NO_PROXY) + @LazyGroup( "SECONDARY" ) + Parent alternateParent; + + public Child() { + } + + public Child(String name, String nickName) { + this.name = name; + this.nickName = nickName; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public Parent getParent() { + return parent; + } + + public void setParent(Parent parent) { + this.parent = parent; + } + + public Parent getAlternateParent() { + return alternateParent; + } + + public void setAlternateParent(Parent alternateParent) { + this.alternateParent = alternateParent; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/LazyGroupAccessTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/LazyGroupAccessTestTask.java new file mode 100644 index 0000000000..f4683729f8 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/LazyGroupAccessTestTask.java @@ -0,0 +1,132 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.lazy.group; + +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.proxy.HibernateProxy; + +import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils; +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; +import org.junit.Assert; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNull; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +/** + * @author Steve Ebersole + */ +public class LazyGroupAccessTestTask extends AbstractEnhancerTestTask { + + @Override + public Class[] getAnnotatedClasses() { + return new Class[] { Child.class, Parent.class }; + } + + @Override + public void prepare() { + Configuration cfg = new Configuration(); + cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" ); + super.prepare( cfg ); + + Session s = getFactory().openSession(); + s.beginTransaction(); + + Child c1 = new Child( "steve", "hibernater" ); + Child c2 = new Child( "sally", "Joe Mama" ); + + Parent p1 = new Parent( "Hibernate" ); + Parent p2 = new Parent( "Swimming" ); + + c1.setParent( p1 ); + p1.getChildren().add( c1 ); + + c1.setAlternateParent( p2 ); + p2.getAlternateChildren().add( c1 ); + + c2.setAlternateParent( p1 ); + p1.getAlternateChildren().add( c2 ); + + c2.setParent( p2 ); + p2.getChildren().add( c2 ); + + s.save( p1 ); + s.save( p2 ); + + s.getTransaction().commit(); + s.close(); + } + + @Override + public void execute() { + Session s = getFactory().openSession(); + s.beginTransaction(); + + Child c1 = (Child) s.createQuery( "from Child c where c.name = :name" ).setString( "name", "steve" ).uniqueResult(); + + // verify the expected initial loaded state + assertLoaded( c1, "name" ); + assertNotLoaded( c1, "nickName" ); + assertNotLoaded( c1, "parent" ); + assertNotLoaded( c1, "alternateParent" ); + + // Now lets access nickName which ought to initialize nickName and parent, but not alternateParent + c1.getNickName(); + assertLoaded( c1, "nickName" ); + assertLoaded( c1, "parent" ); + assertNotLoaded( c1, "alternateParent" ); + assertEquals( "Hibernate", c1.getParent().getNombre() ); + assertFalse( c1.getParent() instanceof HibernateProxy ); + + Child c2 = (Child) s.createQuery( "from Child c where c.name = :name" ).setString( "name", "sally" ).uniqueResult(); + + // verify the expected initial loaded state + assertLoaded( c2, "name" ); + assertNotLoaded( c2, "nickName" ); + assertNotLoaded( c2, "parent" ); + assertNotLoaded( c2, "alternateParent" ); + + // Now lets access alternateParent which ought to initialize alternateParent and nothing else + c2.getAlternateParent(); + assertNotLoaded( c2, "nickName" ); + assertNotLoaded( c2, "parent" ); + assertLoaded( c2, "alternateParent" ); + assertEquals( "Hibernate", c2.getAlternateParent().getNombre() ); + assertFalse( c2.getAlternateParent() instanceof HibernateProxy ); + + s.getTransaction().commit(); + s.close(); + } + + private void assertLoaded(Object owner, String name) { + // NOTE we assume null == not-loaded + Object fieldByReflection = EnhancerTestUtils.getFieldByReflection( owner, name ); + assertNotNull( "Expecting field '" + name + "' to be loaded, but it was not", fieldByReflection ); + } + + private void assertNotLoaded(Object owner, String name) { + // NOTE we assume null == not-loaded + Object fieldByReflection = EnhancerTestUtils.getFieldByReflection( owner, name ); + assertNull( "Expecting field '" + name + "' to be not loaded, but it was", fieldByReflection ); + } + + @Override + protected void cleanup() { + Session s = getFactory().openSession(); + s.beginTransaction(); + + s.createQuery( "delete Child" ).executeUpdate(); + s.createQuery( "delete Parent" ).executeUpdate(); + + s.getTransaction().commit(); + s.close(); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/Parent.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/Parent.java new file mode 100644 index 0000000000..2e5c1292a4 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/Parent.java @@ -0,0 +1,71 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.lazy.group; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +/** + * @author Steve Ebersole + */ +@Entity +public class Parent { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + Long id; + String nombre; + @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + List children = new ArrayList(); + @OneToMany(mappedBy = "alternateParent", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + List alternateChildren = new ArrayList(); + + public Parent() { + } + + public Parent(String nombre) { + this.nombre = nombre; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getNombre() { + return nombre; + } + + public void setNombre(String nombre) { + this.nombre = nombre; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + public List getAlternateChildren() { + return alternateChildren; + } + + public void setAlternateChildren(List alternateChildren) { + this.alternateChildren = alternateChildren; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazyCache/AbstractCachingTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazyCache/AbstractCachingTestTask.java index db3db5022a..5391577c91 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazyCache/AbstractCachingTestTask.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazyCache/AbstractCachingTestTask.java @@ -36,6 +36,7 @@ public abstract class AbstractCachingTestTask implements EnhancerTestTask { StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder(); registryBuilder.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); registryBuilder.applySetting( AvailableSettings.HBM2DDL_AUTO, "create-drop" ); + registryBuilder.applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" ); registryBuilder.addService( ClassLoaderService.class, new ClassLoaderServiceImpl( Thread.currentThread().getContextClassLoader() ) ); StandardServiceRegistry registry = registryBuilder.build(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazyCache/InitFromCacheTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazyCache/InitFromCacheTestTask.java index 227bff614e..1262305eb6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazyCache/InitFromCacheTestTask.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazyCache/InitFromCacheTestTask.java @@ -8,10 +8,14 @@ package org.hibernate.test.bytecode.enhancement.lazyCache; import org.hibernate.Hibernate; import org.hibernate.Session; -import org.hibernate.Transaction; +import org.hibernate.cache.spi.entry.StandardCacheEntryImpl; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.cache.BaseRegion; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; /** @@ -20,42 +24,47 @@ import static org.junit.Assert.assertTrue; public class InitFromCacheTestTask extends AbstractCachingTestTask { @Override public void execute() { - Session s; - Transaction tx; + EntityPersister p = sessionFactory().getEntityPersister( Document.class.getName() ); + assertTrue( p.hasCache() ); + BaseRegion region = (BaseRegion) p.getCacheAccessStrategy().getRegion(); - s = sessionFactory().openSession(); - tx = s.beginTransaction(); + Session s = sessionFactory().openSession(); + s.beginTransaction(); s.persist( new Document("HiA", "Hibernate book", "Hibernate is....") ); - tx.commit(); + s.getTransaction().commit(); s.close(); s = sessionFactory().openSession(); - tx = s.beginTransaction(); - s.createQuery("from Document fetch all properties").uniqueResult(); - tx.commit(); + s.beginTransaction(); + Document d = (Document) s.createQuery( "from Document fetch all properties").uniqueResult(); + assertTrue( Hibernate.isPropertyInitialized( d, "text") ); + assertTrue( Hibernate.isPropertyInitialized( d, "summary") ); + s.getTransaction().commit(); s.close(); + StandardCacheEntryImpl cacheEntry = (StandardCacheEntryImpl) region.getDataMap().get( p.getCacheAccessStrategy().generateCacheKey( d.getId(), p, sessionFactory(), null ) ); + assertNotNull( cacheEntry ); sessionFactory().getStatistics().clear(); s = sessionFactory().openSession(); - tx = s.beginTransaction(); - Document d = (Document) s.createCriteria(Document.class).uniqueResult(); + s.beginTransaction(); + d = (Document) s.createCriteria(Document.class).uniqueResult(); assertFalse( Hibernate.isPropertyInitialized( d, "text") ); assertFalse( Hibernate.isPropertyInitialized(d, "summary") ); assertEquals( "Hibernate is....", d.getText() ); assertTrue( Hibernate.isPropertyInitialized(d, "text") ); assertTrue( Hibernate.isPropertyInitialized(d, "summary") ); - tx.commit(); + s.getTransaction().commit(); s.close(); assertEquals( 2, sessionFactory().getStatistics().getPrepareStatementCount() ); s = sessionFactory().openSession(); - tx = s.beginTransaction(); + s.beginTransaction(); d = s.get(Document.class, d.getId()); assertFalse( Hibernate.isPropertyInitialized(d, "text") ); assertFalse( Hibernate.isPropertyInitialized(d, "summary") ); - tx.commit(); + s.getTransaction().commit(); s.close(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java index 94ca492e92..2f7303ddc8 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java @@ -11,6 +11,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.Comparator; import java.util.Map; +import java.util.Set; import org.hibernate.EntityMode; import org.hibernate.HibernateException; @@ -45,9 +46,9 @@ import org.hibernate.persister.walking.spi.AttributeDefinition; import org.hibernate.persister.walking.spi.CollectionElementDefinition; import org.hibernate.persister.walking.spi.CollectionIndexDefinition; import org.hibernate.persister.walking.spi.EntityIdentifierDefinition; +import org.hibernate.tuple.entity.BytecodeEnhancementMetadataNonPojoImpl; import org.hibernate.tuple.entity.EntityMetamodel; import org.hibernate.tuple.entity.EntityTuplizer; -import org.hibernate.tuple.entity.BytecodeEnhancementMetadataNonPojoImpl; import org.hibernate.type.CollectionType; import org.hibernate.type.Type; import org.hibernate.type.VersionType; @@ -453,7 +454,8 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { } @Override - public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) { + public void afterInitialize(Object entity, SessionImplementor session) { + } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityTuplizer.java b/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityTuplizer.java index 043ad7b011..2acf7ffc63 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityTuplizer.java +++ b/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityTuplizer.java @@ -22,10 +22,12 @@ public class MyEntityTuplizer extends PojoEntityTuplizer { super( entityMetamodel, mappedEntity ); } - protected Instantiator buildInstantiator(PersistentClass persistentClass) { + @Override + protected Instantiator buildInstantiator(EntityMetamodel entityMetamodel, PersistentClass persistentClass) { return new MyEntityInstantiator( persistentClass.getEntityName() ); } + @Override protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, Getter idGetter, Setter idSetter) { // allows defining a custom proxy factory, which is responsible for // generating lazy proxies for a given entity. diff --git a/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java b/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java index f519710578..86586d67dd 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java +++ b/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java @@ -26,14 +26,17 @@ public class MyEntityTuplizer extends PojoEntityTuplizer { super( entityMetamodel, mappedEntity ); } + @Override public EntityNameResolver[] getEntityNameResolvers() { return new EntityNameResolver[] { MyEntityNameResolver.INSTANCE }; } - protected Instantiator buildInstantiator(PersistentClass persistentClass) { + @Override + protected Instantiator buildInstantiator(EntityMetamodel entityMetamodel, PersistentClass persistentClass) { return new MyEntityInstantiator( persistentClass.getEntityName() ); } + @Override public String determineConcreteSubclassEntityName(Object entityInstance, SessionFactoryImplementor factory) { String entityName = ProxyHelper.extractEntityName( entityInstance ); if ( entityName == null ) { @@ -42,6 +45,7 @@ public class MyEntityTuplizer extends PojoEntityTuplizer { return entityName; } + @Override protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, Getter idGetter, Setter idSetter) { // allows defining a custom proxy factory, which is responsible for // generating lazy proxies for a given entity. diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java index c312a36e25..aef2119061 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java @@ -10,6 +10,7 @@ import java.io.Serializable; import java.util.Comparator; import java.util.Hashtable; import java.util.Map; +import java.util.Set; import org.hibernate.EntityMode; import org.hibernate.HibernateException; @@ -45,9 +46,9 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.spi.PersisterCreationContext; import org.hibernate.persister.walking.spi.AttributeDefinition; import org.hibernate.persister.walking.spi.EntityIdentifierDefinition; +import org.hibernate.tuple.entity.BytecodeEnhancementMetadataNonPojoImpl; import org.hibernate.tuple.entity.EntityMetamodel; import org.hibernate.tuple.entity.EntityTuplizer; -import org.hibernate.tuple.entity.BytecodeEnhancementMetadataNonPojoImpl; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.Type; import org.hibernate.type.VersionType; @@ -324,7 +325,6 @@ public class CustomPersister implements EntityPersister { clone, this, LockMode.NONE, - false, session ); TwoPhaseLoad.postHydrate( @@ -333,7 +333,6 @@ public class CustomPersister implements EntityPersister { null, clone, LockMode.NONE, - false, session ); TwoPhaseLoad.initializeEntity( @@ -561,7 +560,7 @@ public class CustomPersister implements EntityPersister { } @Override - public void afterInitialize(Object entity, boolean fetched, SessionImplementor session) { + public void afterInitialize(Object entity, SessionImplementor session) { } @Override @@ -594,7 +593,6 @@ public class CustomPersister implements EntityPersister { return new StandardCacheEntryImpl( state, this, - this.hasUninitializedLazyProperties( entity ), version, session, entity diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java index a13f310218..63a27a012a 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java @@ -474,7 +474,7 @@ public class PersisterClassProviderTest { } @Override - public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) { + public void afterInitialize(Object entity, SessionImplementor session) { } @Override diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/EnhancerTestUtils.java b/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/EnhancerTestUtils.java index 3df21bb923..dd27c4a6d6 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/EnhancerTestUtils.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/EnhancerTestUtils.java @@ -213,7 +213,6 @@ public abstract class EnhancerTestUtils extends BaseUnitTestCase { false, null, false, - false, null ); } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegion.java b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegion.java index de6cd11b1b..9dd38df1b5 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegion.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cache/BaseRegion.java @@ -16,7 +16,7 @@ import org.hibernate.cache.spi.Region; /** * @author Strong Liu */ -class BaseRegion implements Region { +public class BaseRegion implements Region { protected final Map cache = new ConcurrentHashMap(); private final String name; private static int timeout = Timestamper.ONE_MS * 60000; //60s @@ -69,4 +69,8 @@ class BaseRegion implements Region { public int getTimeout() { return timeout; } + + public Map getDataMap() { + return cache; + } }