org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-core Show documentation
Show all versions of hibernate-core Show documentation
Hibernate's core ORM functionality
/*
* 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.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.LockMode;
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.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.spi.SelfDirtinessTracker;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.persister.entity.EntityPersister;
import org.jboss.logging.Logger;
/**
* Interceptor that loads attributes lazily
*
* @author Luis Barreiro
* @author Steve Ebersole
*/
public class LazyAttributeLoadingInterceptor
implements PersistentAttributeInterceptor, Consumer, InterceptorImplementor {
private static final Logger log = Logger.getLogger( LazyAttributeLoadingInterceptor.class );
private final String entityName;
private final Set lazyFields;
private Set initializedLazyFields;
private transient SharedSessionContractImplementor session;
private boolean allowLoadOutsideTransaction;
private String sessionFactoryUuid;
public LazyAttributeLoadingInterceptor(
String entityName,
Set lazyFields,
SharedSessionContractImplementor session) {
this.entityName = entityName;
this.lazyFields = lazyFields;
setSession( session );
}
protected final Object intercept(Object target, String attributeName, Object value) {
if ( !isAttributeLoaded( attributeName ) ) {
Object loadedValue = fetchAttribute( target, attributeName );
attributeInitialized( attributeName );
return loadedValue;
}
return value;
}
/**
* Fetches the lazy attribute. The attribute does not get associated with the entity. (To be used by hibernate methods)
*/
public Object fetchAttribute(final Object target, final String attributeName) {
return loadAttribute( target, attributeName );
}
protected Object loadAttribute(final Object target, final String attributeName) {
return new Helper( this ).performWork(
new LazyInitializationWork() {
@Override
public Object doWork(SharedSessionContractImplementor session, boolean isTemporarySession) {
final EntityPersister persister = session.getFactory().getMetamodel().entityPersister( getEntityName() );
if ( isTemporarySession ) {
final Serializable id = persister.getIdentifier( target, null );
// Add an entry for this entity in the PC of the temp Session
// NOTE : a few arguments that would be nice to pass along here...
// 1) loadedState if we know any
final Object[] loadedState = null;
// 2) does a row exist in the db for this entity?
final boolean existsInDb = true;
session.getPersistenceContext().addEntity(
target,
Status.READ_ONLY,
loadedState,
session.generateEntityKey( id, persister ),
persister.getVersion( target ),
LockMode.NONE,
existsInDb,
persister,
true
);
}
final LazyPropertyInitializer initializer = (LazyPropertyInitializer) persister;
final Object loadedValue = initializer.initializeLazyProperty(
attributeName,
target,
session
);
takeCollectionSizeSnapshot( target, attributeName, loadedValue );
return loadedValue;
}
@Override
public String getEntityName() {
return entityName;
}
@Override
public String getAttributeName() {
return attributeName;
}
}
);
}
public final void setSession(SharedSessionContractImplementor 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() {
this.session = null;
}
public boolean isAttributeLoaded(String 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 ) {
return false;
}
if ( initializedLazyFields == null ) {
return true;
}
for ( String fieldName : lazyFields ) {
if ( !initializedLazyFields.contains( fieldName ) ) {
return true;
}
}
return false;
}
@Override
public String toString() {
return "LazyAttributeLoader(entityName=" + entityName + " ,lazyFields=" + lazyFields + ')';
}
//
private void takeCollectionSizeSnapshot(Object target, String fieldName, Object value) {
if ( value != null && value instanceof Collection && target instanceof SelfDirtinessTracker ) {
CollectionTracker tracker = ( (SelfDirtinessTracker) target ).$$_hibernate_getCollectionTracker();
if ( tracker == null ) {
( (SelfDirtinessTracker) target ).$$_hibernate_clearDirtyAttributes();
tracker = ( (SelfDirtinessTracker) target ).$$_hibernate_getCollectionTracker();
}
tracker.add( fieldName, ( (Collection) value ).size() );
}
}
@Override
public boolean readBoolean(Object obj, String name, boolean oldValue) {
return (Boolean) intercept( obj, name, oldValue );
}
@Override
public boolean writeBoolean(Object obj, String name, boolean oldValue, boolean newValue) {
if ( lazyFields != null && lazyFields.contains( name ) ) {
attributeInitialized( name );
}
return newValue;
}
@Override
public byte readByte(Object obj, String name, byte oldValue) {
return (Byte) intercept( obj, name, oldValue );
}
@Override
public byte writeByte(Object obj, String name, byte oldValue, byte newValue) {
if ( lazyFields != null && lazyFields.contains( name ) ) {
attributeInitialized( name );
}
return newValue;
}
@Override
public char readChar(Object obj, String name, char oldValue) {
return (Character) intercept( obj, name, oldValue );
}
@Override
public char writeChar(Object obj, String name, char oldValue, char newValue) {
if ( lazyFields != null && lazyFields.contains( name ) ) {
attributeInitialized( name );
}
return newValue;
}
@Override
public short readShort(Object obj, String name, short oldValue) {
return (Short) intercept( obj, name, oldValue );
}
@Override
public short writeShort(Object obj, String name, short oldValue, short newValue) {
if ( lazyFields != null && lazyFields.contains( name ) ) {
attributeInitialized( name );
}
return newValue;
}
@Override
public int readInt(Object obj, String name, int oldValue) {
return (Integer) intercept( obj, name, oldValue );
}
@Override
public int writeInt(Object obj, String name, int oldValue, int newValue) {
if ( lazyFields != null && lazyFields.contains( name ) ) {
attributeInitialized( name );
}
return newValue;
}
@Override
public float readFloat(Object obj, String name, float oldValue) {
return (Float) intercept( obj, name, oldValue );
}
@Override
public float writeFloat(Object obj, String name, float oldValue, float newValue) {
if ( lazyFields != null && lazyFields.contains( name ) ) {
attributeInitialized( name );
}
return newValue;
}
@Override
public double readDouble(Object obj, String name, double oldValue) {
return (Double) intercept( obj, name, oldValue );
}
@Override
public double writeDouble(Object obj, String name, double oldValue, double newValue) {
if ( lazyFields != null && lazyFields.contains( name ) ) {
attributeInitialized( name );
}
return newValue;
}
@Override
public long readLong(Object obj, String name, long oldValue) {
return (Long) intercept( obj, name, oldValue );
}
@Override
public long writeLong(Object obj, String name, long oldValue, long newValue) {
if ( lazyFields != null && lazyFields.contains( name ) ) {
attributeInitialized( name );
}
return newValue;
}
@Override
public Object readObject(Object obj, String name, Object oldValue) {
return intercept( obj, name, oldValue );
}
@Override
public Object writeObject(Object obj, String name, Object oldValue, Object newValue) {
if ( lazyFields != null && lazyFields.contains( name ) ) {
attributeInitialized( name );
}
return newValue;
}
@Override
public SharedSessionContractImplementor getLinkedSession() {
return session;
}
@Override
public boolean allowLoadOutsideTransaction() {
return allowLoadOutsideTransaction;
}
@Override
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;
}
}