HHH-8159 - Apply fixups indicated by analysis tools
This commit is contained in:
parent
021401835c
commit
b51164aef6
|
@ -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() );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue