diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java deleted file mode 100644 index fddcf14f4fa7..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.event.internal; - -import org.hibernate.HibernateException; -import org.hibernate.engine.spi.NaturalIdResolutions; -import org.hibernate.event.spi.EventSource; -import org.hibernate.event.spi.ResolveNaturalIdEvent; -import org.hibernate.event.spi.ResolveNaturalIdEventListener; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.stat.spi.StatisticsImplementor; - -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.concurrent.TimeUnit.NANOSECONDS; -import static org.hibernate.pretty.MessageHelper.infoString; - -/** - * Defines the default load event listeners used by hibernate for loading entities - * in response to generated load events. - * - * @author Eric Dalquist - * @author Steve Ebersole - */ -public class DefaultResolveNaturalIdEventListener implements ResolveNaturalIdEventListener { - - private static final CoreMessageLogger LOG = CoreLogging.messageLogger( DefaultResolveNaturalIdEventListener.class ); - - @Override - public void onResolveNaturalId(ResolveNaturalIdEvent event) throws HibernateException { - event.setEntityId( resolveNaturalId( event ) ); - } - - /** - * Coordinates the efforts to load a given entity. First, an attempt is - * made to load the entity from the session-level cache. If not found there, - * an attempt is made to locate it in second-level cache. Lastly, an - * attempt is made to load it directly from the datasource. - * - * @param event The load event - * - * @return The loaded entity, or null. - */ - protected Object resolveNaturalId(final ResolveNaturalIdEvent event) { - final EntityPersister persister = event.getEntityPersister(); - - if ( LOG.isTraceEnabled() ) { - LOG.trace( "Attempting to resolve: " + infoString( persister ) + "#" + event.getNaturalIdValues() ); - } - - final Object entityId = resolveFromCache( event ); - if ( entityId != null ) { - if ( LOG.isTraceEnabled() ) { - LOG.trace( "Resolved object in cache: " + infoString( persister ) + "#" + event.getNaturalIdValues() ); - } - return entityId; - } - else { - if ( LOG.isTraceEnabled() ) { - LOG.trace( "Object not resolved in any cache: "+ infoString( persister ) + "#" + event.getNaturalIdValues() ); - } - return loadFromDatasource( event ); - } - } - - /** - * Attempts to resolve the entity id corresponding to the event's natural id values from the session - * - * @param event The load event - * - * @return The entity from the cache, or null. - */ - protected Object resolveFromCache(ResolveNaturalIdEvent event) { - return getNaturalIdResolutions( event) - .findCachedIdByNaturalId( event.getOrderedNaturalIdValues(), event.getEntityPersister() ); - } - - /** - * Performs the process of loading an entity from the configured - * underlying datasource. - * - * @param event The load event - * - * @return The object loaded from the datasource, or null if not found. - */ - protected Object loadFromDatasource(ResolveNaturalIdEvent event) { - final EventSource session = event.getSession(); - final EntityPersister entityPersister = event.getEntityPersister(); - final StatisticsImplementor statistics = event.getFactory().getStatistics(); - final boolean statisticsEnabled = statistics.isStatisticsEnabled(); - final long startTime = statisticsEnabled ? System.nanoTime() : 0; - - final Object pk = entityPersister.loadEntityIdByNaturalId( - event.getOrderedNaturalIdValues(), - event.getLockOptions(), - session - ); - - if ( statisticsEnabled ) { - final long endTime = System.nanoTime(); - final long milliseconds = MILLISECONDS.convert( endTime - startTime, NANOSECONDS ); - statistics.naturalIdQueryExecuted( entityPersister.getRootEntityName(), milliseconds ); - } - - //PK can be null if the entity doesn't exist - if ( pk != null ) { - getNaturalIdResolutions( event ) - .cacheResolutionFromLoad( pk, event.getOrderedNaturalIdValues(), entityPersister ); - } - return pk; - } - - private static NaturalIdResolutions getNaturalIdResolutions(ResolveNaturalIdEvent event) { - return event.getSession().getPersistenceContextInternal().getNaturalIdResolutions(); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java index 0f31df941a52..95111991da73 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java @@ -29,7 +29,6 @@ import org.hibernate.event.internal.DefaultPreLoadEventListener; import org.hibernate.event.internal.DefaultRefreshEventListener; import org.hibernate.event.internal.DefaultReplicateEventListener; -import org.hibernate.event.internal.DefaultResolveNaturalIdEventListener; import org.hibernate.event.internal.PostDeleteEventListenerStandardImpl; import org.hibernate.event.internal.PostInsertEventListenerStandardImpl; import org.hibernate.event.internal.PostUpdateEventListenerStandardImpl; @@ -75,7 +74,6 @@ import static org.hibernate.event.spi.EventType.PRE_UPSERT; import static org.hibernate.event.spi.EventType.REFRESH; import static org.hibernate.event.spi.EventType.REPLICATE; -import static org.hibernate.event.spi.EventType.RESOLVE_NATURAL_ID; /** * Standard implementation of EventListenerRegistry @@ -123,8 +121,9 @@ public final void setListeners(EventType type, Class... list setListeners( type, resolveListenerInstances( type, listenerClasses ) ); } - @SuppressWarnings( {"unchecked"}) + @SafeVarargs private T[] resolveListenerInstances(EventType type, Class... listenerClasses) { + @SuppressWarnings("unchecked") T[] listeners = (T[]) Array.newInstance( type.baseListenerInterface(), listenerClasses.length ); for ( int i = 0; i < listenerClasses.length; i++ ) { listeners[i] = resolveListenerInstance( listenerClasses[i] ); @@ -132,8 +131,8 @@ private T[] resolveListenerInstances(EventType type, Class.. return listeners; } - @SuppressWarnings( {"unchecked"}) private T resolveListenerInstance(Class listenerClass) { + @SuppressWarnings("unchecked") T listenerInstance = (T) listenerClassToInstanceMap.get( listenerClass ); if ( listenerInstance == null ) { listenerInstance = instantiateListener( listenerClass ); @@ -240,9 +239,6 @@ private void applyStandardListeners() { // load listeners prepareListeners( LOAD, new DefaultLoadEventListener() ); - // resolve natural-id listeners - prepareListeners( RESOLVE_NATURAL_ID, new DefaultResolveNaturalIdEventListener() ); - // load-collection listeners prepareListeners( INIT_COLLECTION, new DefaultInitializeCollectionEventListener() ); diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/EventType.java b/hibernate-core/src/main/java/org/hibernate/event/spi/EventType.java index 55a5ad587b85..9dea91db93be 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/EventType.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/EventType.java @@ -25,7 +25,6 @@ public final class EventType { private static final AtomicInteger STANDARD_TYPE_COUNTER = new AtomicInteger(); public static final EventType LOAD = create( "load", LoadEventListener.class ); - public static final EventType RESOLVE_NATURAL_ID = create( "resolve-natural-id", ResolveNaturalIdEventListener.class ); public static final EventType INIT_COLLECTION = create( "load-collection", InitializeCollectionEventListener.class ); @@ -156,8 +155,7 @@ public String eventName() { return eventName; } - @SuppressWarnings("rawtypes") - public Class baseListenerInterface() { + public Class baseListenerInterface() { return baseListenerInterface; } diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/ResolveNaturalIdEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/ResolveNaturalIdEvent.java deleted file mode 100644 index 73e407779cad..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/ResolveNaturalIdEvent.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.event.spi; - -import java.util.Collections; -import java.util.Map; - -import org.hibernate.HibernateException; -import org.hibernate.LockMode; -import org.hibernate.LockOptions; -import org.hibernate.persister.entity.EntityPersister; - -/** - * Defines an event class for the resolving of an entity id from the entity's natural-id - * - * @author Eric Dalquist - * @author Steve Ebersole - */ -public class ResolveNaturalIdEvent extends AbstractEvent { - public static final LockMode DEFAULT_LOCK_MODE = LockMode.NONE; - - private final EntityPersister entityPersister; - private final Map naturalIdValues; - private final Object[] orderedNaturalIdValues; - private final LockOptions lockOptions; - - private Object entityId; - - public ResolveNaturalIdEvent(Map naturalIdValues, EntityPersister entityPersister, EventSource source) { - this( naturalIdValues, entityPersister, LockOptions.NONE, source ); - } - - public ResolveNaturalIdEvent( - Map naturalIdValues, - EntityPersister entityPersister, - LockOptions lockOptions, - EventSource source) { - super( source ); - - if ( entityPersister == null ) { - throw new IllegalArgumentException( "EntityPersister is required for loading" ); - } - - if ( ! entityPersister.hasNaturalIdentifier() ) { - throw new HibernateException( "Entity did not define a natural-id" ); - } - - if ( naturalIdValues == null || naturalIdValues.isEmpty() ) { - throw new IllegalArgumentException( "natural-id to load is required" ); - } - - if ( entityPersister.getNaturalIdentifierProperties().length != naturalIdValues.size() ) { - throw new HibernateException( - String.format( - "Entity [%s] defines its natural-id with %d properties but only %d were specified", - entityPersister.getEntityName(), - entityPersister.getNaturalIdentifierProperties().length, - naturalIdValues.size() - ) - ); - } - - if ( lockOptions.getLockMode() == LockMode.WRITE ) { - throw new IllegalArgumentException( "Invalid lock mode for loading" ); - } - else if ( lockOptions.getLockMode() == null ) { - lockOptions.setLockMode( DEFAULT_LOCK_MODE ); - } - - this.entityPersister = entityPersister; - this.naturalIdValues = naturalIdValues; - this.lockOptions = lockOptions; - - int[] naturalIdPropertyPositions = entityPersister.getNaturalIdentifierProperties(); - orderedNaturalIdValues = new Object[naturalIdPropertyPositions.length]; - int i = 0; - for ( int position : naturalIdPropertyPositions ) { - final String propertyName = entityPersister.getPropertyNames()[position]; - if ( ! naturalIdValues.containsKey( propertyName ) ) { - throw new HibernateException( - String.format( "No value specified for natural-id property %s#%s", getEntityName(), propertyName ) - ); - } - orderedNaturalIdValues[i++] = naturalIdValues.get( entityPersister.getPropertyNames()[position] ); - } - } - - public Map getNaturalIdValues() { - return Collections.unmodifiableMap( naturalIdValues ); - } - - public Object[] getOrderedNaturalIdValues() { - return orderedNaturalIdValues; - } - - public EntityPersister getEntityPersister() { - return entityPersister; - } - - public String getEntityName() { - return getEntityPersister().getEntityName(); - } - - public LockOptions getLockOptions() { - return lockOptions; - } - - public Object getEntityId() { - return entityId; - } - - public void setEntityId(Object entityId) { - this.entityId = entityId; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/ResolveNaturalIdEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/spi/ResolveNaturalIdEventListener.java deleted file mode 100644 index 19855f2df9d6..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/ResolveNaturalIdEventListener.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.event.spi; - -import org.hibernate.HibernateException; - -/** - * Defines the contract for handling of resolve natural id events generated from a session. - * - * @author Eric Dalquist - * @author Steve Ebersole - */ -public interface ResolveNaturalIdEventListener { - - /** - * Handle the given resolve natural id event. - * - * @param event The resolve natural id event to be handled. - * - * @throws HibernateException Indicates a problem resolving natural id to primary key - */ - void onResolveNaturalId(ResolveNaturalIdEvent event) throws HibernateException; - -} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java index 504623f3a945..72b868330c71 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java @@ -117,7 +117,6 @@ public final class FastSessionServices { public final EventListenerGroup eventListenerGroup_PRE_UPSERT; public final EventListenerGroup eventListenerGroup_REFRESH; public final EventListenerGroup eventListenerGroup_REPLICATE; - public final EventListenerGroup eventListenerGroup_RESOLVE_NATURAL_ID; // Fields used only from within this package final boolean disallowOutOfTransactionUpdateOperations; @@ -196,7 +195,6 @@ public final class FastSessionServices { this.eventListenerGroup_PRE_UPSERT = listeners( eventListenerRegistry, EventType.PRE_UPSERT ); this.eventListenerGroup_REFRESH = listeners( eventListenerRegistry, EventType.REFRESH ); this.eventListenerGroup_REPLICATE = listeners( eventListenerRegistry, EventType.REPLICATE ); - this.eventListenerGroup_RESOLVE_NATURAL_ID = listeners( eventListenerRegistry, EventType.RESOLVE_NATURAL_ID ); //Other highly useful constants: this.dialect = jdbcServices.getJdbcEnvironment().getDialect(); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index de6af4828d74..2b366cc15902 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -104,8 +104,6 @@ import org.hibernate.event.spi.RefreshEventListener; import org.hibernate.event.spi.ReplicateEvent; import org.hibernate.event.spi.ReplicateEventListener; -import org.hibernate.event.spi.ResolveNaturalIdEvent; -import org.hibernate.event.spi.ResolveNaturalIdEventListener; import org.hibernate.loader.internal.CacheLoadHelper; import org.hibernate.resource.transaction.spi.TransactionObserver; import org.hibernate.event.monitor.spi.EventMonitor; @@ -1286,14 +1284,6 @@ private void fireLoadNoChecks(final LoadEvent event, final LoadType loadType) { .fireEventOnEachListener( event, loadType, LoadEventListener::onLoad ); } - private void fireResolveNaturalId(final ResolveNaturalIdEvent event) { - checkOpenOrWaitingForAutoClose(); - pulseTransactionCoordinator(); - fastSessionServices.eventListenerGroup_RESOLVE_NATURAL_ID - .fireEventOnEachListener( event, ResolveNaturalIdEventListener::onResolveNaturalId ); - delayedAfterCompletion(); - } - // refresh() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/loader/internal/SimpleNaturalIdLoadAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/internal/SimpleNaturalIdLoadAccessImpl.java index 37c43ec53aad..4571d09b5257 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/internal/SimpleNaturalIdLoadAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/internal/SimpleNaturalIdLoadAccessImpl.java @@ -74,34 +74,29 @@ public T load(Object naturalIdValue) { return doLoad( entityPersister().getNaturalIdMapping().normalizeInput( naturalIdValue) ); } + /** + * Verify that the given natural id is "simple". + *

+ * We allow compound natural id "simple" loading if all the values are passed as an array, + * list, or map. We assume an array is properly ordered following the attribute ordering. + * For lists, just like arrays, we assume the user has ordered them properly; for maps, + * the key is expected to be the attribute name. + */ private void verifySimplicity(Object naturalIdValue) { assert naturalIdValue != null; - - if ( hasSimpleNaturalId ) { - // implicitly - return; - } - - if ( naturalIdValue.getClass().isArray() ) { - // we allow compound natural-id "simple" loading all the values are passed as an array - // (we assume the array is properly ordered following the mapping-model attribute ordering) - return; - } - - if ( naturalIdValue instanceof List || naturalIdValue instanceof Map ) { - // also allowed. For Lists, just like arrays, we assume the user has ordered them properly; - // for Maps, the key is expected to be the attribute name - return; + if ( !hasSimpleNaturalId + && !naturalIdValue.getClass().isArray() + && !(naturalIdValue instanceof List) + && !(naturalIdValue instanceof Map) ) { + throw new HibernateException( + String.format( + Locale.ROOT, + "Cannot interpret natural-id value [%s] for compound natural-id: %s", + naturalIdValue, + entityPersister().getEntityName() + ) + ); } - - throw new HibernateException( - String.format( - Locale.ROOT, - "Cannot interpret natural-id value [%s] for compound natural-id: %s", - naturalIdValue, - entityPersister().getEntityName() - ) - ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java index 7f0bd0797b96..64cd2e81be9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java @@ -13,7 +13,6 @@ import org.hibernate.HibernateException; import org.hibernate.cache.MutableCacheKeyBuilder; import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.util.IndexedConsumer; import org.hibernate.loader.ast.internal.CompoundNaturalIdLoader; @@ -22,7 +21,6 @@ import org.hibernate.loader.ast.spi.NaturalIdLoader; import org.hibernate.metamodel.UnsupportedMappingException; import org.hibernate.metamodel.mapping.AttributeMapping; -import org.hibernate.metamodel.mapping.AttributeMetadata; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.MappingType; @@ -89,7 +87,6 @@ public CompoundNaturalIdMapping( ) ); this.jdbcMappings = jdbcMappings; - return true; } ); @@ -97,13 +94,10 @@ public CompoundNaturalIdMapping( private static boolean isMutable(List attributes) { for ( int i = 0; i < attributes.size(); i++ ) { - final SingularAttributeMapping attributeMapping = attributes.get( i ); - final AttributeMetadata metadata = attributeMapping.getAttributeMetadata(); - if ( metadata.isUpdatable() ) { + if ( attributes.get( i ).getAttributeMetadata().isUpdatable() ) { return true; } } - return false; } @@ -112,41 +106,34 @@ public Object[] extractNaturalIdFromEntityState(Object[] state) { if ( state == null ) { return null; } - - if ( state.length == attributes.size() ) { + else if ( state.length == attributes.size() ) { return state; } - - final Object[] values = new Object[ attributes.size() ]; - - for ( int i = 0; i <= attributes.size() - 1; i++ ) { - final SingularAttributeMapping attributeMapping = attributes.get( i ); - values[ i ] = state[ attributeMapping.getStateArrayPosition() ]; + else { + final Object[] values = new Object[attributes.size()]; + for ( int i = 0; i <= attributes.size() - 1; i++ ) { + final SingularAttributeMapping attributeMapping = attributes.get( i ); + values[i] = state[attributeMapping.getStateArrayPosition()]; + } + return values; } - - return values; } @Override public Object[] extractNaturalIdFromEntity(Object entity) { final Object[] values = new Object[ attributes.size() ]; - for ( int i = 0; i < attributes.size(); i++ ) { values[i] = attributes.get( i ).getPropertyAccess().getGetter().get( entity ); } - return values; } @Override - @SuppressWarnings( "rawtypes" ) public Object[] normalizeInput(Object incoming) { - if ( incoming instanceof Object[] ) { - return (Object[]) incoming; + if ( incoming instanceof Object[] array ) { + return array; } - - if ( incoming instanceof Map ) { - final Map valueMap = (Map) incoming; + else if ( incoming instanceof Map valueMap ) { final List attributes = getNaturalIdAttributes(); final Object[] values = new Object[ attributes.size() ]; for ( int i = 0; i < attributes.size(); i++ ) { @@ -154,30 +141,28 @@ public Object[] normalizeInput(Object incoming) { } return values; } - - throw new UnsupportedMappingException( "Do not know how to normalize compound natural-id value : " + incoming ); + else { + throw new UnsupportedMappingException( "Could not normalize compound natural-id value: " + incoming ); + } } @Override public void validateInternalForm(Object naturalIdValue) { - if ( naturalIdValue == null ) { - return; - } - - // should be an array, with a size equal to the number of attributes making up this compound natural-id - if ( naturalIdValue instanceof Object[] ) { - final Object[] values = (Object[]) naturalIdValue; - if ( values.length != attributes.size() ) { + if ( naturalIdValue != null ) { + // should be an array, with a size equal to the number of attributes making up this compound natural-id + if ( naturalIdValue instanceof Object[] values ) { + if ( values.length != attributes.size() ) { + throw new IllegalArgumentException( + "Natural-id value [" + naturalIdValue + "] did not contain the expected number of elements [" + + attributes.size() + "]" + ); + } + } + else { throw new IllegalArgumentException( - "Natural-id value [" + naturalIdValue + "] did not contain the expected number of elements [" - + attributes.size() + "]" - ); + "Natural-id value [" + naturalIdValue + "] was not an array as expected" ); } - - return; } - - throw new IllegalArgumentException( "Natural-id value [" + naturalIdValue + "] was not an array as expected" ); } @Override @@ -185,71 +170,65 @@ public int calculateHashCode(Object value) { if ( value == null ) { return 0; } - Object[] values = (Object[]) value; - int hashcode = 0; - for ( int i = 0; i < attributes.size(); i++ ) { - final Object o = values[i]; - if ( o != null ) { - hashcode = 27 * hashcode + ( (JavaType) attributes.get( i ).getExpressibleJavaType() ).extractHashCode( o ); + else { + final Object[] values = (Object[]) value; + int hashcode = 0; + for ( int i = 0; i < attributes.size(); i++ ) { + final Object o = values[i]; + if ( o != null ) { + hashcode = 27 * hashcode + + ((JavaType) attributes.get( i ).getExpressibleJavaType()).extractHashCode( o ); + } } + return hashcode; } - return hashcode; } @Override public void verifyFlushState(Object id, Object[] currentState, Object[] loadedState, SharedSessionContractImplementor session) { - if ( isMutable() ) { - // EARLY EXIT!!! - // the natural id is mutable (!immutable), no need to do the checks - return; - } - - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - final EntityPersister persister = getDeclaringType().getEntityPersister(); - - final Object[] naturalId = extractNaturalIdFromEntityState( currentState ); - - final Object snapshot = loadedState == null - ? persistenceContext.getNaturalIdSnapshot( id, persister ) - : persister.getNaturalIdMapping().extractNaturalIdFromEntityState( loadedState ); - final Object[] previousNaturalId = (Object[]) snapshot; - - assert naturalId.length == getNaturalIdAttributes().size(); - assert previousNaturalId.length == naturalId.length; - - for ( int i = 0; i < getNaturalIdAttributes().size(); i++ ) { - final SingularAttributeMapping attributeMapping = getNaturalIdAttributes().get( i ); - - final boolean updatable = attributeMapping.getAttributeMetadata().isUpdatable(); - if ( updatable ) { - // property is updatable (mutable), there is nothing to check - continue; - } - - final Object currentValue = naturalId[ i ]; - final Object previousValue = previousNaturalId[ i ]; - - if ( ! attributeMapping.areEqual( currentValue, previousValue, session ) ) { - throw new HibernateException( - String.format( - "An immutable attribute [%s] within compound natural identifier of entity %s was altered from `%s` to `%s`", - attributeMapping.getAttributeName(), - persister.getEntityName(), - previousValue, - currentValue - ) - ); + if ( !isMutable() ) { + final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); + final EntityPersister persister = getDeclaringType().getEntityPersister(); + + final Object[] naturalId = extractNaturalIdFromEntityState( currentState ); + final Object snapshot = loadedState == null + ? persistenceContext.getNaturalIdSnapshot( id, persister ) + : persister.getNaturalIdMapping().extractNaturalIdFromEntityState( loadedState ); + final Object[] previousNaturalId = (Object[]) snapshot; + assert naturalId.length == getNaturalIdAttributes().size(); + assert previousNaturalId.length == naturalId.length; + + for ( int i = 0; i < getNaturalIdAttributes().size(); i++ ) { + final SingularAttributeMapping attributeMapping = getNaturalIdAttributes().get( i ); + final boolean updatable = attributeMapping.getAttributeMetadata().isUpdatable(); + if ( !updatable ) { + final Object currentValue = naturalId[i]; + final Object previousValue = previousNaturalId[i]; + if ( !attributeMapping.areEqual( currentValue, previousValue, session ) ) { + throw new HibernateException( + String.format( + "An immutable attribute [%s] within compound natural identifier of entity %s was altered from `%s` to `%s`", + attributeMapping.getAttributeName(), + persister.getEntityName(), + previousValue, + currentValue + ) + ); + } + } + // else property is updatable (mutable), there is nothing to check } } + // otherwise the natural id is mutable (!immutable), no need to do the checks } @Override public boolean areEqual(Object one, Object other, SharedSessionContractImplementor session) { - final Object[] one1 = (Object[]) one; - final Object[] other1 = (Object[]) other; + final Object[] oneArray = (Object[]) one; + final Object[] otherArray = (Object[]) other; final List naturalIdAttributes = getNaturalIdAttributes(); for ( int i = 0; i < naturalIdAttributes.size(); i++ ) { - if ( !naturalIdAttributes.get( i ).areEqual( one1[i], other1[i], session ) ) { + if ( !naturalIdAttributes.get( i ).areEqual( oneArray[i], otherArray[i], session ) ) { return false; } } @@ -305,18 +284,14 @@ public boolean hasPartitionedSelectionMapping() { public DomainResult createDomainResult(NavigablePath navigablePath, TableGroup tableGroup, String resultVariable, DomainResultCreationState creationState) { assert navigablePath.getLocalName().equals( NaturalIdMapping.PART_NAME ); - final SessionFactoryImplementor sessionFactory = creationState.getSqlAstCreationState().getCreationContext().getSessionFactory(); - - final JavaType jtd = sessionFactory - .getTypeConfiguration() - .getJavaTypeRegistry() - .getDescriptor( Object[].class ); + final JavaType jtd = + creationState.getSqlAstCreationState().getCreationContext().getSessionFactory() + .getTypeConfiguration().getJavaTypeRegistry() + .getDescriptor( Object[].class ); // register the table group under `...{natural-id}` as well - creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup( - navigablePath, - (np) -> tableGroup - ); + creationState.getSqlAstCreationState().getFromClauseAccess() + .resolveTableGroup( navigablePath, np -> tableGroup ); return (DomainResult) new DomainResultImpl( navigablePath, @@ -352,15 +327,14 @@ public int breakDownJdbcValues( int span = 0; if ( domainValue == null ) { for ( int i = 0; i < attributes.size(); i++ ) { - span += attributes.get( i ).breakDownJdbcValues( null, offset + span, x, y, valueConsumer, session ); + span += attributes.get( i ) + .breakDownJdbcValues( null, offset + span, x, y, valueConsumer, session ); } } else { assert domainValue instanceof Object[]; - final Object[] values = (Object[]) domainValue; assert values.length == attributes.size(); - for ( int i = 0; i < attributes.size(); i++ ) { span += attributes.get( i ).breakDownJdbcValues( values[i], @@ -412,19 +386,16 @@ public Object disassemble(Object value, SharedSessionContractImplementor session if ( value == null ) { return null; } - assert value instanceof Object[]; - - final Object[] incoming = (Object[]) value; - assert incoming.length == attributes.size(); - - final Object[] outgoing = new Object[ incoming.length ]; - - for ( int i = 0; i < attributes.size(); i++ ) { - final SingularAttributeMapping attribute = attributes.get( i ); - outgoing[ i ] = attribute.disassemble( incoming[ i ], session ); + else { + assert value instanceof Object[]; + final Object[] incoming = (Object[]) value; + assert incoming.length == attributes.size(); + final Object[] outgoing = new Object[incoming.length]; + for ( int i = 0; i < attributes.size(); i++ ) { + outgoing[i] = attributes.get( i ).disassemble( incoming[i], session ); + } + return outgoing; } - - return outgoing; } @Override @@ -436,10 +407,8 @@ public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedS } else { assert value instanceof Object[]; - final Object[] values = (Object[]) value; assert values.length == attributes.size(); - for ( int i = 0; i < attributes.size(); i++ ) { attributes.get( i ).addToCacheKey( cacheKey, values[i], session ); } @@ -505,10 +474,8 @@ public int forEachJdbcValue( } else { assert value instanceof Object[]; - final Object[] incoming = (Object[]) value; assert incoming.length == attributes.size(); - for ( int i = 0; i < attributes.size(); i++ ) { final SingularAttributeMapping attribute = attributes.get( i ); span += attribute.forEachJdbcValue( incoming[i], span + offset, x, y, valuesConsumer, session ); @@ -575,7 +542,6 @@ public DomainResultImpl( this.naturalIdMapping = naturalIdMapping; this.arrayJtd = arrayJtd; this.resultVariable = resultVariable; - this.fetches = creationState.visitFetches( this ); this.hasJoinFetches = this.fetches.hasJoinFetches(); this.containsCollectionFetches = this.fetches.containsCollectionFetches(); @@ -593,13 +559,7 @@ public String getResultVariable() { public DomainResultAssembler createResultAssembler( InitializerParent parent, AssemblerCreationState creationState) { - return new AssemblerImpl( - fetches, - navigablePath, - naturalIdMapping, - arrayJtd, - creationState - ); + return new AssemblerImpl( fetches, arrayJtd, creationState ); } @Override @@ -655,15 +615,9 @@ public boolean containsCollectionFetches() { private static class AssemblerImpl implements DomainResultAssembler { private final JavaType jtd; - private final DomainResultAssembler[] subAssemblers; - private AssemblerImpl( - ImmutableFetchList fetches, - NavigablePath navigablePath, - CompoundNaturalIdMapping naturalIdMapping, - JavaType jtd, - AssemblerCreationState creationState) { + private AssemblerImpl(ImmutableFetchList fetches, JavaType jtd, AssemblerCreationState creationState) { this.jtd = jtd; this.subAssemblers = new DomainResultAssembler[fetches.size()]; int i = 0; @@ -672,14 +626,8 @@ private AssemblerImpl( } } - private AssemblerImpl(JavaType jtd, DomainResultAssembler[] subAssemblers) { - this.jtd = jtd; - this.subAssemblers = subAssemblers; - } - @Override - public Object[] assemble( - RowProcessingState rowProcessingState) { + public Object[] assemble(RowProcessingState rowProcessingState) { final Object[] result = new Object[ subAssemblers.length ]; for ( int i = 0; i < subAssemblers.length; i++ ) { result[ i ] = subAssemblers[i].assemble( rowProcessingState ); @@ -710,7 +658,6 @@ public void forEachResultAssembler(BiConsumer, X> consumer, X public JavaType getAssembledJavaType() { return jtd; } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleNaturalIdMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleNaturalIdMapping.java index 0c7db5d7db67..354adc4cb95e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleNaturalIdMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleNaturalIdMapping.java @@ -12,7 +12,7 @@ import org.hibernate.HibernateException; import org.hibernate.cache.MutableCacheKeyBuilder; -import org.hibernate.engine.spi.PersistenceContext; +import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.util.IndexedConsumer; @@ -42,8 +42,8 @@ /** * Single-attribute NaturalIdMapping implementation */ -public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping implements JavaType.CoercionContext, - BasicValuedMapping { +public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping + implements JavaType.CoercionContext, BasicValuedMapping { private final SingularAttributeMapping attribute; private final SessionFactoryImplementor sessionFactory; private final TypeConfiguration typeConfiguration; @@ -52,15 +52,10 @@ public SimpleNaturalIdMapping( SingularAttributeMapping attribute, EntityMappingType declaringType, MappingModelCreationProcess creationProcess) { - super( - declaringType, - attribute.getAttributeMetadata().isUpdatable() - ); + super( declaringType, attribute.getAttributeMetadata().isUpdatable() ); this.attribute = attribute; - this.sessionFactory = creationProcess.getCreationContext().getSessionFactory(); this.typeConfiguration = creationProcess.getCreationContext().getTypeConfiguration(); - } public SingularAttributeMapping getAttribute() { @@ -73,30 +68,24 @@ public void verifyFlushState( Object[] currentState, Object[] loadedState, SharedSessionContractImplementor session) { - if ( isMutable() ) { - // EARLY EXIT!!! - // the natural id is mutable (!immutable), no need to do the checks - return; - } - - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - final EntityPersister persister = getDeclaringType().getEntityPersister(); - - final Object naturalId = extractNaturalIdFromEntityState( currentState ); - final Object snapshot = loadedState == null - ? persistenceContext.getNaturalIdSnapshot( id, persister ) - : persister.getNaturalIdMapping().extractNaturalIdFromEntityState( loadedState ); - - if ( !areEqual( naturalId, snapshot, session ) ) { - throw new HibernateException( - String.format( - "An immutable natural identifier of entity %s was altered from `%s` to `%s`", - persister.getEntityName(), - snapshot, - naturalId - ) - ); + if ( !isMutable() ) { + final EntityPersister persister = getDeclaringType().getEntityPersister(); + final Object naturalId = extractNaturalIdFromEntityState( currentState ); + final Object snapshot = loadedState == null + ? session.getPersistenceContextInternal().getNaturalIdSnapshot( id, persister ) + : persister.getNaturalIdMapping().extractNaturalIdFromEntityState( loadedState ); + if ( !areEqual( naturalId, snapshot, session ) ) { + throw new HibernateException( + String.format( + "An immutable natural identifier of entity %s was altered from `%s` to `%s`", + persister.getEntityName(), + snapshot, + naturalId + ) + ); + } } + // otherwise, the natural id is mutable (!immutable), no need to do the checks } @Override @@ -104,12 +93,12 @@ public Object extractNaturalIdFromEntityState(Object[] state) { if ( state == null ) { return null; } - - if ( state.length == 1 ) { + else if ( state.length == 1 ) { return state[0]; } - - return state[attribute.getStateArrayPosition()]; + else { + return state[attribute.getStateArrayPosition()]; + } } @Override @@ -119,65 +108,61 @@ public Object extractNaturalIdFromEntity(Object entity) { @Override public void validateInternalForm(Object naturalIdValue) { - if ( naturalIdValue == null ) { - return; - } - - final Class naturalIdValueClass = naturalIdValue.getClass(); - if ( naturalIdValueClass.isArray() && !naturalIdValueClass.getComponentType().isPrimitive() ) { - // be flexible - final Object[] values = (Object[]) naturalIdValue; - if ( values.length == 1 ) { - naturalIdValue = values[0]; + if ( naturalIdValue != null ) { + final Class naturalIdValueClass = naturalIdValue.getClass(); + if ( naturalIdValueClass.isArray() && !naturalIdValueClass.getComponentType().isPrimitive() ) { + // be flexible + final Object[] values = (Object[]) naturalIdValue; + if ( values.length == 1 ) { + naturalIdValue = values[0]; + } } - } - if ( !getJavaType().getJavaTypeClass().isInstance( naturalIdValue ) ) { - throw new IllegalArgumentException( - String.format( - Locale.ROOT, - "Incoming natural-id value [%s (`%s`)] is not of expected type [`%s`] and could not be coerced", - naturalIdValue, - naturalIdValueClass.getName(), - getJavaType().getTypeName() - ) - ); + if ( !getJavaType().getJavaTypeClass().isInstance( naturalIdValue ) ) { + throw new IllegalArgumentException( + String.format( + Locale.ROOT, + "Incoming natural-id value [%s (`%s`)] is not of expected type [`%s`] and could not be coerced", + naturalIdValue, + naturalIdValueClass.getName(), + getJavaType().getTypeName() + ) + ); + } } } @Override public int calculateHashCode(Object value) { - //noinspection unchecked - return value == null ? 0 : ( (JavaType) getJavaType() ).extractHashCode( value ); + //noinspection rawtypes,unchecked + return value == null ? 0 : ( (JavaType) getJavaType() ).extractHashCode( value ); } @Override public Object normalizeInput(Object incoming) { - return normalizeIncomingValue( incoming ); + final Object normalizedValue = normalizedValue( incoming ); + return isLoadByIdComplianceEnabled() + ? normalizedValue + : getJavaType().coerce( normalizedValue, this ); } - @SuppressWarnings("rawtypes") - public Object normalizeIncomingValue(Object naturalIdToLoad) { - final Object normalizedValue; - if ( naturalIdToLoad instanceof Map ) { - final Map valueMap = (Map) naturalIdToLoad; + private Object normalizedValue(Object incoming) { + if ( incoming instanceof Map valueMap ) { assert valueMap.size() == 1; assert valueMap.containsKey( getAttribute().getAttributeName() ); - normalizedValue = valueMap.get( getAttribute().getAttributeName() ); + return valueMap.get( getAttribute().getAttributeName() ); } - else if ( naturalIdToLoad instanceof Object[] ) { - final Object[] values = (Object[]) naturalIdToLoad; + else if ( incoming instanceof Object[] values ) { assert values.length == 1; - normalizedValue = values[0]; + return values[0]; } else { - normalizedValue = naturalIdToLoad; + return incoming; } + } - if ( getTypeConfiguration().getJpaCompliance().isLoadByIdComplianceEnabled() ) { - return normalizedValue; - } - return getJavaType().coerce( normalizedValue, this ); + private boolean isLoadByIdComplianceEnabled() { + return getTypeConfiguration().getJpaCompliance().isLoadByIdComplianceEnabled(); } @Override @@ -301,11 +286,13 @@ public NaturalIdLoader makeLoader(EntityMappingType entityDescriptor) { @Override public MultiNaturalIdLoader makeMultiLoader(EntityMappingType entityDescriptor) { - boolean supportsSqlArrayType = supportsSqlArrayType( sessionFactory.getFastSessionServices().jdbcServices.getDialect() ); - if ( supportsSqlArrayType && attribute instanceof BasicAttributeMapping ) { - return new MultiNaturalIdLoaderArrayParam<>( entityDescriptor ); - } - return new MultiNaturalIdLoaderInPredicate<>( entityDescriptor ); + return supportsSqlArrayType( getDialect() ) && attribute instanceof BasicAttributeMapping + ? new MultiNaturalIdLoaderArrayParam<>( entityDescriptor ) + : new MultiNaturalIdLoaderInPredicate<>( entityDescriptor ); + } + + private Dialect getDialect() { + return sessionFactory.getFastSessionServices().jdbcServices.getDialect(); } @Override diff --git a/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/StaticClassLists.java b/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/StaticClassLists.java index a67dd6cd3524..66e6be18abeb 100644 --- a/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/StaticClassLists.java +++ b/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/StaticClassLists.java @@ -47,7 +47,6 @@ public static Class[] typesNeedingArrayCopy() { //Eventlisteners need to be registered for reflection to allow creation via Array#newInstance ; // types need to be in synch with those declared in org.hibernate.event.spi.EventType org.hibernate.event.spi.LoadEventListener[].class, - org.hibernate.event.spi.ResolveNaturalIdEventListener[].class, org.hibernate.event.spi.InitializeCollectionEventListener[].class, org.hibernate.event.spi.PersistEventListener[].class, org.hibernate.event.spi.MergeEventListener[].class,