HHH-8159 - Apply fixups indicated by analysis tools

This commit is contained in:
Steve Ebersole 2013-04-26 18:50:39 -05:00
parent 021401835c
commit b51164aef6
20 changed files with 696 additions and 752 deletions

View File

@ -150,6 +150,7 @@ import org.hibernate.cfg.annotations.PropertyBinder;
import org.hibernate.cfg.annotations.QueryBinder;
import org.hibernate.cfg.annotations.SimpleValueBinder;
import org.hibernate.cfg.annotations.TableBinder;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.id.MultipleHiLoPerTableGenerator;
@ -1568,7 +1569,7 @@ public final class AnnotationBinder {
SimpleValue simpleValue = ( SimpleValue ) prop.getValue();
simpleValue.setNullValue( "undefined" );
rootClass.setOptimisticLockMode( Versioning.OPTIMISTIC_LOCK_VERSION );
rootClass.setOptimisticLockStyle( OptimisticLockStyle.VERSION );
if ( traceEnabled ) {
LOG.tracev( "Version name: {0}, unsavedValue: {1}", rootClass.getVersion().getName(),
( (SimpleValue) rootClass.getVersion().getValue() ).getNullValue() );

View File

@ -24,7 +24,6 @@
package org.hibernate.cfg;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -41,7 +40,7 @@ import org.hibernate.EntityMode;
import org.hibernate.FetchMode;
import org.hibernate.FlushMode;
import org.hibernate.MappingException;
import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.NamedQueryDefinition;
@ -688,7 +687,7 @@ public final class HbmBinder {
// OPTIMISTIC LOCK MODE
Attribute olNode = node.attribute( "optimistic-lock" );
entity.setOptimisticLockMode( getOptimisticLockMode( olNode ) );
entity.setOptimisticLockStyle( getOptimisticLockStyle( olNode ) );
entity.setMetaAttributes( getMetas( node, inheritedMetas ) );
@ -2932,21 +2931,23 @@ public final class HbmBinder {
}
}
private static int getOptimisticLockMode(Attribute olAtt) throws MappingException {
private static OptimisticLockStyle getOptimisticLockStyle(Attribute olAtt) throws MappingException {
if ( olAtt == null ) {
return OptimisticLockStyle.VERSION;
}
if ( olAtt == null ) return Versioning.OPTIMISTIC_LOCK_VERSION;
String olMode = olAtt.getValue();
final String olMode = olAtt.getValue();
if ( olMode == null || "version".equals( olMode ) ) {
return Versioning.OPTIMISTIC_LOCK_VERSION;
return OptimisticLockStyle.VERSION;
}
else if ( "dirty".equals( olMode ) ) {
return Versioning.OPTIMISTIC_LOCK_DIRTY;
return OptimisticLockStyle.DIRTY;
}
else if ( "all".equals( olMode ) ) {
return Versioning.OPTIMISTIC_LOCK_ALL;
return OptimisticLockStyle.ALL;
}
else if ( "none".equals( olMode ) ) {
return Versioning.OPTIMISTIC_LOCK_NONE;
return OptimisticLockStyle.NONE;
}
else {
throw new MappingException( "Unsupported optimistic-lock style: " + olMode );

View File

@ -84,6 +84,7 @@ import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.cfg.ObjectNameSource;
import org.hibernate.cfg.PropertyHolder;
import org.hibernate.cfg.UniqueConstraintHolder;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.FilterDefinition;
@ -289,7 +290,7 @@ public class EntityBinder {
LOG.immutableAnnotationOnNonRoot(annotatedClass.getName());
}
}
persistentClass.setOptimisticLockMode( getVersioning( optimisticLockType ) );
persistentClass.setOptimisticLockStyle( getVersioning( optimisticLockType ) );
persistentClass.setSelectBeforeUpdate( selectBeforeUpdate );
//set persister if needed
@ -428,16 +429,16 @@ public class EntityBinder {
}
}
int getVersioning(OptimisticLockType type) {
OptimisticLockStyle getVersioning(OptimisticLockType type) {
switch ( type ) {
case VERSION:
return Versioning.OPTIMISTIC_LOCK_VERSION;
return OptimisticLockStyle.VERSION;
case NONE:
return Versioning.OPTIMISTIC_LOCK_NONE;
return OptimisticLockStyle.NONE;
case DIRTY:
return Versioning.OPTIMISTIC_LOCK_DIRTY;
return OptimisticLockStyle.DIRTY;
case ALL:
return Versioning.OPTIMISTIC_LOCK_ALL;
return OptimisticLockStyle.ALL;
default:
throw new AssertionFailure( "optimistic locking not supported: " + type );
}

View File

@ -32,17 +32,47 @@ public enum OptimisticLockStyle {
/**
* no optimistic locking
*/
NONE,
NONE( -1 ),
/**
* use a dedicated version column
*/
VERSION,
VERSION( 0 ),
/**
* dirty columns are compared
*/
DIRTY,
DIRTY( 1 ),
/**
* all columns are compared
*/
ALL
ALL( 2 );
private final int oldCode;
private OptimisticLockStyle(int oldCode) {
this.oldCode = oldCode;
}
public int getOldCode() {
return oldCode;
}
public static OptimisticLockStyle interpretOldCode(int oldCode) {
switch ( oldCode ) {
case -1: {
return NONE;
}
case 0: {
return VERSION;
}
case 1: {
return DIRTY;
}
case 2: {
return ALL;
}
default: {
throw new IllegalArgumentException( "Illegal legacy optimistic lock style code :" + oldCode );
}
}
}
}

View File

@ -36,13 +36,10 @@ import org.hibernate.engine.spi.SessionImplementor;
* @author Gail Badner
*/
public class NonNullableTransientDependencies {
// Multiple property paths can refer to the same transient entity, so use Set<String>
// for the map value.
private final Map<Object,Set<String>> propertyPathsByTransientEntity =
new IdentityHashMap<Object,Set<String>>();
private final Map<Object,Set<String>> propertyPathsByTransientEntity = new IdentityHashMap<Object,Set<String>>();
/* package-protected */
void add(String propertyName, Object transientEntity) {
Set<String> propertyPaths = propertyPathsByTransientEntity.get( transientEntity );
if ( propertyPaths == null ) {
@ -56,22 +53,48 @@ public class NonNullableTransientDependencies {
return propertyPathsByTransientEntity.keySet();
}
/**
* Retrieve the paths that refer to the transient entity
*
* @param entity The transient entity
*
* @return The property paths
*/
public Iterable<String> getNonNullableTransientPropertyPaths(Object entity) {
return propertyPathsByTransientEntity.get( entity );
}
/**
* Are there any paths currently tracked here?
*
* @return {@code true} indicates there are no path tracked here currently
*/
public boolean isEmpty() {
return propertyPathsByTransientEntity.isEmpty();
}
/**
* Clean up any tracked references for the given entity, throwing an exception if there were any paths.
*
* @param entity The entity
*
* @throws IllegalStateException If the entity had tracked paths
*/
public void resolveNonNullableTransientEntity(Object entity) {
if ( propertyPathsByTransientEntity.remove( entity ) == null ) {
throw new IllegalStateException( "Attempt to resolve a non-nullable, transient entity that is not a dependency." );
}
}
/**
* Build a loggable representation of the paths tracked here at the moment.
*
* @param session The session (used to resolve entity names)
*
* @return The loggable representation
*/
public String toLoggableString(SessionImplementor session) {
StringBuilder sb = new StringBuilder( getClass().getSimpleName() ).append( '[' );
final StringBuilder sb = new StringBuilder( getClass().getSimpleName() ).append( '[' );
for ( Map.Entry<Object,Set<String>> entry : propertyPathsByTransientEntity.entrySet() ) {
sb.append( "transientEntityName=" ).append( session.bestGuessEntityName( entry.getKey() ) );
sb.append( " requiredBy=" ).append( entry.getValue() );

View File

@ -42,10 +42,14 @@ import org.hibernate.type.Type;
* @author Gavin King
*/
public final class Nullability {
private final SessionImplementor session;
private final boolean checkNullability;
/**
* Constructs a Nullability
*
* @param session The session
*/
public Nullability(SessionImplementor session) {
this.session = session;
this.checkNullability = session.getFactory().getSettings().isCheckNullability();
@ -56,14 +60,14 @@ public final class Nullability {
* @param values entity properties
* @param persister class persister
* @param isUpdate whether it is intended to be updated or saved
* @throws org.hibernate.PropertyValueException Break the nullability of one property
*
* @throws PropertyValueException Break the nullability of one property
* @throws HibernateException error while getting Component values
*/
public void checkNullability(
final Object[] values,
final EntityPersister persister,
final boolean isUpdate)
throws PropertyValueException, HibernateException {
final boolean isUpdate) throws HibernateException {
/*
* Typically when Bean Validation is on, we don't want to validate null values
* at the Hibernate Core level. Hence the checkNullability setting.
@ -108,9 +112,8 @@ public final class Nullability {
}
else if ( value != null ) {
//values is not null and is checkable, we'll look deeper
String breakProperties = checkSubElementsNullability( propertyTypes[i], value );
final String breakProperties = checkSubElementsNullability( propertyTypes[i], value );
if ( breakProperties != null ) {
throw new PropertyValueException(
"not-null property references a null or transient value",
@ -136,8 +139,8 @@ public final class Nullability {
* @return property path
* @throws HibernateException error while getting subcomponent values
*/
private String checkSubElementsNullability(final Type propertyType, final Object value)
throws HibernateException {
private String checkSubElementsNullability(final Type propertyType, final Object value)
throws HibernateException {
//for non null args, check for components and elements containing components
if ( propertyType.isComponentType() ) {
return checkComponentNullability( value, (CompositeType) propertyType );
@ -145,17 +148,17 @@ public final class Nullability {
else if ( propertyType.isCollectionType() ) {
//persistent collections may have components
CollectionType collectionType = (CollectionType) propertyType;
Type collectionElementType = collectionType.getElementType( session.getFactory() );
final CollectionType collectionType = (CollectionType) propertyType;
final Type collectionElementType = collectionType.getElementType( session.getFactory() );
if ( collectionElementType.isComponentType() ) {
//check for all components values in the collection
CompositeType componentType = (CompositeType) collectionElementType;
Iterator iter = CascadingActions.getLoadedElementsIterator( session, collectionType, value );
while ( iter.hasNext() ) {
Object compValue = iter.next();
if (compValue != null) {
return checkComponentNullability(compValue, componentType);
final CompositeType componentType = (CompositeType) collectionElementType;
final Iterator itr = CascadingActions.getLoadedElementsIterator( session, collectionType, value );
while ( itr.hasNext() ) {
Object compValue = itr.next();
if ( compValue != null ) {
return checkComponentNullability( compValue, componentType );
}
}
}
@ -174,11 +177,11 @@ public final class Nullability {
* @throws HibernateException error while getting subcomponent values
*/
private String checkComponentNullability(final Object value, final CompositeType compType)
throws HibernateException {
throws HibernateException {
/* will check current level if some of them are not null
* or sublevels if they exist
*/
boolean[] nullability = compType.getPropertyNullability();
final boolean[] nullability = compType.getPropertyNullability();
if ( nullability!=null ) {
//do the test
final Object[] values = compType.getPropertyValues( value, EntityMode.POJO );
@ -189,27 +192,26 @@ public final class Nullability {
return compType.getPropertyNames()[i];
}
else if ( subvalue != null ) {
String breakProperties = checkSubElementsNullability( propertyTypes[i], subvalue );
final String breakProperties = checkSubElementsNullability( propertyTypes[i], subvalue );
if ( breakProperties != null ) {
return buildPropertyPath( compType.getPropertyNames()[i], breakProperties );
}
}
}
}
}
}
return null;
}
/**
* Return a well formed property path.
* Basically, it will return parent.child
* Return a well formed property path. Basically, it will return parent.child
*
* @param parent parent in path
* @param child child in path
*
* @return parent-child path
*/
private static String buildPropertyPath(String parent, String child) {
return new StringBuilder( parent.length() + child.length() + 1 )
.append(parent).append('.').append(child).toString();
return parent + '.' + child;
}
}

View File

@ -46,48 +46,74 @@ import org.hibernate.type.Type;
* @author Steve Ebersole
*/
public class ParameterBinder {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
ParameterBinder.class.getName()
);
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, ParameterBinder.class.getName());
/**
* Helper contract for dealing with named parameters and resolving their locations
*/
public static interface NamedParameterSource {
/**
* Retrieve the locations for the given parameter name
*
* @param name The parameter name
*
* @return The locations
*/
public int[] getNamedParameterLocations(String name);
}
private ParameterBinder() {
}
/**
* Perform parameter binding
*
* @param st The statement to bind parameters to
* @param queryParameters The parameters
* @param start The initial bind position
* @param source The named parameter source, for resolving the locations of named parameters
* @param session The session
*
* @return The next bind position after the last position we bound here.
*
* @throws SQLException Indicates a problem calling JDBC bind methods
* @throws HibernateException Indicates a problem access bind values.
*/
public static int bindQueryParameters(
final PreparedStatement st,
final QueryParameters queryParameters,
final int start,
final NamedParameterSource source,
SessionImplementor session) throws SQLException, HibernateException {
final PreparedStatement st,
final QueryParameters queryParameters,
final int start,
final NamedParameterSource source,
SessionImplementor session) throws SQLException, HibernateException {
int col = start;
col += bindPositionalParameters( st, queryParameters, col, session );
col += bindNamedParameters( st, queryParameters, col, source, session );
return col;
}
public static int bindPositionalParameters(
final PreparedStatement st,
final QueryParameters queryParameters,
final int start,
final SessionImplementor session) throws SQLException, HibernateException {
private static int bindPositionalParameters(
final PreparedStatement st,
final QueryParameters queryParameters,
final int start,
final SessionImplementor session) throws SQLException, HibernateException {
return bindPositionalParameters(
st,
queryParameters.getPositionalParameterValues(),
queryParameters.getPositionalParameterTypes(),
start,
session
st,
queryParameters.getPositionalParameterValues(),
queryParameters.getPositionalParameterTypes(),
start,
session
);
}
public static int bindPositionalParameters(
final PreparedStatement st,
final Object[] values,
final Type[] types,
final int start,
final SessionImplementor session) throws SQLException, HibernateException {
private static int bindPositionalParameters(
final PreparedStatement st,
final Object[] values,
final Type[] types,
final int start,
final SessionImplementor session) throws SQLException, HibernateException {
int span = 0;
for ( int i = 0; i < values.length; i++ ) {
types[i].nullSafeSet( st, values[i], start + span, session );
@ -96,41 +122,46 @@ public class ParameterBinder {
return span;
}
public static int bindNamedParameters(
final PreparedStatement ps,
final QueryParameters queryParameters,
final int start,
final NamedParameterSource source,
final SessionImplementor session) throws SQLException, HibernateException {
private static int bindNamedParameters(
final PreparedStatement ps,
final QueryParameters queryParameters,
final int start,
final NamedParameterSource source,
final SessionImplementor session) throws SQLException, HibernateException {
return bindNamedParameters( ps, queryParameters.getNamedParameters(), start, source, session );
}
public static int bindNamedParameters(
final PreparedStatement ps,
final Map namedParams,
final int start,
final NamedParameterSource source,
final SessionImplementor session) throws SQLException, HibernateException {
private static int bindNamedParameters(
final PreparedStatement ps,
final Map namedParams,
final int start,
final NamedParameterSource source,
final SessionImplementor session) throws SQLException, HibernateException {
if ( namedParams != null ) {
final boolean debugEnabled = LOG.isDebugEnabled();
// assumes that types are all of span 1
Iterator iter = namedParams.entrySet().iterator();
final Iterator iter = namedParams.entrySet().iterator();
int result = 0;
while ( iter.hasNext() ) {
Map.Entry e = ( Map.Entry ) iter.next();
String name = ( String ) e.getKey();
TypedValue typedval = (TypedValue) e.getValue();
final Map.Entry e = (Map.Entry) iter.next();
final String name = (String) e.getKey();
final TypedValue typedVal = (TypedValue) e.getValue();
int[] locations = source.getNamedParameterLocations( name );
for ( int i = 0; i < locations.length; i++ ) {
for ( int location : locations ) {
if ( debugEnabled ) {
LOG.debugf("bindNamedParameters() %s -> %s [%s]", typedval.getValue(), name, locations[i] + start);
LOG.debugf(
"bindNamedParameters() %s -> %s [%s]",
typedVal.getValue(),
name,
location + start
);
}
typedval.getType().nullSafeSet( ps, typedval.getValue(), locations[i] + start, session );
typedVal.getType().nullSafeSet( ps, typedVal.getValue(), location + start, session );
}
result += locations.length;
}
return result;
}
return 0;
return 0;
}
}

View File

@ -56,17 +56,19 @@ import org.hibernate.type.Type;
import org.hibernate.type.TypeHelper;
/**
* Functionality relating to Hibernate's two-phase loading process,
* that may be reused by persisters that do not use the Loader
* framework
* Functionality relating to the Hibernate two-phase loading process, that may be reused by persisters
* that do not use the Loader framework
*
* @author Gavin King
*/
public final class TwoPhaseLoad {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
TwoPhaseLoad.class.getName()
);
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, TwoPhaseLoad.class.getName() );
private TwoPhaseLoad() {}
private TwoPhaseLoad() {
}
/**
* Register the "hydrated" state of an entity instance, after the first step of 2-phase loading.
@ -74,19 +76,26 @@ public final class TwoPhaseLoad {
* Add the "hydrated state" (an array) of an uninitialized entity to the session. We don't try
* to resolve any associations yet, because there might be other entities waiting to be
* read from the JDBC result set we are currently processing
*
* @param persister The persister for the hydrated entity
* @param id The entity identifier
* @param values The entity values
* @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(
final EntityPersister persister,
final Serializable id,
final Object[] values,
final Object rowId,
final Object object,
final LockMode lockMode,
final boolean lazyPropertiesAreUnfetched,
final SessionImplementor session)
throws HibernateException {
Object version = Versioning.getVersion( values, persister );
final EntityPersister persister,
final Serializable id,
final Object[] values,
final Object rowId,
final Object object,
final LockMode lockMode,
final boolean lazyPropertiesAreUnFetched,
final SessionImplementor session) throws HibernateException {
final Object version = Versioning.getVersion( values, persister );
session.getPersistenceContext().addEntry(
object,
Status.LOADING,
@ -98,47 +107,41 @@ public final class TwoPhaseLoad {
true,
persister,
false,
lazyPropertiesAreUnfetched
lazyPropertiesAreUnFetched
);
if ( version != null && LOG.isTraceEnabled() ) {
String versionStr = persister.isVersioned()
final String versionStr = persister.isVersioned()
? persister.getVersionType().toLoggableString( version, session.getFactory() )
: "null";
LOG.tracev( "Version: {0}", versionStr );
LOG.tracef( "Version: %s", versionStr );
}
}
/**
* Perform the second step of 2-phase load. Fully initialize the entity
* instance.
*
* <p/>
* After processing a JDBC result set, we "resolve" all the associations
* between the entities which were instantiated and had their state
* "hydrated" into an array
*
* @param entity The entity being loaded
* @param readOnly Is the entity being loaded as read-only
* @param session The Session
* @param preLoadEvent The (re-used) pre-load event
*/
public static void initializeEntity(
final Object entity,
final boolean readOnly,
final SessionImplementor session,
final PreLoadEvent preLoadEvent,
final PostLoadEvent postLoadEvent) throws HibernateException {
final PreLoadEvent preLoadEvent) {
final PersistenceContext persistenceContext = session.getPersistenceContext();
final EntityEntry entityEntry = persistenceContext.getEntry(entity);
final EntityEntry entityEntry = persistenceContext.getEntry( entity );
if ( entityEntry == null ) {
throw new AssertionFailure( "possible non-threadsafe access to the session" );
}
final EntityPersister persister = entityEntry.getPersister();
final Serializable id = entityEntry.getId();
// persistenceContext.getNaturalIdHelper().startingLoad( persister, id );
// try {
doInitializeEntity( entity, entityEntry, readOnly, session, preLoadEvent, postLoadEvent );
// }
// finally {
// persistenceContext.getNaturalIdHelper().endingLoad( persister, id );
// }
doInitializeEntity( entity, entityEntry, readOnly, session, preLoadEvent );
}
private static void doInitializeEntity(
@ -146,12 +149,11 @@ public final class TwoPhaseLoad {
final EntityEntry entityEntry,
final boolean readOnly,
final SessionImplementor session,
final PreLoadEvent preLoadEvent,
final PostLoadEvent postLoadEvent) throws HibernateException {
final PreLoadEvent preLoadEvent) throws HibernateException {
final PersistenceContext persistenceContext = session.getPersistenceContext();
EntityPersister persister = entityEntry.getPersister();
Serializable id = entityEntry.getId();
Object[] hydratedState = entityEntry.getLoadedState();
final EntityPersister persister = entityEntry.getPersister();
final Serializable id = entityEntry.getId();
final Object[] hydratedState = entityEntry.getLoadedState();
final boolean debugEnabled = LOG.isDebugEnabled();
if ( debugEnabled ) {
@ -161,7 +163,7 @@ public final class TwoPhaseLoad {
);
}
Type[] types = persister.getPropertyTypes();
final Type[] types = persister.getPropertyTypes();
for ( int i = 0; i < hydratedState.length; i++ ) {
final Object value = hydratedState[i];
if ( value!=LazyPropertyInitializer.UNFETCHED_PROPERTY && value!=BackrefPropertyAccessor.UNKNOWN ) {
@ -195,9 +197,9 @@ public final class TwoPhaseLoad {
);
}
Object version = Versioning.getVersion(hydratedState, persister);
CacheEntry entry = persister.buildCacheEntry( entity, hydratedState, version, session );
CacheKey cacheKey = session.generateCacheKey( id, persister.getIdentifierType(), persister.getRootEntityName() );
final Object version = Versioning.getVersion( hydratedState, persister );
final CacheEntry entry = persister.buildCacheEntry( entity, hydratedState, version, session );
final CacheKey cacheKey = session.generateCacheKey( id, persister.getIdentifierType(), persister.getRootEntityName() );
// explicit handling of caching for rows just inserted and then somehow forced to be read
// from the database *within the same transaction*. usually this is done by
@ -214,7 +216,7 @@ public final class TwoPhaseLoad {
);
}
else {
boolean put = persister.getCacheAccessStrategy().putFromLoad(
final boolean put = persister.getCacheAccessStrategy().putFromLoad(
cacheKey,
persister.getCacheEntryStructure().structure( entry ),
session.getTimestamp(),
@ -241,11 +243,11 @@ public final class TwoPhaseLoad {
isReallyReadOnly = true;
}
else {
Object proxy = persistenceContext.getProxy( entityEntry.getEntityKey() );
final Object proxy = persistenceContext.getProxy( entityEntry.getEntityKey() );
if ( proxy != null ) {
// there is already a proxy for this impl
// only set the status to read-only if the proxy is read-only
isReallyReadOnly = ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer().isReadOnly();
isReallyReadOnly = ( (HibernateProxy) proxy ).getHibernateLazyInitializer().isReadOnly();
}
}
if ( isReallyReadOnly ) {
@ -253,7 +255,7 @@ public final class TwoPhaseLoad {
//performance optimization, but not really
//important, except for entities with huge
//mutable property values
persistenceContext.setEntryStatus(entityEntry, Status.READ_ONLY);
persistenceContext.setEntryStatus( entityEntry, Status.READ_ONLY );
}
else {
//take a snapshot
@ -261,10 +263,11 @@ public final class TwoPhaseLoad {
hydratedState,
persister.getPropertyTypes(),
persister.getPropertyUpdateability(),
hydratedState, //after setting values to object, entityMode
//after setting values to object
hydratedState,
session
);
persistenceContext.setEntryStatus(entityEntry, Status.MANAGED);
persistenceContext.setEntryStatus( entityEntry, Status.MANAGED );
}
persister.afterInitialize(
@ -290,13 +293,12 @@ public final class TwoPhaseLoad {
* the Set collections are added to the persistence context by Loader.
* Without the split, LazyInitializationExceptions can occur in the Entity's
* postLoad if it acts upon the collection.
*
*
*
* HHH-6043
*
* @param entity
* @param session
* @param postLoadEvent
* @param entity The entity
* @param session The Session
* @param postLoadEvent The (re-used) post-load event
*/
public static void postLoad(
final Object entity,
@ -306,15 +308,11 @@ public final class TwoPhaseLoad {
if ( session.isEventSource() ) {
final PersistenceContext persistenceContext
= session.getPersistenceContext();
final EntityEntry entityEntry = persistenceContext.getEntry(entity);
final Serializable id = entityEntry.getId();
postLoadEvent.setEntity( entity ).setId( entityEntry.getId() )
.setPersister( entityEntry.getPersister() );
final EntityEntry entityEntry = persistenceContext.getEntry( entity );
final EventListenerGroup<PostLoadEventListener> listenerGroup
= session
.getFactory()
postLoadEvent.setEntity( entity ).setId( entityEntry.getId() ).setPersister( entityEntry.getPersister() );
final EventListenerGroup<PostLoadEventListener> listenerGroup = session.getFactory()
.getServiceRegistry()
.getService( EventListenerRegistry.class )
.getEventListenerGroup( EventType.POST_LOAD );
@ -325,11 +323,11 @@ 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() );
return ( session.getFactory().getSettings().isMinimalPutsEnabled()
&& session.getCacheMode()!=CacheMode.REFRESH )
|| ( entityEntry.getPersister().hasLazyProperties()
&& entityEntry.isLoadedWithLazyPropertiesUnfetched()
&& entityEntry.getPersister().isLazyPropertiesCacheable() );
}
/**
@ -338,15 +336,21 @@ public final class TwoPhaseLoad {
*
* Create a "temporary" entry for a newly instantiated entity. The entity is uninitialized,
* but we need the mapping from id to instance in order to guarantee uniqueness.
*
* @param key The entity key
* @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(
final EntityKey key,
final Object object,
final EntityPersister persister,
final LockMode lockMode,
final boolean lazyPropertiesAreUnfetched,
final SessionImplementor session
) {
final boolean lazyPropertiesAreUnFetched,
final SessionImplementor session) {
session.getPersistenceContext().addEntity(
object,
Status.LOADING,
@ -357,19 +361,29 @@ public final class TwoPhaseLoad {
true,
persister,
false,
lazyPropertiesAreUnfetched
);
lazyPropertiesAreUnFetched
);
}
/**
* Same as {@link #addUninitializedEntity}, but here for an entity from the second level cache
*
* @param key The entity key
* @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
*/
public static void addUninitializedCachedEntity(
final EntityKey key,
final Object object,
final EntityPersister persister,
final LockMode lockMode,
final boolean lazyPropertiesAreUnfetched,
final boolean lazyPropertiesAreUnFetched,
final Object version,
final SessionImplementor session
) {
final SessionImplementor session) {
session.getPersistenceContext().addEntity(
object,
Status.LOADING,
@ -380,7 +394,7 @@ public final class TwoPhaseLoad {
true,
persister,
false,
lazyPropertiesAreUnfetched
lazyPropertiesAreUnFetched
);
}
}

View File

@ -37,13 +37,24 @@ import org.hibernate.type.Type;
import org.hibernate.type.VersionType;
/**
* Helper for dealing with unsaved value handling
*
* @author Gavin King
*/
public class UnsavedValueFactory {
/**
* Instantiate a class using the provided Constructor
*
* @param constructor The constructor
*
* @return The instantiated object
*
* @throws InstantiationException if something went wrong
*/
private static Object instantiate(Constructor constructor) {
try {
return constructor.newInstance( (Object[]) null );
return constructor.newInstance();
}
catch (Exception e) {
throw new InstantiationException( "could not instantiate test object", constructor.getDeclaringClass(), e );
@ -54,22 +65,28 @@ public class UnsavedValueFactory {
* Return an IdentifierValue for the specified unsaved-value. If none is specified,
* guess the unsaved value by instantiating a test instance of the class and
* reading it's id property, or if that is not possible, using the java default
* value for the type
* value for the type
*
* @param unsavedValue The mapping defined unsaved value
* @param identifierGetter The getter for the entity identifier attribute
* @param identifierType The mapping type for the identifier
* @param constructor The constructor for the entity
*
* @return The appropriate IdentifierValue
*/
public static IdentifierValue getUnsavedIdentifierValue(
String unsavedValue,
String unsavedValue,
Getter identifierGetter,
Type identifierType,
Constructor constructor) {
if ( unsavedValue == null ) {
if ( identifierGetter!=null && constructor!=null ) {
if ( identifierGetter != null && constructor != null ) {
// use the id value of a newly instantiated instance as the unsaved-value
Serializable defaultValue = (Serializable) identifierGetter.get( instantiate(constructor) );
final Serializable defaultValue = (Serializable) identifierGetter.get( instantiate(constructor) );
return new IdentifierValue( defaultValue );
}
else if ( identifierGetter != null && (identifierType instanceof PrimitiveType) ) {
Serializable defaultValue = ( ( PrimitiveType ) identifierType ).getDefaultValue();
final Serializable defaultValue = ( (PrimitiveType) identifierType ).getDefaultValue();
return new IdentifierValue( defaultValue );
}
else {
@ -90,7 +107,7 @@ public class UnsavedValueFactory {
}
else {
try {
return new IdentifierValue( ( Serializable ) ( ( IdentifierType ) identifierType ).stringToObject( unsavedValue ) );
return new IdentifierValue( (Serializable) ( (IdentifierType) identifierType ).stringToObject( unsavedValue ) );
}
catch ( ClassCastException cce ) {
throw new MappingException( "Bad identifier type: " + identifierType.getName() );
@ -101,6 +118,19 @@ public class UnsavedValueFactory {
}
}
/**
* Return an IdentifierValue for the specified unsaved-value. If none is specified,
* guess the unsaved value by instantiating a test instance of the class and
* reading it's version property value, or if that is not possible, using the java default
* value for the type
*
* @param versionUnsavedValue The mapping defined unsaved value
* @param versionGetter The version attribute getter
* @param versionType The mapping type for the version
* @param constructor The constructor for the entity
*
* @return The appropriate VersionValue
*/
public static VersionValue getUnsavedVersionValue(
String versionUnsavedValue,
Getter versionGetter,
@ -109,12 +139,12 @@ public class UnsavedValueFactory {
if ( versionUnsavedValue == null ) {
if ( constructor!=null ) {
Object defaultValue = versionGetter.get( instantiate(constructor) );
final Object defaultValue = versionGetter.get( instantiate( constructor ) );
// if the version of a newly instantiated object is not the same
// as the version seed value, use that as the unsaved-value
return versionType.isEqual( versionType.seed( null ), defaultValue ) ?
VersionValue.UNDEFINED :
new VersionValue( defaultValue );
return versionType.isEqual( versionType.seed( null ), defaultValue )
? VersionValue.UNDEFINED
: new VersionValue( defaultValue );
}
else {
return VersionValue.UNDEFINED;
@ -133,7 +163,8 @@ public class UnsavedValueFactory {
// this should not happen since the DTD prevents it
throw new MappingException( "Could not parse version unsaved-value: " + versionUnsavedValue );
}
}
private UnsavedValueFactory() {
}
}

View File

@ -36,38 +36,16 @@ import org.hibernate.type.VersionType;
* @author Gavin King
*/
public final class Versioning {
// todo : replace these constants with references to org.hibernate.annotations.OptimisticLockType enum
/**
* Apply no optimistic locking
*/
public static final int OPTIMISTIC_LOCK_NONE = -1;
/**
* Apply optimistic locking based on the defined version or timestamp
* property.
*/
public static final int OPTIMISTIC_LOCK_VERSION = 0;
/**
* Apply optimistic locking based on the a current vs. snapshot comparison
* of <b>all</b> properties.
*/
public static final int OPTIMISTIC_LOCK_ALL = 2;
/**
* Apply optimistic locking based on the a current vs. snapshot comparison
* of <b>dirty</b> properties.
*/
public static final int OPTIMISTIC_LOCK_DIRTY = 1;
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, Versioning.class.getName() );
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
Versioning.class.getName()
);
/**
* Private constructor disallowing instantiation.
*/
private Versioning() {}
private Versioning() {
}
/**
* Create an initial optimistic locking value according the {@link VersionType}
@ -78,8 +56,8 @@ public final class Versioning {
* @return The initial optimistic locking value
*/
private static Object seed(VersionType versionType, SessionImplementor session) {
Object seed = versionType.seed( session );
LOG.tracev( "Seeding: {0}", seed );
final Object seed = versionType.seed( session );
LOG.tracef( "Seeding: %s", seed );
return seed;
}
@ -96,11 +74,11 @@ public final class Versioning {
* otherwise.
*/
public static boolean seedVersion(
Object[] fields,
int versionProperty,
VersionType versionType,
SessionImplementor session) {
Object initialVersion = fields[versionProperty];
Object[] fields,
int versionProperty,
VersionType versionType,
SessionImplementor session) {
final Object initialVersion = fields[versionProperty];
if (
initialVersion==null ||
// This next bit is to allow for both unsaved-value="negative"
@ -126,11 +104,15 @@ public final class Versioning {
* @param session The originating session
* @return The incremented optimistic locking value.
*/
@SuppressWarnings("unchecked")
public static Object increment(Object version, VersionType versionType, SessionImplementor session) {
Object next = versionType.next( version, session );
final Object next = versionType.next( version, session );
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Incrementing: {0} to {1}", versionType.toLoggableString( version, session.getFactory() ),
versionType.toLoggableString( next, session.getFactory() ) );
LOG.tracef(
"Incrementing: %s to %s",
versionType.toLoggableString( version, session.getFactory() ),
versionType.toLoggableString( next, session.getFactory() )
);
}
return next;
}
@ -178,8 +160,8 @@ public final class Versioning {
if ( hasDirtyCollections ) {
return true;
}
for ( int i = 0; i < dirtyProperties.length; i++ ) {
if ( propertyVersionability[ dirtyProperties[i] ] ) {
for ( int dirtyProperty : dirtyProperties ) {
if ( propertyVersionability[dirtyProperty] ) {
return true;
}
}

View File

@ -33,6 +33,7 @@ import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.loading.internal.LoadContexts;
import org.hibernate.internal.util.MarkerObject;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
@ -52,7 +53,11 @@ import org.hibernate.persister.entity.EntityPersister;
*/
@SuppressWarnings( {"JavaDoc"})
public interface PersistenceContext {
/**
* Marker object used to indicate (via reference checking) that no row was returned.
*/
public static final Object NO_ROW = new MarkerObject( "NO_ROW" );
@SuppressWarnings( {"UnusedDeclaration"})
public boolean isStateless();
@ -135,11 +140,15 @@ public interface PersistenceContext {
public Object[] getDatabaseSnapshot(Serializable id, EntityPersister persister);
/**
* Get the current database state of the entity, using the cached state snapshot if one is available.
*
* @param key The entity key
*
* @return The entity's (non-cached) snapshot
* Retrieve the cached database snapshot for the requested entity key.
* <p/>
* This differs from {@link #getDatabaseSnapshot} is two important respects:<ol>
* <li>no snapshot is obtained from the database if not already cached</li>
* <li>an entry of {@link #NO_ROW} here is interpretet as an exception</li>
* </ol>
* @param key The entity key for which to retrieve the cached snapshot
* @return The cached snapshot
* @throws IllegalStateException if the cached snapshot was == {@link #NO_ROW}.
*/
public Object[] getCachedDatabaseSnapshot(EntityKey key);
@ -316,7 +325,9 @@ public interface PersistenceContext {
/**
* Attempts to check whether the given key represents an entity already loaded within the
* current session.
*
* @param object The entity reference against which to perform the uniqueness check.
*
* @throws HibernateException
*/
public void checkUniqueness(EntityKey key, Object object) throws HibernateException;
@ -467,7 +478,13 @@ public interface PersistenceContext {
public void addProxy(EntityKey key, Object proxy);
/**
* Remove a proxy from the session cache
* Remove a proxy from the session cache.
* <p/>
* Additionally, ensure that any load optimization references
* such as batch or subselect loading get cleaned up as well.
*
* @param key The key of the entity proxy to be removed
* @return The proxy reference.
*/
public Object removeProxy(EntityKey key);
@ -559,10 +576,27 @@ public interface PersistenceContext {
public String toString();
/**
* Search the persistence context for an owner for the child object,
* given a collection role
* Search <tt>this</tt> persistence context for an associated entity instance which is considered the "owner" of
* the given <tt>childEntity</tt>, and return that owner's id value. This is performed in the scenario of a
* uni-directional, non-inverse one-to-many collection (which means that the collection elements do not maintain
* a direct reference to the owner).
* <p/>
* As such, the processing here is basically to loop over every entity currently associated with this persistence
* context and for those of the correct entity (sub) type to extract its collection role property value and see
* if the child is contained within that collection. If so, we have found the owner; if not, we go on.
* <p/>
* Also need to account for <tt>mergeMap</tt> which acts as a local copy cache managed for the duration of a merge
* operation. It represents a map of the detached entity instances pointing to the corresponding managed instance.
*
* @param entityName The entity name for the entity type which would own the child
* @param propertyName The name of the property on the owning entity type which would name this child association.
* @param childEntity The child entity instance for which to locate the owner instance id.
* @param mergeMap A map of non-persistent instances from an on-going merge operation (possibly null).
*
* @return The id of the entityName instance which is said to own the child; null if an appropriate owner not
* located.
*/
public Serializable getOwnerId(String entity, String property, Object childObject, Map mergeMap);
public Serializable getOwnerId(String entityName, String propertyName, Object childEntity, Map mergeMap);
/**
* Search the persistence context for an index of the child object,

View File

@ -1099,7 +1099,7 @@ public abstract class Loader {
if ( LOG.isTraceEnabled() )
LOG.tracev( "Total objects hydrated: {0}", hydratedObjectsSize );
for ( int i = 0; i < hydratedObjectsSize; i++ ) {
TwoPhaseLoad.initializeEntity( hydratedObjects.get(i), readOnly, session, pre, post );
TwoPhaseLoad.initializeEntity( hydratedObjects.get(i), readOnly, session, pre );
}
}

View File

@ -664,7 +664,7 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
}
// now finish loading the entities (2-phase load)
performTwoPhaseLoad( preLoadEvent, postLoadEvent );
performTwoPhaseLoad( preLoadEvent );
// now we can finalize loading collections
finishLoadingCollections();
@ -699,7 +699,7 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
);
}
private void performTwoPhaseLoad(PreLoadEvent preLoadEvent, PostLoadEvent postLoadEvent) {
private void performTwoPhaseLoad(PreLoadEvent preLoadEvent) {
final int numberOfHydratedObjects = hydratedEntityRegistrationList == null
? 0
: hydratedEntityRegistrationList.size();
@ -710,7 +710,7 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
}
for ( HydratedEntityRegistration registration : hydratedEntityRegistrationList ) {
TwoPhaseLoad.initializeEntity( registration.instance, readOnly, session, preLoadEvent, postLoadEvent );
TwoPhaseLoad.initializeEntity( registration.instance, readOnly, session, preLoadEvent );
}
}

View File

@ -33,6 +33,8 @@ import java.util.StringTokenizer;
import org.hibernate.EntityMode;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.internal.FilterConfiguration;
@ -100,9 +102,9 @@ public abstract class PersistentClass implements Serializable, Filterable, MetaA
private java.util.Map tuplizerImpls;
protected int optimisticLockMode;
private MappedSuperclass superMappedSuperclass;
private Component declaredIdentifierMapper;
private OptimisticLockStyle optimisticLockStyle;
public String getClassName() {
return className;
@ -456,10 +458,22 @@ public abstract class PersistentClass implements Serializable, Filterable, MetaA
}
}
abstract public int getOptimisticLockMode();
@Deprecated
public int getOptimisticLockMode() {
return getOptimisticLockStyle().getOldCode();
}
@Deprecated
public void setOptimisticLockMode(int optimisticLockMode) {
this.optimisticLockMode = optimisticLockMode;
setOptimisticLockStyle( OptimisticLockStyle.interpretOldCode( optimisticLockMode ) );
}
public OptimisticLockStyle getOptimisticLockStyle() {
return optimisticLockStyle;
}
public void setOptimisticLockStyle(OptimisticLockStyle optimisticLockStyle) {
this.optimisticLockStyle = optimisticLockStyle;
}
public void validate(Mapping mapping) throws MappingException {

View File

@ -31,6 +31,7 @@ import java.util.Set;
import org.jboss.logging.Logger;
import org.hibernate.MappingException;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
@ -351,10 +352,4 @@ public class RootClass extends PersistentClass implements TableOwner {
public Object accept(PersistentClassVisitor mv) {
return mv.accept(this);
}
@Override
public int getOptimisticLockMode() {
return optimisticLockMode;
}
}

View File

@ -30,6 +30,7 @@ import java.util.Map;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.internal.util.collections.JoinedIterator;
import org.hibernate.internal.util.collections.SingletonIterator;
@ -295,9 +296,9 @@ public class Subclass extends PersistentClass {
public Component getIdentifierMapper() {
return superclass.getIdentifierMapper();
}
public int getOptimisticLockMode() {
return superclass.getOptimisticLockMode();
}
@Override
public OptimisticLockStyle getOptimisticLockStyle() {
return superclass.getOptimisticLockStyle();
}
}

View File

@ -325,7 +325,7 @@ public class EntityMetamodel implements Serializable {
null;
hasSubclasses = persistentClass.hasSubclasses();
optimisticLockStyle = interpretOptLockMode( persistentClass.getOptimisticLockMode() );
optimisticLockStyle = persistentClass.getOptimisticLockStyle();
final boolean isAllOrDirty =
optimisticLockStyle == OptimisticLockStyle.ALL
|| optimisticLockStyle == OptimisticLockStyle.DIRTY;
@ -365,23 +365,6 @@ public class EntityMetamodel implements Serializable {
}
}
private OptimisticLockStyle interpretOptLockMode(int optimisticLockMode) {
switch ( optimisticLockMode ) {
case Versioning.OPTIMISTIC_LOCK_NONE: {
return OptimisticLockStyle.NONE;
}
case Versioning.OPTIMISTIC_LOCK_DIRTY: {
return OptimisticLockStyle.DIRTY;
}
case Versioning.OPTIMISTIC_LOCK_ALL: {
return OptimisticLockStyle.ALL;
}
default: {
return OptimisticLockStyle.VERSION;
}
}
}
public EntityMetamodel(
EntityBinding entityBinding,
AbstractEntityPersister persister,

View File

@ -52,7 +52,7 @@ public class NewCustomEntityMappingAnnotationsTest extends BaseCoreFunctionalTes
assertEquals( forest.useDynamicInsert(), forest2.useDynamicInsert() );
assertEquals( forest.useDynamicUpdate(), forest2.useDynamicUpdate() );
assertEquals( forest.hasSelectBeforeUpdate(), forest2.hasSelectBeforeUpdate() );
assertEquals( forest.getOptimisticLockMode(), forest2.getOptimisticLockMode() );
assertEquals( forest.getOptimisticLockStyle(), forest2.getOptimisticLockStyle() );
assertEquals( forest.isExplicitPolymorphism(), forest2.isExplicitPolymorphism() );
}
}

View File

@ -309,7 +309,7 @@ public class CustomPersister implements EntityPersister {
LockMode.NONE,
false,
session
);
);
TwoPhaseLoad.postHydrate(
this, id,
new String[] { obj.getName() },
@ -318,14 +318,14 @@ public class CustomPersister implements EntityPersister {
LockMode.NONE,
false,
session
);
);
TwoPhaseLoad.initializeEntity(
clone,
false,
session,
new PreLoadEvent( (EventSource) session ),
new PostLoadEvent( (EventSource) session )
);
new PreLoadEvent( (EventSource) session )
);
TwoPhaseLoad.postLoad( clone, session, new PostLoadEvent( (EventSource) session ) );
}
return clone;
}