HHH-8683 Class org.hibernate.engine.spi.EntityEntry consumes lots of memory
This commit is contained in:
parent
d84c6b35aa
commit
dedd24afc2
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.internal;
|
||||
|
||||
import org.hibernate.engine.spi.EntityEntryExtraState;
|
||||
|
||||
/**
|
||||
* Contains optional state from {@link org.hibernate.engine.spi.EntityEntry}.
|
||||
*
|
||||
* @author Emmanuel Bernard <emmanuel@hibernate.org>
|
||||
*/
|
||||
public class EntityEntryExtraStateHolder implements EntityEntryExtraState {
|
||||
private EntityEntryExtraState next;
|
||||
private Object[] deletedState;
|
||||
|
||||
public Object[] getDeletedState() {
|
||||
return deletedState;
|
||||
}
|
||||
|
||||
public void setDeletedState(Object[] deletedState) {
|
||||
this.deletedState = deletedState;
|
||||
}
|
||||
|
||||
//the following methods are handling extraState contracts.
|
||||
//they are not shared by a common superclass to avoid alignment padding
|
||||
//we are trading off duplication for padding efficiency
|
||||
@Override
|
||||
public void addExtraState(EntityEntryExtraState extraState) {
|
||||
if ( next == null ) {
|
||||
next = extraState;
|
||||
}
|
||||
else {
|
||||
next.addExtraState( extraState );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends EntityEntryExtraState> T getExtraState(Class<T> extraStateType) {
|
||||
if ( next == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( extraStateType.isAssignableFrom( next.getClass() ) ) {
|
||||
return (T) next;
|
||||
}
|
||||
else {
|
||||
return next.getExtraState( extraStateType );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||
* Copyright (c) 2010-2014, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
|
@ -28,12 +28,14 @@ import java.io.ObjectInputStream;
|
|||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.CustomEntityDirtinessStrategy;
|
||||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
import org.hibernate.engine.internal.EntityEntryExtraStateHolder;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.UniqueKeyLoadable;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
|
@ -41,26 +43,49 @@ import org.hibernate.pretty.MessageHelper;
|
|||
/**
|
||||
* We need an entry to tell us all about the current state of an object with respect to its persistent state
|
||||
*
|
||||
* Implementation Warning: Hibernate needs to instantiate a high amount of instances of this class,
|
||||
* therefore we need to take care of its impact on memory consumption.
|
||||
*
|
||||
* @author Gavin King
|
||||
* @author Emmanuel Bernard <emmanuel@hibernate.org>
|
||||
* @author Gunnar Morling
|
||||
* @author Sanne Grinovero <sanne@hibernate.org>
|
||||
*/
|
||||
public final class EntityEntry implements Serializable {
|
||||
private LockMode lockMode;
|
||||
private Status status;
|
||||
private Status previousStatus;
|
||||
private final Serializable id;
|
||||
private Object[] loadedState;
|
||||
private Object[] deletedState;
|
||||
private boolean existsInDatabase;
|
||||
private Object version;
|
||||
private transient EntityPersister persister;
|
||||
private final String entityName;
|
||||
// cached EntityKey (lazy-initialized)
|
||||
private transient EntityKey cachedEntityKey;
|
||||
private boolean isBeingReplicated;
|
||||
//NOTE: this is not updated when properties are fetched lazily!
|
||||
private boolean loadedWithLazyPropertiesUnfetched;
|
||||
private final EntityPersister persister; // permanent but we only need the entityName state in a non transient way
|
||||
private transient EntityKey cachedEntityKey; // cached EntityKey (lazy-initialized)
|
||||
private final transient Object rowId;
|
||||
private final transient PersistenceContext persistenceContext;
|
||||
private EntityEntryExtraState next;
|
||||
|
||||
/**
|
||||
* Holds several boolean and enum typed attributes in a very compact manner. Enum values are stored in 4 bits
|
||||
* (where 0 represents {@code null}, and each enum value is represented by its ordinal value + 1), thus allowing
|
||||
* for up to 15 values per enum. Boolean values are stored in one bit.
|
||||
* <p>
|
||||
* The value is structured as follows:
|
||||
*
|
||||
* <pre>
|
||||
* 1 - Lock mode
|
||||
* 2 - Status
|
||||
* 3 - Previous Status
|
||||
* 4 - existsInDatabase
|
||||
* 5 - isBeingReplicated
|
||||
* 6 - loadedWithLazyPropertiesUnfetched; NOTE: this is not updated when properties are fetched lazily!
|
||||
*
|
||||
* 0000 0000 | 0000 0000 | 0654 3333 | 2222 1111
|
||||
* </pre>
|
||||
* Use {@link #setCompressedValue(org.hibernate.engine.spi.EntityEntry.EnumState, Enum)},
|
||||
* {@link #getCompressedValue(org.hibernate.engine.spi.EntityEntry.EnumState, Class)} etc
|
||||
* to access the enums and booleans stored in this value.
|
||||
* <p>
|
||||
* Representing enum values by their ordinal value is acceptable for our case as this value itself is never
|
||||
* serialized or deserialized and thus is not affected should ordinal values change.
|
||||
*/
|
||||
private transient int compressedState;
|
||||
|
||||
/**
|
||||
* @deprecated the tenantId and entityMode parameters where removed: this constructor accepts but ignores them.
|
||||
|
@ -97,21 +122,21 @@ public final class EntityEntry implements Serializable {
|
|||
final boolean disableVersionIncrement,
|
||||
final boolean lazyPropertiesAreUnfetched,
|
||||
final PersistenceContext persistenceContext) {
|
||||
this.status = status;
|
||||
this.previousStatus = null;
|
||||
setCompressedValue( EnumState.STATUS, status );
|
||||
// not useful strictly speaking but more explicit
|
||||
setCompressedValue( EnumState.PREVIOUS_STATUS, null );
|
||||
// only retain loaded state if the status is not Status.READ_ONLY
|
||||
if ( status != Status.READ_ONLY ) {
|
||||
this.loadedState = loadedState;
|
||||
}
|
||||
this.id=id;
|
||||
this.rowId=rowId;
|
||||
this.existsInDatabase=existsInDatabase;
|
||||
setCompressedValue( BooleanState.EXISTS_IN_DATABASE, existsInDatabase );
|
||||
this.version=version;
|
||||
this.lockMode=lockMode;
|
||||
this.isBeingReplicated=disableVersionIncrement;
|
||||
this.loadedWithLazyPropertiesUnfetched = lazyPropertiesAreUnfetched;
|
||||
setCompressedValue( EnumState.LOCK_MODE, lockMode );
|
||||
setCompressedValue( BooleanState.IS_BEING_REPLICATED, disableVersionIncrement );
|
||||
setCompressedValue( BooleanState.LOADED_WITH_LAZY_PROPERTIES_UNFETCHED, lazyPropertiesAreUnfetched );
|
||||
this.persister=persister;
|
||||
this.entityName = persister == null ? null : persister.getEntityName();
|
||||
this.persistenceContext = persistenceContext;
|
||||
}
|
||||
|
||||
|
@ -133,33 +158,35 @@ public final class EntityEntry implements Serializable {
|
|||
final boolean isBeingReplicated,
|
||||
final boolean loadedWithLazyPropertiesUnfetched,
|
||||
final PersistenceContext persistenceContext) {
|
||||
this.entityName = entityName;
|
||||
this.persister = ( factory == null ? null : factory.getEntityPersister( entityName ) );
|
||||
this.id = id;
|
||||
this.status = status;
|
||||
this.previousStatus = previousStatus;
|
||||
setCompressedValue( EnumState.STATUS, status );
|
||||
setCompressedValue( EnumState.PREVIOUS_STATUS, previousStatus );
|
||||
this.loadedState = loadedState;
|
||||
this.deletedState = deletedState;
|
||||
setDeletedState( deletedState );
|
||||
this.version = version;
|
||||
this.lockMode = lockMode;
|
||||
this.existsInDatabase = existsInDatabase;
|
||||
this.isBeingReplicated = isBeingReplicated;
|
||||
this.loadedWithLazyPropertiesUnfetched = loadedWithLazyPropertiesUnfetched;
|
||||
// this is equivalent to the old behavior...
|
||||
this.rowId = null;
|
||||
setCompressedValue( EnumState.LOCK_MODE, lockMode );
|
||||
setCompressedValue( BooleanState.EXISTS_IN_DATABASE, existsInDatabase );
|
||||
setCompressedValue( BooleanState.IS_BEING_REPLICATED, isBeingReplicated );
|
||||
setCompressedValue( BooleanState.LOADED_WITH_LAZY_PROPERTIES_UNFETCHED, loadedWithLazyPropertiesUnfetched );
|
||||
this.rowId = null; // this is equivalent to the old behavior...
|
||||
this.persistenceContext = persistenceContext;
|
||||
}
|
||||
|
||||
public LockMode getLockMode() {
|
||||
return lockMode;
|
||||
return getCompressedValue( EnumState.LOCK_MODE, LockMode.class );
|
||||
}
|
||||
|
||||
public void setLockMode(LockMode lockMode) {
|
||||
this.lockMode = lockMode;
|
||||
setCompressedValue( EnumState.LOCK_MODE, lockMode );
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
return getCompressedValue( EnumState.STATUS, Status.class );
|
||||
}
|
||||
|
||||
private Status getPreviousStatus() {
|
||||
return getCompressedValue( EnumState.PREVIOUS_STATUS, Status.class );
|
||||
}
|
||||
|
||||
public void setStatus(Status status) {
|
||||
|
@ -167,9 +194,12 @@ public final class EntityEntry implements Serializable {
|
|||
//memory optimization
|
||||
loadedState = null;
|
||||
}
|
||||
if ( this.status != status ) {
|
||||
this.previousStatus = this.status;
|
||||
this.status = status;
|
||||
|
||||
Status currentStatus = this.getStatus();
|
||||
|
||||
if ( currentStatus != status ) {
|
||||
setCompressedValue( EnumState.PREVIOUS_STATUS, currentStatus );
|
||||
setCompressedValue( EnumState.STATUS, status );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,16 +211,28 @@ public final class EntityEntry implements Serializable {
|
|||
return loadedState;
|
||||
}
|
||||
|
||||
private static final Object[] DEFAULT_DELETED_STATE = null;
|
||||
|
||||
public Object[] getDeletedState() {
|
||||
return deletedState;
|
||||
EntityEntryExtraStateHolder extra = getExtraState( EntityEntryExtraStateHolder.class );
|
||||
return extra != null ? extra.getDeletedState() : DEFAULT_DELETED_STATE;
|
||||
}
|
||||
|
||||
public void setDeletedState(Object[] deletedState) {
|
||||
this.deletedState = deletedState;
|
||||
EntityEntryExtraStateHolder extra = getExtraState( EntityEntryExtraStateHolder.class );
|
||||
if ( extra == null && deletedState == DEFAULT_DELETED_STATE ) {
|
||||
//this is the default value and we do not store the extra state
|
||||
return;
|
||||
}
|
||||
if ( extra == null ) {
|
||||
extra = new EntityEntryExtraStateHolder();
|
||||
addExtraState( extra );
|
||||
}
|
||||
extra.setDeletedState( deletedState );
|
||||
}
|
||||
|
||||
public boolean isExistsInDatabase() {
|
||||
return existsInDatabase;
|
||||
return getCompressedValue( BooleanState.EXISTS_IN_DATABASE );
|
||||
}
|
||||
|
||||
public Object getVersion() {
|
||||
|
@ -217,11 +259,12 @@ public final class EntityEntry implements Serializable {
|
|||
}
|
||||
|
||||
public String getEntityName() {
|
||||
return entityName;
|
||||
return persister == null ? null : persister.getEntityName();
|
||||
|
||||
}
|
||||
|
||||
public boolean isBeingReplicated() {
|
||||
return isBeingReplicated;
|
||||
return getCompressedValue( BooleanState.IS_BEING_REPLICATED );
|
||||
}
|
||||
|
||||
public Object getRowId() {
|
||||
|
@ -269,17 +312,17 @@ public final class EntityEntry implements Serializable {
|
|||
* exists in the database
|
||||
*/
|
||||
public void postDelete() {
|
||||
previousStatus = status;
|
||||
status = Status.GONE;
|
||||
existsInDatabase = false;
|
||||
setCompressedValue( EnumState.PREVIOUS_STATUS, getStatus() );
|
||||
setCompressedValue( EnumState.STATUS, Status.GONE );
|
||||
setCompressedValue( BooleanState.EXISTS_IN_DATABASE, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* After actually inserting a row, record the fact that the instance exists on the
|
||||
* After actually inserting a row, record the fact that the instance exists on the
|
||||
* database (needed for identity-column key generation)
|
||||
*/
|
||||
public void postInsert(Object[] insertedState) {
|
||||
existsInDatabase = true;
|
||||
setCompressedValue( BooleanState.EXISTS_IN_DATABASE, true );
|
||||
}
|
||||
|
||||
public boolean isNullifiable(boolean earlyInsert, SessionImplementor session) {
|
||||
|
@ -357,6 +400,8 @@ public final class EntityEntry implements Serializable {
|
|||
* @return true, if the entity is modifiable; false, otherwise,
|
||||
*/
|
||||
public boolean isModifiableEntity() {
|
||||
Status status = getStatus();
|
||||
Status previousStatus = getPreviousStatus();
|
||||
return getPersister().isMutable()
|
||||
&& status != Status.READ_ONLY
|
||||
&& ! ( status == Status.DELETED && previousStatus == Status.READ_ONLY );
|
||||
|
@ -372,8 +417,9 @@ public final class EntityEntry implements Serializable {
|
|||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
if ( status != Status.MANAGED && status != Status.READ_ONLY ) {
|
||||
throw new HibernateException( "instance was not in a valid state" );
|
||||
Status status = getStatus();
|
||||
if (status != Status.MANAGED && status != Status.READ_ONLY) {
|
||||
throw new HibernateException("instance was not in a valid state");
|
||||
}
|
||||
return status == Status.READ_ONLY;
|
||||
}
|
||||
|
@ -405,11 +451,13 @@ public final class EntityEntry implements Serializable {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EntityEntry" + MessageHelper.infoString( entityName, id ) + '(' + status + ')';
|
||||
return "EntityEntry" +
|
||||
MessageHelper.infoString( getPersister().getEntityName(), id ) +
|
||||
'(' + getStatus() + ')';
|
||||
}
|
||||
|
||||
public boolean isLoadedWithLazyPropertiesUnfetched() {
|
||||
return loadedWithLazyPropertiesUnfetched;
|
||||
return getCompressedValue( BooleanState.LOADED_WITH_LAZY_PROPERTIES_UNFETCHED );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -418,21 +466,22 @@ public final class EntityEntry implements Serializable {
|
|||
*
|
||||
* @param oos The stream to which we should write the serial data.
|
||||
*
|
||||
* @throws IOException If a stream error occurs
|
||||
* @throws java.io.IOException If a stream error occurs
|
||||
*/
|
||||
public void serialize(ObjectOutputStream oos) throws IOException {
|
||||
oos.writeObject( entityName );
|
||||
Status previousStatus = getPreviousStatus();
|
||||
oos.writeObject( getEntityName() );
|
||||
oos.writeObject( id );
|
||||
oos.writeObject( status.name() );
|
||||
oos.writeObject( getStatus().name() );
|
||||
oos.writeObject( (previousStatus == null ? "" : previousStatus.name()) );
|
||||
// todo : potentially look at optimizing these two arrays
|
||||
oos.writeObject( loadedState );
|
||||
oos.writeObject( deletedState );
|
||||
oos.writeObject( getDeletedState() );
|
||||
oos.writeObject( version );
|
||||
oos.writeObject( lockMode.toString() );
|
||||
oos.writeBoolean( existsInDatabase );
|
||||
oos.writeBoolean( isBeingReplicated );
|
||||
oos.writeBoolean( loadedWithLazyPropertiesUnfetched );
|
||||
oos.writeObject( getLockMode().toString() );
|
||||
oos.writeBoolean( isExistsInDatabase() );
|
||||
oos.writeBoolean( isBeingReplicated() );
|
||||
oos.writeBoolean( isLoadedWithLazyPropertiesUnfetched() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -470,4 +519,192 @@ public final class EntityEntry implements Serializable {
|
|||
persistenceContext
|
||||
);
|
||||
}
|
||||
|
||||
//the following methods are handling extraState contracts.
|
||||
//they are not shared by a common superclass to avoid alignment padding
|
||||
//we are trading off duplication for padding efficiency
|
||||
public void addExtraState(EntityEntryExtraState extraState) {
|
||||
if ( next == null ) {
|
||||
next = extraState;
|
||||
}
|
||||
else {
|
||||
next.addExtraState( extraState );
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends EntityEntryExtraState> T getExtraState(Class<T> extraStateType) {
|
||||
if ( next == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( extraStateType.isAssignableFrom( next.getClass() ) ) {
|
||||
return (T) next;
|
||||
}
|
||||
else {
|
||||
return next.getExtraState( extraStateType );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Saves the value for the given enum property.
|
||||
*
|
||||
* @param state
|
||||
* identifies the value to store
|
||||
* @param value
|
||||
* the value to store; The caller must make sure that it matches
|
||||
* the given identifier
|
||||
*/
|
||||
private void setCompressedValue(EnumState state, Enum<?> value) {
|
||||
// reset the bits for the given property to 0
|
||||
compressedState &= state.getUnsetMask();
|
||||
// store the numeric representation of the enum value at the right offset
|
||||
compressedState |= ( state.getValue( value ) << state.getOffset() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current value of the given enum property.
|
||||
*
|
||||
* @param state
|
||||
* identifies the value to store
|
||||
* @param type
|
||||
* the actual enum type of the given property; The caller must
|
||||
* make sure that it matches the given identifier
|
||||
* @return the current value of the specified property
|
||||
*/
|
||||
private <E extends Enum<?>> E getCompressedValue(EnumState state, Class<E> type) {
|
||||
E[] enumConstants = type.getEnumConstants();
|
||||
// restore the numeric value from the bits at the right offset and return the corresponding enum constant
|
||||
int index = ( ( compressedState & state.getMask() ) >> state.getOffset() ) - 1;
|
||||
return index == - 1 ? null : enumConstants[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the value for the given boolean flag.
|
||||
*
|
||||
* @param state
|
||||
* identifies the value to store
|
||||
* @param value
|
||||
* the value to store
|
||||
*/
|
||||
private void setCompressedValue(BooleanState state, boolean value) {
|
||||
compressedState &= state.getUnsetMask();
|
||||
compressedState |= ( state.getValue( value ) << state.getOffset() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current value of the given boolean flag.
|
||||
*
|
||||
* @param state
|
||||
* identifies the value to store
|
||||
* @return the current value of the specified flag
|
||||
*/
|
||||
private boolean getCompressedValue(BooleanState state) {
|
||||
return ( ( compressedState & state.getMask() ) >> state.getOffset() ) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an enum value stored within a number value, using four bits starting at a specified offset.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
private enum EnumState {
|
||||
|
||||
LOCK_MODE(0, LockMode.class),
|
||||
STATUS(4, Status.class),
|
||||
PREVIOUS_STATUS(8, Status.class);
|
||||
|
||||
private final int offset;
|
||||
private final int mask;
|
||||
private final int unsetMask;
|
||||
|
||||
private <E extends Enum<?>> EnumState(int offset, Class<E> enumType) {
|
||||
// In case any of the enums cannot be stored in 4 bits anymore, we'd have to re-structure the compressed
|
||||
// state int
|
||||
if ( enumType.getEnumConstants().length > 15 ) {
|
||||
throw new AssertionFailure( "Cannot store enum type " + enumType.getName() + " in compressed state as"
|
||||
+ " it has too many values." );
|
||||
}
|
||||
|
||||
this.offset = offset;
|
||||
|
||||
// a mask for reading the four bits, starting at the right offset
|
||||
this.mask = 0xF << offset;
|
||||
|
||||
// a mask for setting the four bits at the right offset to 0
|
||||
this.unsetMask = 0xFFFF & ~mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the numeric value to be stored for the given enum value.
|
||||
*/
|
||||
private int getValue(Enum<?> value) {
|
||||
return value != null ? value.ordinal() + 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset within the number value at which this enum value is stored.
|
||||
*/
|
||||
private int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bit mask for reading this enum value from the number value storing it.
|
||||
*/
|
||||
private int getMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bit mask for resetting this enum value from the number value storing it.
|
||||
*/
|
||||
private int getUnsetMask() {
|
||||
return unsetMask;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a boolean flag stored within a number value, using one bit at a specified offset.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
private enum BooleanState {
|
||||
|
||||
EXISTS_IN_DATABASE(13),
|
||||
IS_BEING_REPLICATED(14),
|
||||
LOADED_WITH_LAZY_PROPERTIES_UNFETCHED(15);
|
||||
|
||||
private final int offset;
|
||||
private final int mask;
|
||||
private final int unsetMask;
|
||||
|
||||
private BooleanState(int offset) {
|
||||
this.offset = offset;
|
||||
this.mask = 0x1 << offset;
|
||||
this.unsetMask = 0xFFFF & ~mask;
|
||||
}
|
||||
|
||||
private int getValue(boolean value) {
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset within the number value at which this boolean flag is stored.
|
||||
*/
|
||||
private int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bit mask for reading this flag from the number value storing it.
|
||||
*/
|
||||
private int getMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bit mask for resetting this flag from the number value storing it.
|
||||
*/
|
||||
private int getUnsetMask() {
|
||||
return unsetMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.engine.spi;
|
||||
|
||||
/**
|
||||
* Navigation methods for extra state objects attached to {@link org.hibernate.engine.spi.EntityEntry}.
|
||||
*
|
||||
* @author Emmanuel Bernard <emmanuel@hibernate.org>
|
||||
*/
|
||||
public interface EntityEntryExtraState {
|
||||
|
||||
/**
|
||||
* Attach additional state to the core state of {@link org.hibernate.engine.spi.EntityEntry}
|
||||
* <p>
|
||||
* Implementations must delegate to the next state or add it as next state if last in line.
|
||||
*/
|
||||
void addExtraState(EntityEntryExtraState extraState);
|
||||
|
||||
/**
|
||||
* Retrieve additional state by class type or null if no extra state of that type is present.
|
||||
* <p>
|
||||
* Implementations must return self if they match or delegate discovery to the next state in line.
|
||||
*/
|
||||
<T extends EntityEntryExtraState> T getExtraState(Class<T> extraStateType);
|
||||
|
||||
//a remove method is ugly to define and has not real use case that we found: left out
|
||||
}
|
Loading…
Reference in New Issue