HHH-18959 remove unused ResolveNaturalIdEvent stuff

this has all been obsolete since Hibernate 6.0
This commit is contained in:
Gavin King 2024-12-21 11:26:18 +01:00
parent 18c56775da
commit 07ecda306a
10 changed files with 177 additions and 528 deletions

View File

@ -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();
}
}

View File

@ -29,7 +29,6 @@ import org.hibernate.event.internal.DefaultPostLoadEventListener;
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_UPDATE;
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
@ -240,9 +238,6 @@ public class EventListenerRegistryImpl implements EventListenerRegistry {
// load listeners
prepareListeners( LOAD, new DefaultLoadEventListener() );
// resolve natural-id listeners
prepareListeners( RESOLVE_NATURAL_ID, new DefaultResolveNaturalIdEventListener() );
// load-collection listeners
prepareListeners( INIT_COLLECTION, new DefaultInitializeCollectionEventListener() );

View File

@ -25,7 +25,6 @@ public final class EventType<T> {
private static final AtomicInteger STANDARD_TYPE_COUNTER = new AtomicInteger();
public static final EventType<LoadEventListener> LOAD = create( "load", LoadEventListener.class );
public static final EventType<ResolveNaturalIdEventListener> RESOLVE_NATURAL_ID = create( "resolve-natural-id", ResolveNaturalIdEventListener.class );
public static final EventType<InitializeCollectionEventListener> INIT_COLLECTION = create( "load-collection", InitializeCollectionEventListener.class );

View File

@ -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<String, Object> naturalIdValues;
private final Object[] orderedNaturalIdValues;
private final LockOptions lockOptions;
private Object entityId;
public ResolveNaturalIdEvent(Map<String, Object> naturalIdValues, EntityPersister entityPersister, EventSource source) {
this( naturalIdValues, entityPersister, LockOptions.NONE, source );
}
public ResolveNaturalIdEvent(
Map<String, Object> 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<String, Object> 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;
}
}

View File

@ -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;
}

View File

@ -117,7 +117,6 @@ public final class FastSessionServices {
public final EventListenerGroup<PreUpsertEventListener> eventListenerGroup_PRE_UPSERT;
public final EventListenerGroup<RefreshEventListener> eventListenerGroup_REFRESH;
public final EventListenerGroup<ReplicateEventListener> eventListenerGroup_REPLICATE;
public final EventListenerGroup<ResolveNaturalIdEventListener> 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();

View File

@ -104,8 +104,6 @@ import org.hibernate.event.spi.RefreshEvent;
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 @@ public class SessionImpl
.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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -74,34 +74,29 @@ public class SimpleNaturalIdLoadAccessImpl<T>
return doLoad( entityPersister().getNaturalIdMapping().normalizeInput( naturalIdValue) );
}
/**
* Verify that the given natural id is "simple".
* <p>
* 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 ( !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()
)
);
}
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;
}
throw new HibernateException(
String.format(
Locale.ROOT,
"Cannot interpret natural-id value [%s] for compound natural-id: %s",
naturalIdValue,
entityPersister().getEntityName()
)
);
}
@Override

View File

@ -13,7 +13,6 @@ import java.util.function.Consumer;
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.MultiNaturalIdLoader;
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 class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
)
);
this.jdbcMappings = jdbcMappings;
return true;
}
);
@ -97,13 +94,10 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
private static boolean isMutable(List<SingularAttributeMapping> 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 class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
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<SingularAttributeMapping> attributes = getNaturalIdAttributes();
final Object[] values = new Object[ attributes.size() ];
for ( int i = 0; i < attributes.size(); i++ ) {
@ -154,30 +141,28 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
}
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() ) {
throw new IllegalArgumentException(
"Natural-id value [" + naturalIdValue + "] did not contain the expected number of elements ["
+ 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 + "] 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 class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
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;
}
if ( !isMutable() ) {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityPersister persister = getDeclaringType().getEntityPersister();
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;
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
)
);
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<SingularAttributeMapping> 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 class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
public <T> DomainResult<T> 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<Object[]> jtd = sessionFactory
.getTypeConfiguration()
.getJavaTypeRegistry()
.getDescriptor( Object[].class );
final JavaType<Object[]> 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<T>) new DomainResultImpl(
navigablePath,
@ -352,15 +327,14 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
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 class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
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 class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
}
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 class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
}
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 class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
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 class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
public DomainResultAssembler<Object[]> 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 class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
private static class AssemblerImpl implements DomainResultAssembler<Object[]> {
private final JavaType<Object[]> jtd;
private final DomainResultAssembler<?>[] subAssemblers;
private AssemblerImpl(
ImmutableFetchList fetches,
NavigablePath navigablePath,
CompoundNaturalIdMapping naturalIdMapping,
JavaType<Object[]> jtd,
AssemblerCreationState creationState) {
private AssemblerImpl(ImmutableFetchList fetches, JavaType<Object[]> jtd, AssemblerCreationState creationState) {
this.jtd = jtd;
this.subAssemblers = new DomainResultAssembler[fetches.size()];
int i = 0;
@ -672,14 +626,8 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
}
}
private AssemblerImpl(JavaType<Object[]> 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 class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
public JavaType<Object[]> getAssembledJavaType() {
return jtd;
}
}
}

View File

@ -12,7 +12,7 @@ import java.util.function.BiConsumer;
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 @@ import static org.hibernate.loader.ast.internal.MultiKeyLoadHelper.supportsSqlAr
/**
* 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 class SimpleNaturalIdMapping extends AbstractNaturalIdMapping implements
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 class SimpleNaturalIdMapping extends AbstractNaturalIdMapping implements
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 class SimpleNaturalIdMapping extends AbstractNaturalIdMapping implements
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 class SimpleNaturalIdMapping extends AbstractNaturalIdMapping implements
@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<Object>) 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 class SimpleNaturalIdMapping extends AbstractNaturalIdMapping implements
@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