split up TypeHelper
This commit is contained in:
parent
6c3b74d39e
commit
38f4c70e7b
98
hibernate-core/src/main/java/org/hibernate/cache/spi/entry/CacheEntryHelper.java
vendored
Normal file
98
hibernate-core/src/main/java/org/hibernate/cache/spi/entry/CacheEntryHelper.java
vendored
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.cache.spi.entry;
|
||||||
|
|
||||||
|
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operations for assembly and disassembly of an array of property values.
|
||||||
|
*/
|
||||||
|
class CacheEntryHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the {@link Type#disassemble} operation across a series of values.
|
||||||
|
*
|
||||||
|
* @param row The values
|
||||||
|
* @param types The value types
|
||||||
|
* @param nonCacheable An array indicating which values to include in the disassembled state
|
||||||
|
* @param session The originating session
|
||||||
|
* @param owner The entity "owning" the values
|
||||||
|
*
|
||||||
|
* @return The disassembled state
|
||||||
|
*/
|
||||||
|
public static Serializable[] disassemble(
|
||||||
|
final Object[] row,
|
||||||
|
final Type[] types,
|
||||||
|
final boolean[] nonCacheable,
|
||||||
|
final SharedSessionContractImplementor session,
|
||||||
|
final Object owner) {
|
||||||
|
Serializable[] disassembled = new Serializable[row.length];
|
||||||
|
for ( int i = 0; i < row.length; i++ ) {
|
||||||
|
if ( nonCacheable!=null && nonCacheable[i] ) {
|
||||||
|
disassembled[i] = LazyPropertyInitializer.UNFETCHED_PROPERTY;
|
||||||
|
}
|
||||||
|
else if ( row[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY
|
||||||
|
| row[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
|
||||||
|
disassembled[i] = (Serializable) row[i];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
disassembled[i] = types[i].disassemble( row[i], session, owner );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return disassembled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the {@link Type#assemble} operation across a series of values.
|
||||||
|
*
|
||||||
|
* @param row The values
|
||||||
|
* @param types The value types
|
||||||
|
* @param session The originating session
|
||||||
|
* @param owner The entity "owning" the values
|
||||||
|
* @return The assembled state
|
||||||
|
*/
|
||||||
|
public static Object[] assemble(
|
||||||
|
final Serializable[] row,
|
||||||
|
final Type[] types,
|
||||||
|
final SharedSessionContractImplementor session,
|
||||||
|
final Object owner) {
|
||||||
|
Object[] assembled = new Object[row.length];
|
||||||
|
for ( int i = 0; i < types.length; i++ ) {
|
||||||
|
if ( row[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY
|
||||||
|
|| row[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
|
||||||
|
assembled[i] = row[i];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assembled[i] = types[i].assemble( row[i], session, owner );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assembled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static Object[] assemble(
|
||||||
|
// final Object[] row,
|
||||||
|
// final Type[] types,
|
||||||
|
// final SharedSessionContractImplementor session,
|
||||||
|
// final Object owner) {
|
||||||
|
// Object[] assembled = new Object[row.length];
|
||||||
|
// for ( int i = 0; i < types.length; i++ ) {
|
||||||
|
// if ( row[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY || row[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
|
||||||
|
// assembled[i] = row[i];
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// assembled[i] = types[i].assemble( (Serializable) row[i], session, owner );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return assembled;
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
|
@ -11,16 +11,12 @@ import java.io.Serializable;
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Interceptor;
|
import org.hibernate.Interceptor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.event.service.spi.EventListenerGroup;
|
import org.hibernate.event.service.spi.EventListenerGroup;
|
||||||
import org.hibernate.event.service.spi.EventListenerRegistry;
|
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.event.spi.EventType;
|
|
||||||
import org.hibernate.event.spi.PreLoadEvent;
|
import org.hibernate.event.spi.PreLoadEvent;
|
||||||
import org.hibernate.event.spi.PreLoadEventListener;
|
import org.hibernate.event.spi.PreLoadEventListener;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.type.TypeHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard representation of entity cached data using the "disassembled state".
|
* Standard representation of entity cached data using the "disassembled state".
|
||||||
|
@ -51,7 +47,7 @@ public class StandardCacheEntryImpl implements CacheEntry {
|
||||||
final SharedSessionContractImplementor session,
|
final SharedSessionContractImplementor session,
|
||||||
final Object owner) throws HibernateException {
|
final Object owner) throws HibernateException {
|
||||||
// disassembled state gets put in a new array (we write to cache by value!)
|
// disassembled state gets put in a new array (we write to cache by value!)
|
||||||
this.disassembledState = TypeHelper.disassemble(
|
this.disassembledState = CacheEntryHelper.disassemble(
|
||||||
state,
|
state,
|
||||||
persister.getPropertyTypes(),
|
persister.getPropertyTypes(),
|
||||||
persister.isLazyPropertiesCacheable() ? null : persister.getPropertyLaziness(),
|
persister.isLazyPropertiesCacheable() ? null : persister.getPropertyLaziness(),
|
||||||
|
@ -133,7 +129,7 @@ public class StandardCacheEntryImpl implements CacheEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
//assembled state gets put in a new array (we read from cache by value!)
|
//assembled state gets put in a new array (we read from cache by value!)
|
||||||
final Object[] state = TypeHelper.assemble(
|
final Object[] state = CacheEntryHelper.assemble(
|
||||||
disassembledState,
|
disassembledState,
|
||||||
persister.getPropertyTypes(),
|
persister.getPropertyTypes(),
|
||||||
session, instance
|
session, instance
|
||||||
|
|
|
@ -262,7 +262,6 @@ import org.hibernate.type.CollectionType;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
import org.hibernate.type.EntityType;
|
import org.hibernate.type.EntityType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
import org.hibernate.type.TypeHelper;
|
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||||
|
|
||||||
|
@ -4326,8 +4325,7 @@ public abstract class AbstractEntityPersister
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// we still need to verify collection fields to be eagerly loaded by 'join'
|
// we still need to verify collection fields to be eagerly loaded by 'join'
|
||||||
final NonIdentifierAttribute[] attributes = entityMetamodel.getProperties();
|
for ( NonIdentifierAttribute attribute : entityMetamodel.getProperties() ) {
|
||||||
for ( NonIdentifierAttribute attribute : attributes ) {
|
|
||||||
if ( attribute instanceof EntityBasedAssociationAttribute ) {
|
if ( attribute instanceof EntityBasedAssociationAttribute ) {
|
||||||
final AssociationType associationType = ( (EntityBasedAssociationAttribute) attribute ).getType();
|
final AssociationType associationType = ( (EntityBasedAssociationAttribute) attribute ).getType();
|
||||||
if ( associationType instanceof CollectionType ) {
|
if ( associationType instanceof CollectionType ) {
|
||||||
|
@ -4408,7 +4406,7 @@ public abstract class AbstractEntityPersister
|
||||||
*/
|
*/
|
||||||
public int[] findDirty(Object[] currentState, Object[] previousState, Object entity, SharedSessionContractImplementor session)
|
public int[] findDirty(Object[] currentState, Object[] previousState, Object entity, SharedSessionContractImplementor session)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
int[] props = TypeHelper.findDirty(
|
int[] props = DirtyHelper.findDirty(
|
||||||
entityMetamodel.getProperties(),
|
entityMetamodel.getProperties(),
|
||||||
currentState,
|
currentState,
|
||||||
previousState,
|
previousState,
|
||||||
|
@ -4437,7 +4435,7 @@ public abstract class AbstractEntityPersister
|
||||||
*/
|
*/
|
||||||
public int[] findModified(Object[] old, Object[] current, Object entity, SharedSessionContractImplementor session)
|
public int[] findModified(Object[] old, Object[] current, Object entity, SharedSessionContractImplementor session)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
int[] props = TypeHelper.findModified(
|
int[] props = DirtyHelper.findModified(
|
||||||
entityMetamodel.getProperties(),
|
entityMetamodel.getProperties(),
|
||||||
current,
|
current,
|
||||||
old,
|
old,
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.persister.entity;
|
||||||
|
|
||||||
|
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
|
import org.hibernate.tuple.NonIdentifierAttribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operations for searching an array of property values for modified elements.
|
||||||
|
*/
|
||||||
|
class DirtyHelper {
|
||||||
|
/**
|
||||||
|
* Determine if any of the given field values are dirty, returning an array containing
|
||||||
|
* indices of the dirty fields.
|
||||||
|
* <p/>
|
||||||
|
* If it is determined that no fields are dirty, null is returned.
|
||||||
|
*
|
||||||
|
* @param properties The property definitions
|
||||||
|
* @param currentState The current state of the entity
|
||||||
|
* @param previousState The baseline state of the entity
|
||||||
|
* @param includeColumns Columns to be included in the dirty checking, per property
|
||||||
|
* @param session The session from which the dirty check request originated.
|
||||||
|
*
|
||||||
|
* @return Array containing indices of the dirty properties, or null if no properties considered dirty.
|
||||||
|
*/
|
||||||
|
public static int[] findDirty(
|
||||||
|
final NonIdentifierAttribute[] properties,
|
||||||
|
final Object[] currentState,
|
||||||
|
final Object[] previousState,
|
||||||
|
final boolean[][] includeColumns,
|
||||||
|
final SharedSessionContractImplementor session) {
|
||||||
|
int[] results = null;
|
||||||
|
int count = 0;
|
||||||
|
int span = properties.length;
|
||||||
|
|
||||||
|
for ( int i = 0; i < span; i++ ) {
|
||||||
|
|
||||||
|
if ( isDirty( properties, currentState, previousState, includeColumns, session, i ) ) {
|
||||||
|
if ( results == null ) {
|
||||||
|
results = new int[span];
|
||||||
|
}
|
||||||
|
results[count++] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count == 0 ? null : ArrayHelper.trim( results, count );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isDirty(
|
||||||
|
NonIdentifierAttribute[] properties,
|
||||||
|
Object[] currentState,
|
||||||
|
Object[] previousState,
|
||||||
|
boolean[][] includeColumns,
|
||||||
|
SharedSessionContractImplementor session, int i) {
|
||||||
|
if ( currentState[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if ( previousState[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return properties[i].isDirtyCheckable()
|
||||||
|
&& properties[i].getType().isDirty( previousState[i], currentState[i], includeColumns[i], session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if any of the given field values are modified, returning an array containing
|
||||||
|
* indices of the modified fields.
|
||||||
|
* <p/>
|
||||||
|
* If it is determined that no fields are dirty, null is returned.
|
||||||
|
*
|
||||||
|
* @param properties The property definitions
|
||||||
|
* @param currentState The current state of the entity
|
||||||
|
* @param previousState The baseline state of the entity
|
||||||
|
* @param includeColumns Columns to be included in the mod checking, per property
|
||||||
|
* @param includeProperties Array of property indices that identify which properties participate in check
|
||||||
|
* @param session The session from which the dirty check request originated.
|
||||||
|
*
|
||||||
|
* @return Array containing indices of the modified properties, or null if no properties considered modified.
|
||||||
|
**/
|
||||||
|
public static int[] findModified(
|
||||||
|
final NonIdentifierAttribute[] properties,
|
||||||
|
final Object[] currentState,
|
||||||
|
final Object[] previousState,
|
||||||
|
final boolean[][] includeColumns,
|
||||||
|
final boolean[] includeProperties,
|
||||||
|
final SharedSessionContractImplementor session) {
|
||||||
|
int[] results = null;
|
||||||
|
int count = 0;
|
||||||
|
int span = properties.length;
|
||||||
|
|
||||||
|
for ( int i = 0; i < span; i++ ) {
|
||||||
|
if ( isModified( properties, currentState, previousState, includeColumns, includeProperties, session, i ) ) {
|
||||||
|
if ( results == null ) {
|
||||||
|
results = new int[ span ];
|
||||||
|
}
|
||||||
|
results[ count++ ] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( count == 0 ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int[] trimmed = new int[ count ];
|
||||||
|
System.arraycopy( results, 0, trimmed, 0, count );
|
||||||
|
return trimmed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isModified(
|
||||||
|
NonIdentifierAttribute[] properties,
|
||||||
|
Object[] currentState,
|
||||||
|
Object[] previousState,
|
||||||
|
boolean[][] includeColumns,
|
||||||
|
boolean[] includeProperties,
|
||||||
|
SharedSessionContractImplementor session,
|
||||||
|
int i) {
|
||||||
|
return currentState[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY
|
||||||
|
&& includeProperties[i]
|
||||||
|
&& properties[i].isDirtyCheckable()
|
||||||
|
&& properties[i].getType().isModified( previousState[i], currentState[i], includeColumns[i], session );
|
||||||
|
}
|
||||||
|
}
|
|
@ -136,7 +136,6 @@ import org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl;
|
||||||
import org.hibernate.query.sqm.sql.internal.SqmMapEntryResult;
|
import org.hibernate.query.sqm.sql.internal.SqmMapEntryResult;
|
||||||
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
|
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
|
||||||
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
|
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
|
||||||
import org.hibernate.query.sqm.sql.internal.TypeHelper;
|
|
||||||
import org.hibernate.query.sqm.tree.SqmJoinType;
|
import org.hibernate.query.sqm.tree.SqmJoinType;
|
||||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
||||||
|
@ -5106,7 +5105,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
);
|
);
|
||||||
final Expression resultExpression = (Expression) whenFragment.getResult().accept( this );
|
final Expression resultExpression = (Expression) whenFragment.getResult().accept( this );
|
||||||
inferrableTypeAccessStack.pop();
|
inferrableTypeAccessStack.pop();
|
||||||
resolved = (MappingModelExpressible<?>) TypeHelper.highestPrecedence( resolved, resultExpression.getExpressionType() );
|
resolved = (MappingModelExpressible<?>) highestPrecedence( resolved, resultExpression.getExpressionType() );
|
||||||
|
|
||||||
whenFragments.add(
|
whenFragments.add(
|
||||||
new CaseSimpleExpression.WhenFragment(
|
new CaseSimpleExpression.WhenFragment(
|
||||||
|
@ -5123,7 +5122,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
);
|
);
|
||||||
otherwise = (Expression) expression.getOtherwise().accept( this );
|
otherwise = (Expression) expression.getOtherwise().accept( this );
|
||||||
inferrableTypeAccessStack.pop();
|
inferrableTypeAccessStack.pop();
|
||||||
resolved = (MappingModelExpressible<?>) TypeHelper.highestPrecedence( resolved, otherwise.getExpressionType() );
|
resolved = (MappingModelExpressible<?>) highestPrecedence( resolved, otherwise.getExpressionType() );
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CaseSimpleExpression(
|
return new CaseSimpleExpression(
|
||||||
|
@ -5151,7 +5150,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
);
|
);
|
||||||
final Expression resultExpression = (Expression) whenFragment.getResult().accept( this );
|
final Expression resultExpression = (Expression) whenFragment.getResult().accept( this );
|
||||||
inferrableTypeAccessStack.pop();
|
inferrableTypeAccessStack.pop();
|
||||||
resolved = (MappingModelExpressible<?>) TypeHelper.highestPrecedence( resolved, resultExpression.getExpressionType() );
|
resolved = (MappingModelExpressible<?>) highestPrecedence( resolved, resultExpression.getExpressionType() );
|
||||||
|
|
||||||
whenFragments.add( new CaseSearchedExpression.WhenFragment( whenPredicate, resultExpression ) );
|
whenFragments.add( new CaseSearchedExpression.WhenFragment( whenPredicate, resultExpression ) );
|
||||||
}
|
}
|
||||||
|
@ -5163,7 +5162,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
);
|
);
|
||||||
otherwise = (Expression) expression.getOtherwise().accept( this );
|
otherwise = (Expression) expression.getOtherwise().accept( this );
|
||||||
inferrableTypeAccessStack.pop();
|
inferrableTypeAccessStack.pop();
|
||||||
resolved = (MappingModelExpressible<?>) TypeHelper.highestPrecedence( resolved, otherwise.getExpressionType() );
|
resolved = (MappingModelExpressible<?>) highestPrecedence( resolved, otherwise.getExpressionType() );
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CaseSearchedExpression( resolved, whenFragments, otherwise );
|
return new CaseSearchedExpression( resolved, whenFragments, otherwise );
|
||||||
|
@ -6265,4 +6264,28 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static JdbcMappingContainer highestPrecedence(JdbcMappingContainer type1, JdbcMappingContainer type2) {
|
||||||
|
if ( type1 == null ) {
|
||||||
|
return type2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( type2 == null ) {
|
||||||
|
return type1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( type1 instanceof ModelPart ) {
|
||||||
|
return type1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( type2 instanceof ModelPart ) {
|
||||||
|
return type2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo (6.0) : we probably want a precedence based on generic resolutions such as those based on Serializable
|
||||||
|
|
||||||
|
// todo (6.0) : anything else to consider?
|
||||||
|
|
||||||
|
return type1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
|
||||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
|
||||||
*/
|
|
||||||
package org.hibernate.query.sqm.sql.internal;
|
|
||||||
|
|
||||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class TypeHelper {
|
|
||||||
public static JdbcMappingContainer highestPrecedence(JdbcMappingContainer type1, JdbcMappingContainer type2) {
|
|
||||||
if ( type1 == null ) {
|
|
||||||
return type2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( type2 == null ) {
|
|
||||||
return type1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( type1 instanceof ModelPart ) {
|
|
||||||
return type1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( type2 instanceof ModelPart ) {
|
|
||||||
return type2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo (6.0) : we probably want a precedence based on generic resolutions such as those based on Serializable
|
|
||||||
|
|
||||||
// todo (6.0) : anything else to consider?
|
|
||||||
|
|
||||||
return type1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,6 +14,7 @@ import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.StaleObjectStateException;
|
import org.hibernate.StaleObjectStateException;
|
||||||
import org.hibernate.WrongClassException;
|
import org.hibernate.WrongClassException;
|
||||||
|
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||||
import org.hibernate.cache.spi.access.EntityDataAccess;
|
import org.hibernate.cache.spi.access.EntityDataAccess;
|
||||||
import org.hibernate.cache.spi.entry.CacheEntry;
|
import org.hibernate.cache.spi.entry.CacheEntry;
|
||||||
|
@ -36,9 +37,11 @@ import org.hibernate.loader.entity.CacheEntityLoaderHelper;
|
||||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.EntityVersionMapping;
|
import org.hibernate.metamodel.mapping.EntityVersionMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.persister.entity.UniqueKeyLoadable;
|
import org.hibernate.persister.entity.UniqueKeyLoadable;
|
||||||
|
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.proxy.LazyInitializer;
|
import org.hibernate.proxy.LazyInitializer;
|
||||||
import org.hibernate.proxy.map.MapProxy;
|
import org.hibernate.proxy.map.MapProxy;
|
||||||
|
@ -56,7 +59,6 @@ import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
import org.hibernate.type.AssociationType;
|
import org.hibernate.type.AssociationType;
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
import org.hibernate.type.TypeHelper;
|
|
||||||
|
|
||||||
import static org.hibernate.internal.log.LoggingHelper.toLoggableString;
|
import static org.hibernate.internal.log.LoggingHelper.toLoggableString;
|
||||||
|
|
||||||
|
@ -189,6 +191,32 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void deepCopy(
|
||||||
|
ManagedMappingType containerDescriptor,
|
||||||
|
Object[] source,
|
||||||
|
Object[] target,
|
||||||
|
EntityPersister concreteDescriptor) {
|
||||||
|
containerDescriptor.visitStateArrayContributors(
|
||||||
|
contributor -> {
|
||||||
|
if ( contributor.getAttributeMetadataAccess().resolveAttributeMetadata( concreteDescriptor ).isUpdatable() ) {
|
||||||
|
final int position = contributor.getStateArrayPosition();
|
||||||
|
Object result;
|
||||||
|
if ( source[position] == LazyPropertyInitializer.UNFETCHED_PROPERTY
|
||||||
|
|| source[position] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
|
||||||
|
result = source[position];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = contributor.getAttributeMetadataAccess()
|
||||||
|
.resolveAttributeMetadata(null)
|
||||||
|
.getMutabilityPlan()
|
||||||
|
.deepCopy( source[position] );
|
||||||
|
}
|
||||||
|
target[position] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelPart getInitializedPart() {
|
public ModelPart getInitializedPart() {
|
||||||
return referencedModelPart;
|
return referencedModelPart;
|
||||||
|
@ -832,11 +860,11 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//take a snapshot
|
//take a snapshot
|
||||||
TypeHelper.deepCopy(
|
deepCopy(
|
||||||
concreteDescriptor,
|
concreteDescriptor,
|
||||||
resolvedEntityState,
|
resolvedEntityState,
|
||||||
resolvedEntityState,
|
resolvedEntityState,
|
||||||
attributeMapping -> attributeMapping.getAttributeMetadataAccess().resolveAttributeMetadata( concreteDescriptor ).isUpdatable()
|
concreteDescriptor
|
||||||
);
|
);
|
||||||
persistenceContext.setEntryStatus( entityEntry, Status.MANAGED );
|
persistenceContext.setEntryStatus( entityEntry, Status.MANAGED );
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,27 +6,19 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.type;
|
package org.hibernate.type;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
|
import org.hibernate.Internal;
|
||||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
|
||||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMapping;
|
|
||||||
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
|
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
|
||||||
import org.hibernate.tuple.NonIdentifierAttribute;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of convenience methods relating to operations across arrays of types...
|
* Certain operations for working with arrays of property values.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*
|
|
||||||
* @deprecated with no real replacement. this was always intended as an internal class
|
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "6.0")
|
@Internal
|
||||||
public class TypeHelper {
|
public class TypeHelper {
|
||||||
/**
|
/**
|
||||||
* Disallow instantiation
|
* Disallow instantiation
|
||||||
|
@ -34,49 +26,6 @@ public class TypeHelper {
|
||||||
private TypeHelper() {
|
private TypeHelper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final BiFunction<StateArrayContributorMapping,Object,Object> DEEP_COPY_VALUE_PRODUCER = (navigable, sourceValue) -> {
|
|
||||||
if ( sourceValue == LazyPropertyInitializer.UNFETCHED_PROPERTY
|
|
||||||
|| sourceValue == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
|
|
||||||
return sourceValue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return navigable.getAttributeMetadataAccess()
|
|
||||||
.resolveAttributeMetadata( null )
|
|
||||||
.getMutabilityPlan()
|
|
||||||
.deepCopy( sourceValue );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static void deepCopy(
|
|
||||||
ManagedMappingType containerDescriptor,
|
|
||||||
Object[] source,
|
|
||||||
Object[] target,
|
|
||||||
Predicate<StateArrayContributorMapping> copyConditions) {
|
|
||||||
deepCopy(
|
|
||||||
containerDescriptor,
|
|
||||||
source,
|
|
||||||
target,
|
|
||||||
copyConditions,
|
|
||||||
DEEP_COPY_VALUE_PRODUCER
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deepCopy(
|
|
||||||
ManagedMappingType containerDescriptor,
|
|
||||||
Object[] source,
|
|
||||||
Object[] target,
|
|
||||||
Predicate<StateArrayContributorMapping> copyConditions,
|
|
||||||
BiFunction<StateArrayContributorMapping, Object, Object> targetValueProducer) {
|
|
||||||
containerDescriptor.visitStateArrayContributors(
|
|
||||||
contributor -> {
|
|
||||||
if ( copyConditions.test( contributor ) ) {
|
|
||||||
final int position = contributor.getStateArrayPosition();
|
|
||||||
target[position] = targetValueProducer.apply( contributor, source[position] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deep copy a series of values from one array to another...
|
* Deep copy a series of values from one array to another...
|
||||||
*
|
*
|
||||||
|
@ -106,81 +55,6 @@ public class TypeHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the {@link Type#assemble} operation across a series of values.
|
|
||||||
*
|
|
||||||
* @param row The values
|
|
||||||
* @param types The value types
|
|
||||||
* @param session The originating session
|
|
||||||
* @param owner The entity "owning" the values
|
|
||||||
* @return The assembled state
|
|
||||||
*/
|
|
||||||
public static Object[] assemble(
|
|
||||||
final Serializable[] row,
|
|
||||||
final Type[] types,
|
|
||||||
final SharedSessionContractImplementor session,
|
|
||||||
final Object owner) {
|
|
||||||
Object[] assembled = new Object[row.length];
|
|
||||||
for ( int i = 0; i < types.length; i++ ) {
|
|
||||||
if ( row[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY || row[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
|
|
||||||
assembled[i] = row[i];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assembled[i] = types[i].assemble( row[i], session, owner );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return assembled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object[] assemble(
|
|
||||||
final Object[] row,
|
|
||||||
final Type[] types,
|
|
||||||
final SharedSessionContractImplementor session,
|
|
||||||
final Object owner) {
|
|
||||||
Object[] assembled = new Object[row.length];
|
|
||||||
for ( int i = 0; i < types.length; i++ ) {
|
|
||||||
if ( row[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY || row[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
|
|
||||||
assembled[i] = row[i];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assembled[i] = types[i].assemble( (Serializable) row[i], session, owner );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return assembled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the {@link Type#disassemble} operation across a series of values.
|
|
||||||
*
|
|
||||||
* @param row The values
|
|
||||||
* @param types The value types
|
|
||||||
* @param nonCacheable An array indicating which values to include in the disassembled state
|
|
||||||
* @param session The originating session
|
|
||||||
* @param owner The entity "owning" the values
|
|
||||||
*
|
|
||||||
* @return The disassembled state
|
|
||||||
*/
|
|
||||||
public static Serializable[] disassemble(
|
|
||||||
final Object[] row,
|
|
||||||
final Type[] types,
|
|
||||||
final boolean[] nonCacheable,
|
|
||||||
final SharedSessionContractImplementor session,
|
|
||||||
final Object owner) {
|
|
||||||
Serializable[] disassembled = new Serializable[row.length];
|
|
||||||
for ( int i = 0; i < row.length; i++ ) {
|
|
||||||
if ( nonCacheable!=null && nonCacheable[i] ) {
|
|
||||||
disassembled[i] = LazyPropertyInitializer.UNFETCHED_PROPERTY;
|
|
||||||
}
|
|
||||||
else if ( row[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY || row[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
|
|
||||||
disassembled[i] = (Serializable) row[i];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
disassembled[i] = types[i].disassemble( row[i], session, owner );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return disassembled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the {@link Type#replace} operation across a series of values.
|
* Apply the {@link Type#replace} operation across a series of values.
|
||||||
*
|
*
|
||||||
|
@ -302,109 +176,4 @@ public class TypeHelper {
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if any of the given field values are dirty, returning an array containing
|
|
||||||
* indices of the dirty fields.
|
|
||||||
* <p/>
|
|
||||||
* If it is determined that no fields are dirty, null is returned.
|
|
||||||
*
|
|
||||||
* @param properties The property definitions
|
|
||||||
* @param currentState The current state of the entity
|
|
||||||
* @param previousState The baseline state of the entity
|
|
||||||
* @param includeColumns Columns to be included in the dirty checking, per property
|
|
||||||
* @param session The session from which the dirty check request originated.
|
|
||||||
*
|
|
||||||
* @return Array containing indices of the dirty properties, or null if no properties considered dirty.
|
|
||||||
*/
|
|
||||||
public static int[] findDirty(
|
|
||||||
final NonIdentifierAttribute[] properties,
|
|
||||||
final Object[] currentState,
|
|
||||||
final Object[] previousState,
|
|
||||||
final boolean[][] includeColumns,
|
|
||||||
final SharedSessionContractImplementor session) {
|
|
||||||
int[] results = null;
|
|
||||||
int count = 0;
|
|
||||||
int span = properties.length;
|
|
||||||
|
|
||||||
for ( int i = 0; i < span; i++ ) {
|
|
||||||
final boolean dirty;
|
|
||||||
if ( currentState[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
|
|
||||||
dirty = false;
|
|
||||||
}
|
|
||||||
else if ( previousState[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
else if ( properties[i].isDirtyCheckable()
|
|
||||||
&& properties[i].getType().isDirty( previousState[i], currentState[i], includeColumns[i], session ) ) {
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( dirty ) {
|
|
||||||
if ( results == null ) {
|
|
||||||
results = new int[span];
|
|
||||||
}
|
|
||||||
results[count++] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( count == 0 ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return ArrayHelper.trim(results, count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if any of the given field values are modified, returning an array containing
|
|
||||||
* indices of the modified fields.
|
|
||||||
* <p/>
|
|
||||||
* If it is determined that no fields are dirty, null is returned.
|
|
||||||
*
|
|
||||||
* @param properties The property definitions
|
|
||||||
* @param currentState The current state of the entity
|
|
||||||
* @param previousState The baseline state of the entity
|
|
||||||
* @param includeColumns Columns to be included in the mod checking, per property
|
|
||||||
* @param includeProperties Array of property indices that identify which properties participate in check
|
|
||||||
* @param session The session from which the dirty check request originated.
|
|
||||||
*
|
|
||||||
* @return Array containing indices of the modified properties, or null if no properties considered modified.
|
|
||||||
**/
|
|
||||||
public static int[] findModified(
|
|
||||||
final NonIdentifierAttribute[] properties,
|
|
||||||
final Object[] currentState,
|
|
||||||
final Object[] previousState,
|
|
||||||
final boolean[][] includeColumns,
|
|
||||||
final boolean[] includeProperties,
|
|
||||||
final SharedSessionContractImplementor session) {
|
|
||||||
int[] results = null;
|
|
||||||
int count = 0;
|
|
||||||
int span = properties.length;
|
|
||||||
|
|
||||||
for ( int i = 0; i < span; i++ ) {
|
|
||||||
final boolean modified = currentState[ i ] != LazyPropertyInitializer.UNFETCHED_PROPERTY
|
|
||||||
&& includeProperties[ i ]
|
|
||||||
&& properties[ i ].isDirtyCheckable()
|
|
||||||
&& properties[ i ].getType().isModified( previousState[ i ], currentState[ i ], includeColumns[ i ], session );
|
|
||||||
if ( modified ) {
|
|
||||||
if ( results == null ) {
|
|
||||||
results = new int[ span ];
|
|
||||||
}
|
|
||||||
results[ count++ ] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( count == 0 ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int[] trimmed = new int[ count ];
|
|
||||||
System.arraycopy( results, 0, trimmed, 0, count );
|
|
||||||
return trimmed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue