miscellaneous code cleanups

This commit is contained in:
Gavin King 2023-07-22 11:47:29 +02:00
parent 57cbf2e16a
commit 47024e7bd5
4 changed files with 199 additions and 240 deletions

View File

@ -50,20 +50,20 @@ import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.OneToOneType;
import org.hibernate.type.Type;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
/**
* Responsible for maintaining the queue of actions related to events.
*
* The ActionQueue holds the DML operations queued as part of a session's transactional-write-behind semantics. The
* DML operations are queued here until a flush forces them to be executed against the database.
* <p>
* The {@code ActionQueue} holds the DML operations queued as part of a session's transactional-write-behind semantics.
* The DML operations are queued here until a flush forces them to be executed against the database.
*
* @author Steve Ebersole
* @author Gail Badner
@ -76,12 +76,11 @@ public class ActionQueue {
private UnresolvedEntityInsertActions unresolvedInsertions;
// NOTE: ExecutableList fields must be instantiated via ListProvider#init or #getOrInit
// to ensure that they are instantiated consistently.
// NOTE: ExecutableList fields must be instantiated via ListProvider#init
// or #getOrInit to ensure that they are instantiated consistently.
// Object insertions, updates, and deletions have list semantics because
// they must happen in the right order so as to respect referential
// integrity
// they must happen in the right order to respect referential integrity
private ExecutableList<AbstractEntityInsertAction> insertions;
private ExecutableList<EntityDeleteAction> deletions;
private ExecutableList<EntityUpdateAction> updates;
@ -96,8 +95,8 @@ public class ActionQueue {
private ExecutableList<CollectionRemoveAction> collectionRemovals;
private ExecutableList<CollectionRemoveAction> orphanCollectionRemovals;
// TODO: The removeOrphan concept is a temporary "hack" for HHH-6484. This should be removed once action/task
// ordering is improved.
// TODO: The removeOrphan concept is a temporary "hack" for HHH-6484.
// This should be removed once action/task ordering is improved.
private ExecutableList<OrphanRemovalAction> orphanRemovals;
@ -105,11 +104,11 @@ public class ActionQueue {
private AfterTransactionCompletionProcessQueue afterTransactionProcesses;
private BeforeTransactionCompletionProcessQueue beforeTransactionProcesses;
//Extract this as a constant to perform efficient iterations:
//method values() otherwise allocates a new array on each invocation.
// Extract this as a constant to perform efficient iterations:
// method values() otherwise allocates a new array on each invocation.
private static final OrderedActions[] ORDERED_OPERATIONS = OrderedActions.values();
//The order of these operations is very important
// The order of these operations is very important
private enum OrderedActions {
OrphanCollectionRemoveAction {
@Override
@ -266,7 +265,7 @@ public class ActionQueue {
LOG.tracev( "Executing inserts before finding non-nullable transient entities for early insert: [{0}]", insert );
executeInserts();
}
NonNullableTransientDependencies nonNullableTransientDependencies = insert.findNonNullableTransientEntities();
final NonNullableTransientDependencies nonNullableTransientDependencies = insert.findNonNullableTransientEntities();
if ( nonNullableTransientDependencies == null ) {
LOG.tracev( "Adding insert with no non-nullable, transient entities: [{0}]", insert );
addResolvedEntityInsertAction( insert );
@ -293,13 +292,13 @@ public class ActionQueue {
else {
LOG.trace( "Adding resolved non-early insert action." );
OrderedActions.EntityInsertAction.ensureInitialized( this );
this.insertions.add( insert );
insertions.add( insert );
}
if ( !insert.isVeto() ) {
insert.makeEntityManaged();
if ( unresolvedInsertions != null ) {
for ( AbstractEntityInsertAction resolvedAction : unresolvedInsertions.resolveDependentActions( insert.getInstance(), session ) ) {
for ( AbstractEntityInsertAction resolvedAction :
unresolvedInsertions.resolveDependentActions( insert.getInstance(), session ) ) {
addResolvedEntityInsertAction( resolvedAction );
}
}
@ -329,7 +328,7 @@ public class ActionQueue {
*/
public void addAction(EntityDeleteAction action) {
OrderedActions.EntityDeleteAction.ensureInitialized( this );
this.deletions.add( action );
deletions.add( action );
}
/**
@ -339,7 +338,7 @@ public class ActionQueue {
*/
public void addAction(final OrphanRemovalAction action) {
OrderedActions.OrphanRemovalAction.ensureInitialized( this );
this.orphanRemovals.add( action );
orphanRemovals.add( action );
}
/**
@ -349,7 +348,7 @@ public class ActionQueue {
*/
public void addAction(final EntityUpdateAction action) {
OrderedActions.EntityUpdateAction.ensureInitialized( this );
this.updates.add( action );
updates.add( action );
}
/**
@ -359,7 +358,7 @@ public class ActionQueue {
*/
public void addAction(final CollectionRecreateAction action) {
OrderedActions.CollectionRecreateAction.ensureInitialized( this );
this.collectionCreations.add( action );
collectionCreations.add( action );
}
/**
@ -368,22 +367,23 @@ public class ActionQueue {
* @param action The action representing the removal of a collection
*/
public void addAction(final CollectionRemoveAction action) {
if ( orphanRemovals != null && action.getAffectedOwner() != null && session.getPersistenceContextInternal()
.getEntry( action.getAffectedOwner() )
.getStatus()
.isDeletedOrGone() ) {
if ( orphanRemovals != null && action.getAffectedOwner() != null
&& session.getPersistenceContextInternal()
.getEntry( action.getAffectedOwner() )
.getStatus()
.isDeletedOrGone() ) {
// We need to check if this collection's owner is an orphan being removed,
// which case we should remove the collection first to avoid constraint violations
for ( OrphanRemovalAction orphanRemoval : orphanRemovals ) {
if ( orphanRemoval.getInstance() == action.getAffectedOwner() ) {
OrderedActions.OrphanCollectionRemoveAction.ensureInitialized( this );
this.orphanCollectionRemovals.add( action );
orphanCollectionRemovals.add( action );
return;
}
}
}
OrderedActions.CollectionRemoveAction.ensureInitialized( this );
this.collectionRemovals.add( action );
collectionRemovals.add( action );
}
/**
@ -393,7 +393,7 @@ public class ActionQueue {
*/
public void addAction(final CollectionUpdateAction action) {
OrderedActions.CollectionUpdateAction.ensureInitialized( this );
this.collectionUpdates.add( action );
collectionUpdates.add( action );
}
/**
@ -423,7 +423,7 @@ public class ActionQueue {
beforeTransactionProcesses.register( executable.getBeforeTransactionCompletionProcess() );
}
if ( session.getFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
invalidateSpaces( convertTimestampSpaces( executable.getPropertySpaces() ) );
invalidateSpaces( (String[]) executable.getPropertySpaces() );
}
if ( executable.getAfterTransactionCompletionProcess() != null ) {
if ( afterTransactionProcesses == null ) {
@ -433,10 +433,6 @@ public class ActionQueue {
}
}
private static String[] convertTimestampSpaces(Serializable[] spaces) {
return (String[]) spaces;
}
/**
* Are there unresolved entity insert actions that depend on non-nullable associations with a transient entity?
*
@ -653,8 +649,7 @@ public class ActionQueue {
// Strictly speaking, only a subset of the list may have been processed if a RuntimeException occurs.
// We still invalidate all spaces. I don't see this as a big deal - after all, RuntimeExceptions are
// unexpected.
Set propertySpaces = list.getQuerySpaces();
invalidateSpaces( convertTimestampSpaces( propertySpaces ) );
invalidateSpaces( list.getQuerySpaces().toArray(StringHelper.EMPTY_STRINGS) );
}
}
@ -662,10 +657,6 @@ public class ActionQueue {
session.getJdbcCoordinator().executeBatch();
}
private static String[] convertTimestampSpaces(Set<String> spaces) {
return spaces.toArray(StringHelper.EMPTY_STRINGS);
}
/**
* @param executable The action to execute
*/
@ -683,7 +674,7 @@ public class ActionQueue {
*
* @param spaces The spaces to invalidate
*/
private void invalidateSpaces(String... spaces) {
private void invalidateSpaces(String[] spaces) {
if ( spaces != null && spaces.length > 0 ) {
for ( String space : spaces ) {
if ( afterTransactionProcesses == null ) {
@ -855,10 +846,18 @@ public class ActionQueue {
}
public boolean hasAnyQueuedActions() {
return ( updates != null && !updates.isEmpty() ) || ( insertions != null && !insertions.isEmpty() ) || hasUnresolvedEntityInsertActions()
|| ( deletions != null && !deletions.isEmpty()) || ( collectionUpdates != null && !collectionUpdates.isEmpty() )
|| ( collectionQueuedOps != null && !collectionQueuedOps.isEmpty() ) || ( collectionRemovals != null && !collectionRemovals.isEmpty() )
|| ( collectionCreations != null && !collectionCreations.isEmpty() );
return hasUnresolvedEntityInsertActions()
|| nonempty( updates )
|| nonempty( insertions )
|| nonempty( deletions )
|| nonempty( collectionUpdates )
|| nonempty( collectionQueuedOps )
|| nonempty( collectionRemovals )
|| nonempty( collectionCreations );
}
private boolean nonempty(ExecutableList<?> list) {
return list != null && !list.isEmpty();
}
public void unScheduleUnloadedDeletion(Object newEntity) {
@ -866,13 +865,12 @@ public class ActionQueue {
final Object identifier = entityPersister.getIdentifier( newEntity, session );
if ( deletions != null ) {
for ( int i = 0; i < deletions.size(); i++ ) {
EntityDeleteAction action = deletions.get( i );
final EntityDeleteAction action = deletions.get( i );
if ( action.getInstance() == null
&& action.getEntityName().equals( entityPersister.getEntityName() )
&& entityPersister.getIdentifierMapping().areEqual( action.getId(), identifier, session ) ) {
session.getPersistenceContextInternal().removeDeletedUnloadedEntityKey(
session.generateEntityKey( identifier, entityPersister )
);
session.getPersistenceContextInternal()
.removeDeletedUnloadedEntityKey( session.generateEntityKey( identifier, entityPersister ) );
deletions.remove( i );
return;
}
@ -882,7 +880,7 @@ public class ActionQueue {
}
public void unScheduleDeletion(EntityEntry entry, Object rescuedEntity) {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( rescuedEntity );
final LazyInitializer lazyInitializer = extractLazyInitializer( rescuedEntity );
if ( lazyInitializer != null ) {
if ( !lazyInitializer.isUninitialized() ) {
rescuedEntity = lazyInitializer.getImplementation( session );
@ -890,7 +888,7 @@ public class ActionQueue {
}
if ( deletions != null ) {
for ( int i = 0; i < deletions.size(); i++ ) {
EntityDeleteAction action = deletions.get( i );
final EntityDeleteAction action = deletions.get( i );
if ( action.getInstance() == rescuedEntity ) {
deletions.remove( i );
return;
@ -899,7 +897,7 @@ public class ActionQueue {
}
if ( orphanRemovals != null ) {
for ( int i = 0; i < orphanRemovals.size(); i++ ) {
EntityDeleteAction action = orphanRemovals.get( i );
final EntityDeleteAction action = orphanRemovals.get( i );
if ( action.getInstance() == rescuedEntity ) {
orphanRemovals.remove( i );
return;
@ -923,7 +921,7 @@ public class ActionQueue {
unresolvedInsertions.serialize( oos );
for ( OrderedActions action : ORDERED_OPERATIONS ) {
ExecutableList<?> l = action.getActions( this );
final ExecutableList<?> l = action.getActions( this );
if ( l == null ) {
oos.writeBoolean( false );
}
@ -985,10 +983,9 @@ public class ActionQueue {
}
public void register(T process) {
if ( process == null ) {
return;
if ( process != null ) {
processes.add( process );
}
processes.add( process );
}
public boolean hasActions() {
@ -999,7 +996,9 @@ public class ActionQueue {
/**
* Encapsulates behavior needed for before transaction processing
*/
private static class BeforeTransactionCompletionProcessQueue extends AbstractTransactionCompletionProcessQueue<BeforeTransactionCompletionProcess> {
private static class BeforeTransactionCompletionProcessQueue
extends AbstractTransactionCompletionProcessQueue<BeforeTransactionCompletionProcess> {
private BeforeTransactionCompletionProcessQueue(SessionImplementor session) {
super( session );
}
@ -1111,26 +1110,26 @@ public class ActionQueue {
public void buildDirectDependencies(IdentityHashMap<Object, InsertInfo> insertInfosByEntity) {
final Object[] propertyValues = insertAction.getState();
final Type[] propertyTypes = insertAction.getPersister().getPropertyTypes();
for (int i = 0, propertyTypesLength = propertyTypes.length; i < propertyTypesLength; i++) {
addDirectDependency(propertyTypes[i], propertyValues[i], insertInfosByEntity);
for ( int i = 0, propertyTypesLength = propertyTypes.length; i < propertyTypesLength; i++ ) {
addDirectDependency( propertyTypes[i], propertyValues[i], insertInfosByEntity );
}
}
public void propagateChildDependencies() {
if ( outgoingDependencies != null ) {
for (InsertInfo childDependency : outgoingDependencies) {
for ( InsertInfo childDependency : outgoingDependencies ) {
if (childDependency.transitiveIncomingDependencies == null) {
childDependency.transitiveIncomingDependencies = new HashSet<>();
}
childDependency.transitiveIncomingDependencies.add(this);
childDependency.transitiveIncomingDependencies.add( this );
}
}
}
public void buildTransitiveDependencies(Set<InsertInfo> visited) {
if (transitiveIncomingDependencies != null) {
visited.addAll(transitiveIncomingDependencies);
for (InsertInfo insertInfo : transitiveIncomingDependencies.toArray(new InsertInfo[0])) {
if ( transitiveIncomingDependencies != null ) {
visited.addAll( transitiveIncomingDependencies );
for ( InsertInfo insertInfo : transitiveIncomingDependencies.toArray(new InsertInfo[0]) ) {
insertInfo.addTransitiveDependencies(this, visited);
}
visited.clear();
@ -1138,11 +1137,11 @@ public class ActionQueue {
}
public void addTransitiveDependencies(InsertInfo origin, Set<InsertInfo> visited) {
if (transitiveIncomingDependencies != null) {
for (InsertInfo insertInfo : transitiveIncomingDependencies) {
if (visited.add(insertInfo)) {
origin.transitiveIncomingDependencies.add(insertInfo);
insertInfo.addTransitiveDependencies(origin, visited);
if ( transitiveIncomingDependencies != null ) {
for ( InsertInfo insertInfo : transitiveIncomingDependencies ) {
if ( visited.add(insertInfo) ) {
origin.transitiveIncomingDependencies.add( insertInfo );
insertInfo.addTransitiveDependencies( origin, visited );
}
}
}
@ -1151,21 +1150,22 @@ public class ActionQueue {
private void addDirectDependency(Type type, Object value, IdentityHashMap<Object, InsertInfo> insertInfosByEntity) {
if ( type.isEntityType() && value != null ) {
final EntityType entityType = (EntityType) type;
final InsertInfo insertInfo = insertInfosByEntity.get(value);
if (insertInfo != null) {
if (entityType.isOneToOne() && OneToOneType.class.cast( entityType).getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT) {
if (!entityType.isReferenceToPrimaryKey()) {
if (outgoingDependencies == null) {
final InsertInfo insertInfo = insertInfosByEntity.get( value );
if ( insertInfo != null ) {
if ( entityType.isOneToOne()
&& entityType.getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) {
if ( !entityType.isReferenceToPrimaryKey() ) {
if ( outgoingDependencies == null ) {
outgoingDependencies = new HashSet<>();
}
outgoingDependencies.add(insertInfo);
}
}
else {
if (transitiveIncomingDependencies == null) {
if ( transitiveIncomingDependencies == null ) {
transitiveIncomingDependencies = new HashSet<>();
}
transitiveIncomingDependencies.add(insertInfo);
transitiveIncomingDependencies.add( insertInfo );
}
}
}
@ -1176,7 +1176,8 @@ public class ActionQueue {
.getMappingMetamodel()
.getCollectionDescriptor( collectionType.getRole() )
.getAttributeMapping();
// We only care about mappedBy one-to-many associations, because for these, the elements depend on the collection owner
// We only care about mappedBy one-to-many associations, because for these,
// the elements depend on the collection owner
if ( pluralAttributeMapping.getCollectionDescriptor().isOneToMany()
&& pluralAttributeMapping.getElementDescriptor() instanceof EntityCollectionPart ) {
final Iterator<?> elementsIterator = collectionType.getElementsIterator( value );
@ -1194,29 +1195,28 @@ public class ActionQueue {
}
else if ( type.isComponentType() && value != null ) {
// Support recursive checks of composite type properties for associations and collections.
CompositeType compositeType = (CompositeType) type;
final CompositeType compositeType = (CompositeType) type;
final SharedSessionContractImplementor session = insertAction.getSession();
Object[] componentValues = compositeType.getPropertyValues( value, session );
final Object[] componentValues = compositeType.getPropertyValues( value, session );
for ( int j = 0; j < componentValues.length; ++j ) {
Type componentValueType = compositeType.getSubtypes()[j];
Object componentValue = componentValues[j];
addDirectDependency( componentValueType, componentValue, insertInfosByEntity);
final Type componentValueType = compositeType.getSubtypes()[j];
final Object componentValue = componentValues[j];
addDirectDependency( componentValueType, componentValue, insertInfosByEntity );
}
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
if ( this == o ) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if ( o == null || getClass() != o.getClass() ) {
return false;
}
InsertInfo that = (InsertInfo) o;
return insertAction.equals(that.insertAction);
final InsertInfo that = (InsertInfo) o;
return insertAction.equals( that.insertAction );
}
@Override

View File

@ -1272,20 +1272,13 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
@Override
public <T> JpaCriteriaParameter<T> parameter(Class<T> paramClass, String name) {
final BasicType<T> basicType = getTypeConfiguration().getBasicTypeForJavaType( paramClass );
if ( basicType == null ) {
final BindableType<T> parameterType;
if ( Collection.class.isAssignableFrom( paramClass ) ) {
// a Collection-valued, multi-valued parameter
parameterType = new MultiValueParameterType<>( (Class<T>) Collection.class );
}
else {
parameterType = null;
}
return new JpaCriteriaParameter<>( name, parameterType, true, this );
}
else {
return new JpaCriteriaParameter<>( name, basicType, false, this );
}
boolean notBasic = basicType == null;
final BindableType<T> parameterType =
notBasic && Collection.class.isAssignableFrom( paramClass )
// a Collection-valued, multi-valued parameter
? new MultiValueParameterType<>( (Class<T>) Collection.class )
: basicType;
return new JpaCriteriaParameter<>( name, parameterType, notBasic, this );
}
@Override

View File

@ -16,12 +16,16 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Abstract superclass of the built in Type hierarchy.
* Abstract superclass of the built-in {@link Type} hierarchy.
*
* @author Gavin King
*/
public abstract class AbstractType implements Type {
@Deprecated(forRemoval = true)
protected static final Size LEGACY_DICTATED_SIZE = new Size();
@Deprecated(forRemoval = true)
protected static final Size LEGACY_DEFAULT_SIZE = new Size( 19, 2, 255L, Size.LobMultiplier.NONE ); // to match legacy behavior
@Override
@ -44,46 +48,32 @@ public abstract class AbstractType implements Type {
return false;
}
@Override
@Override @SuppressWarnings({"rawtypes", "unchecked"})
public int compare(Object x, Object y) {
return ( (Comparable) x ).compareTo(y);
}
@Override
public Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner)
throws HibernateException {
if (value==null) {
return null;
}
else {
return (Serializable) deepCopy( value, session.getFactory() );
}
throws HibernateException {
return value == null ? null : (Serializable) deepCopy( value, session.getFactory() );
}
@Override
public Serializable disassemble(Object value, SessionFactoryImplementor sessionFactory) throws HibernateException {
if ( value == null ) {
return null;
}
else {
return (Serializable) deepCopy( value, sessionFactory );
}
public Serializable disassemble(Object value, SessionFactoryImplementor sessionFactory)
throws HibernateException {
return value == null ? null : (Serializable) deepCopy( value, sessionFactory );
}
@Override
public Object assemble(Serializable cached, SharedSessionContractImplementor session, Object owner)
throws HibernateException {
if ( cached==null ) {
return null;
}
else {
return deepCopy( cached, session.getFactory() );
}
return cached == null ? null : deepCopy( cached, session.getFactory() );
}
@Override
public boolean isDirty(Object old, Object current, SharedSessionContractImplementor session) throws HibernateException {
public boolean isDirty(Object old, Object current, SharedSessionContractImplementor session)
throws HibernateException {
return !isSame( old, current );
}
@ -94,8 +84,8 @@ public abstract class AbstractType implements Type {
@Override
public boolean isModified(Object old, Object current, boolean[] checkable, SharedSessionContractImplementor session)
throws HibernateException {
return isDirty(old, current, session);
throws HibernateException {
return isDirty( old, current, session );
}
@Override
@ -115,12 +105,12 @@ public abstract class AbstractType implements Type {
@Override
public boolean isEqual(Object x, Object y, SessionFactoryImplementor factory) {
return isEqual(x, y );
return isEqual( x, y );
}
@Override
public int getHashCode(Object x, SessionFactoryImplementor factory) {
return getHashCode(x );
return getHashCode( x );
}
@Override
@ -132,24 +122,19 @@ public abstract class AbstractType implements Type {
Map<Object, Object> copyCache,
ForeignKeyDirection foreignKeyDirection)
throws HibernateException {
boolean include;
return needsReplacement( foreignKeyDirection ) ? replace( original, target, session, owner, copyCache ) : target;
}
private boolean needsReplacement(ForeignKeyDirection foreignKeyDirection) {
if ( isAssociationType() ) {
AssociationType atype = (AssociationType) this;
include = atype.getForeignKeyDirection()==foreignKeyDirection;
final AssociationType associationType = (AssociationType) this;
return associationType.getForeignKeyDirection() == foreignKeyDirection;
}
else {
include = ForeignKeyDirection.FROM_PARENT ==foreignKeyDirection;
return ForeignKeyDirection.FROM_PARENT == foreignKeyDirection;
}
return include ? replace(original, target, session, owner, copyCache) : target;
}
@Override
public void beforeAssemble(Serializable cached, SharedSessionContractImplementor session) {}
/*public Object copy(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache)
throws HibernateException {
if (original==null) return null;
return assemble( disassemble(original, session), session, owner );
}*/
}

View File

@ -19,6 +19,7 @@ import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.Remove;
import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.engine.spi.CascadeStyle;
@ -26,11 +27,11 @@ import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.Generator;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
@ -39,12 +40,15 @@ import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.spi.CompositeTypeImplementor;
import org.hibernate.usertype.CompositeUserType;
import static org.hibernate.internal.util.ReflectHelper.isRecord;
/**
* Handles "component" mappings
* Handles {@linkplain jakarta.persistence.Embedded embedded} mappings.
*
* @author Gavin King
*/
@ -63,15 +67,14 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
private final boolean isAggregate;
private final boolean isKey;
private boolean hasNotNullProperty;
private final CompositeUserType<Object> compositeUserType;
@SuppressWarnings("rawtypes")
private final CompositeUserType compositeUserType;
private EmbeddableValuedModelPart mappingModelPart;
public ComponentType(Component component, int[] originalPropertyOrder, MetadataBuildingContext buildingContext) {
this.componentClass = component.isDynamic()
? Map.class
: component.getComponentClass();
this.componentClass = component.isDynamic() ? Map.class : component.getComponentClass();
this.isAggregate = component.getAggregateColumn() != null;
this.isKey = component.isKey();
this.propertySpan = component.getPropertySpan();
@ -95,26 +98,22 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
i++;
}
if ( component.getTypeName() != null ) {
final ManagedBeanRegistry beanRegistry = buildingContext.getBootstrapContext()
.getServiceRegistry()
.getService( ManagedBeanRegistry.class );
final Class<CompositeUserType<?>> customTypeClass = buildingContext.getBootstrapContext()
.getClassLoaderAccess()
.classForName( component.getTypeName() );
if ( buildingContext.getBuildingOptions().disallowExtensionsInCdi() ) {
//noinspection unchecked,rawtypes
this.compositeUserType = (CompositeUserType) FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( customTypeClass );
}
else {
//noinspection unchecked,rawtypes
this.compositeUserType = (CompositeUserType) beanRegistry.getBean( customTypeClass ).getBeanInstance();
}
this.compositeUserType =
component.getTypeName() == null ? null : createCompositeUserType( component, buildingContext );
this.mutable = !isRecord( componentClass ) && ( compositeUserType == null || compositeUserType.isMutable() );
}
private static CompositeUserType<?> createCompositeUserType(Component component, MetadataBuildingContext buildingContext) {
final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext();
final Class<CompositeUserType<?>> customTypeClass =
bootstrapContext.getClassLoaderAccess().classForName( component.getTypeName() );
if ( buildingContext.getBuildingOptions().disallowExtensionsInCdi() ) {
return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( customTypeClass );
}
else {
this.compositeUserType = null;
return bootstrapContext.getServiceRegistry().requireService( ManagedBeanRegistry.class )
.getBean( customTypeClass ).getBeanInstance();
}
this.mutable = !ReflectHelper.isRecord( componentClass ) && ( compositeUserType == null || compositeUserType.isMutable() );
}
private boolean isAggregate() {
@ -137,7 +136,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
@Override
public int[] getSqlTypeCodes(Mapping mapping) throws MappingException {
//Not called at runtime so doesn't matter if it's slow :)
int[] sqlTypes = new int[getColumnSpan( mapping )];
final int[] sqlTypes = new int[getColumnSpan( mapping )];
int n = 0;
for ( int i = 0; i < propertySpan; i++ ) {
int[] subtypes = propertyTypes[i].getSqlTypeCodes( mapping );
@ -164,8 +163,8 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
return true;
}
// null value and empty component are considered equivalent
Object[] xvalues = getPropertyValues( x );
Object[] yvalues = getPropertyValues( y );
final Object[] xvalues = getPropertyValues( x );
final Object[] yvalues = getPropertyValues( y );
for ( int i = 0; i < propertySpan; i++ ) {
if ( !propertyTypes[i].isSame( xvalues[i], yvalues[i] ) ) {
return false;
@ -248,7 +247,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
}
int result = 17;
for ( int i = 0; i < propertySpan; i++ ) {
Object y = getPropertyValue( x, i );
final Object y = getPropertyValue( x, i );
result *= 37;
if ( y != null ) {
result += propertyTypes[i].getHashCode( y );
@ -264,7 +263,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
}
int result = 17;
for ( int i = 0; i < propertySpan; i++ ) {
Object y = getPropertyValue( x, i );
final Object y = getPropertyValue( x, i );
result *= 37;
if ( y != null ) {
result += propertyTypes[i].getHashCode( y, factory );
@ -304,7 +303,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
}
}
else {
boolean[] subcheckable = new boolean[len];
final boolean[] subcheckable = new boolean[len];
System.arraycopy( checkable, loc, subcheckable, 0, len );
final boolean dirty = propertyTypes[i].isDirty(
getPropertyValue( x, i ),
@ -333,8 +332,8 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
// null value and empty components are considered equivalent
int loc = 0;
for ( int i = 0; i < propertySpan; i++ ) {
int len = propertyTypes[i].getColumnSpan( session.getFactory() );
boolean[] subcheckable = new boolean[len];
final int len = propertyTypes[i].getColumnSpan( session.getFactory() );
final boolean[] subcheckable = new boolean[len];
System.arraycopy( checkable, loc, subcheckable, 0, len );
if ( propertyTypes[i].isModified( getPropertyValue( old, i ), getPropertyValue( current, i ), subcheckable, session ) ) {
return true;
@ -366,7 +365,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
SharedSessionContractImplementor session)
throws HibernateException, SQLException {
Object[] subvalues = nullSafeGetValues( value );
final Object[] subvalues = nullSafeGetValues( value );
int loc = 0;
for ( int i = 0; i < propertySpan; i++ ) {
int len = propertyTypes[i].getColumnSpan( session.getFactory() );
@ -381,7 +380,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
}
}
else {
boolean[] subsettable = new boolean[len];
final boolean[] subsettable = new boolean[len];
System.arraycopy( settable, loc, subsettable, 0, len );
propertyTypes[i].nullSafeSet( st, subvalues[i], begin, subsettable, session );
begin += ArrayHelper.countTrue( subsettable );
@ -409,18 +408,15 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
if ( component == null ) {
return null;
}
if ( component instanceof Object[] ) {
else if ( component instanceof Object[] ) {
// A few calls to hashCode pass the property values already in an
// Object[] (ex: QueryKey hash codes for cached queries).
// It's easiest to just check for the condition here prior to
// trying reflection.
return ( (Object[]) component )[i];
return ((Object[]) component)[i];
}
else {
return mappingModelPart
.getEmbeddableTypeDescriptor()
.getValue( component, i );
return embeddableTypeDescriptor().getValue( component, i );
}
}
@ -442,15 +438,13 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
return (Object[]) component;
}
else {
return mappingModelPart
.getEmbeddableTypeDescriptor()
.getValues( component );
return embeddableTypeDescriptor().getValues( component );
}
}
@Override
public void setPropertyValues(Object component, Object[] values) {
mappingModelPart.getEmbeddableTypeDescriptor().setValues( component, values );
embeddableTypeDescriptor().setValues( component, values );
}
@Override
@ -475,8 +469,8 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
return "null";
}
Map<String, String> result = new HashMap<>();
Object[] values = getPropertyValues( value );
final Map<String, String> result = new HashMap<>();
final Object[] values = getPropertyValues( value );
for ( int i = 0; i < propertyTypes.length; i++ ) {
if ( values[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
result.put( propertyNames[i], "<uninitialized>" );
@ -507,10 +501,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
values[i] = propertyTypes[i].deepCopy( values[i], factory );
}
final EmbeddableInstantiator instantiator = mappingModelPart.getEmbeddableTypeDescriptor()
.getRepresentationStrategy()
.getInstantiator();
Object result = instantiator.instantiate( () -> values, factory );
final Object result = instantiator().instantiate( () -> values, factory );
//not absolutely necessary, but helps for some
//equals()/hashCode() implementations
@ -561,10 +552,8 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
);
if ( target == null ) {
final EmbeddableInstantiator instantiator = mappingModelPart.getEmbeddableTypeDescriptor()
.getRepresentationStrategy()
.getInstantiator();
return instantiator.instantiate( () -> replacedValues, session.getSessionFactory() );
return instantiator()
.instantiate( () -> replacedValues, session.getSessionFactory() );
}
else {
setPropertyValues( target, replacedValues );
@ -592,7 +581,6 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
}
//if ( original == target ) return target;
final Object[] originalValues = getPropertyValues( original );
final Object[] resultValues;
@ -614,10 +602,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
);
if ( target == null ) {
final EmbeddableInstantiator instantiator = mappingModelPart.getEmbeddableTypeDescriptor()
.getRepresentationStrategy()
.getInstantiator();
return instantiator.instantiate( () -> replacedValues, session.getSessionFactory() );
return instantiator().instantiate( () -> replacedValues, session.getSessionFactory() );
}
else {
setPropertyValues( target, replacedValues );
@ -638,7 +623,6 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
@Override
public Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner)
throws HibernateException {
if ( value == null ) {
return null;
}
@ -646,7 +630,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
return compositeUserType.disassemble( value );
}
else {
Object[] values = getPropertyValues( value );
final Object[] values = getPropertyValues( value );
for ( int i = 0; i < propertyTypes.length; i++ ) {
values[i] = propertyTypes[i].disassemble( values[i], session, owner );
}
@ -663,7 +647,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
return compositeUserType.disassemble( value );
}
else {
Object[] values = getPropertyValues( value );
final Object[] values = getPropertyValues( value );
for ( int i = 0; i < propertyTypes.length; i++ ) {
values[i] = propertyTypes[i].disassemble( values[i], sessionFactory );
}
@ -682,16 +666,13 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
return compositeUserType.assemble( object, owner );
}
else {
Object[] values = (Object[]) object;
Object[] assembled = new Object[values.length];
final Object[] values = (Object[]) object;
final Object[] assembled = new Object[values.length];
for ( int i = 0; i < propertyTypes.length; i++ ) {
assembled[i] = propertyTypes[i].assemble( (Serializable) values[i], session, owner );
}
final EmbeddableInstantiator instantiator = mappingModelPart.getEmbeddableTypeDescriptor()
.getRepresentationStrategy()
.getInstantiator();
return instantiator.instantiate( () -> assembled, session.getFactory() );
return instantiator().instantiate( () -> assembled, session.getFactory() );
}
}
@ -707,16 +688,15 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
@Override
public boolean[] toColumnNullness(Object value, Mapping mapping) {
boolean[] result = new boolean[getColumnSpan( mapping )];
if ( value == null ) {
return result;
}
Object[] values = getPropertyValues( value ); //TODO!!!!!!!
int loc = 0;
for ( int i = 0; i < propertyTypes.length; i++ ) {
boolean[] propertyNullness = propertyTypes[i].toColumnNullness( values[i], mapping );
System.arraycopy( propertyNullness, 0, result, loc, propertyNullness.length );
loc += propertyNullness.length;
final boolean[] result = new boolean[getColumnSpan( mapping )];
if ( value != null ) {
final Object[] values = getPropertyValues( value ); //TODO!!!!!!!
int loc = 0;
for ( int i = 0; i < propertyTypes.length; i++ ) {
final boolean[] propertyNullness = propertyTypes[i].toColumnNullness( values[i], mapping );
System.arraycopy( propertyNullness, 0, result, loc, propertyNullness.length );
loc += propertyNullness.length;
}
}
return result;
}
@ -728,7 +708,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
@Override
public int getPropertyIndex(String name) {
String[] names = getPropertyNames();
final String[] names = getPropertyNames();
for ( int i = 0, max = names.length; i < max; i++ ) {
if ( names[i].equals( name ) ) {
return i;
@ -756,7 +736,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
@Override
public JdbcType getJdbcType() {
final SelectableMapping aggregateMapping = mappingModelPart.getEmbeddableTypeDescriptor().getAggregateMapping();
final SelectableMapping aggregateMapping = embeddableTypeDescriptor().getAggregateMapping();
return aggregateMapping == null ? null : aggregateMapping.getJdbcMapping().getJdbcType();
}
@ -776,10 +756,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
public Object extract(CallableStatement statement, int startIndex, SharedSessionContractImplementor session) throws SQLException {
Object[] values;
if ( isAggregate() ) {
values = (Object[]) getMappingModelPart().getEmbeddableTypeDescriptor().getAggregateMapping()
.getJdbcMapping()
.getJdbcValueExtractor()
.extract( statement, startIndex, session );
values = (Object[]) jdbcValueExtractor().extract( statement, startIndex, session );
}
else {
values = new Object[propertySpan];
@ -788,8 +765,9 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
for ( int i = 0; i < propertySpan; i++ ) {
// we know this cast is safe from canDoExtraction
final Type propertyType = propertyTypes[i];
final Object value = ( (ProcedureParameterExtractionAware<?>) propertyType )
.extract( statement, currentIndex, session );
final ProcedureParameterExtractionAware<?> extractionAware =
(ProcedureParameterExtractionAware<?>) propertyType;
final Object value = extractionAware.extract( statement, currentIndex, session );
if ( value == null ) {
if ( isKey ) {
return null; //different nullability rules for pk/fk
@ -813,21 +791,24 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
@Override
public Object extract(CallableStatement statement, String paramName, SharedSessionContractImplementor session)
throws SQLException {
assert isAggregate();
final Object[] values = (Object[]) getMappingModelPart().getEmbeddableTypeDescriptor().getAggregateMapping()
.getJdbcMapping()
.getJdbcValueExtractor()
.extract( statement, paramName, session );
return resolve( values, session );
return resolve( (Object[]) jdbcValueExtractor().extract( statement, paramName, session ), session );
}
private Object resolve(Object[] value, SharedSessionContractImplementor session) throws HibernateException {
final EmbeddableInstantiator instantiator = mappingModelPart.getEmbeddableTypeDescriptor()
.getRepresentationStrategy()
.getInstantiator();
return instantiator.instantiate( () -> value, session.getFactory() );
return instantiator().instantiate( () -> value, session.getFactory() );
}
private EmbeddableMappingType embeddableTypeDescriptor() {
return mappingModelPart.getEmbeddableTypeDescriptor();
}
private ValueExtractor<?> jdbcValueExtractor() {
return embeddableTypeDescriptor().getAggregateMapping().getJdbcMapping().getJdbcValueExtractor();
}
private EmbeddableInstantiator instantiator() {
return embeddableTypeDescriptor().getRepresentationStrategy().getInstantiator();
}
@Override
@ -842,12 +823,12 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
@Override
public SqmExpressible<?> resolveExpressible(SessionFactoryImplementor sessionFactory) {
return sessionFactory.getRuntimeMetamodels().getJpaMetamodel().embeddable( getReturnedClass() );
return sessionFactory.getJpaMetamodel().embeddable( getReturnedClass() );
}
@Override
public void injectMappingModelPart(EmbeddableValuedModelPart part, MappingModelCreationProcess process) {
this.mappingModelPart = part;
mappingModelPart = part;
}
@Override