diff --git a/hibernate-core/src/main/java/org/hibernate/EntityMode.java b/hibernate-core/src/main/java/org/hibernate/EntityMode.java index 1f07ca88d4..666ef60a34 100644 --- a/hibernate-core/src/main/java/org/hibernate/EntityMode.java +++ b/hibernate-core/src/main/java/org/hibernate/EntityMode.java @@ -8,11 +8,16 @@ package org.hibernate; import java.util.Locale; +import org.hibernate.metamodel.RepresentationMode; + /** * Defines the representation modes available for entities. * * @author Steve Ebersole + * + * @deprecated See {@link RepresentationMode} */ +@Deprecated public enum EntityMode { /** * The {@code pojo} entity mode describes an entity model made up of entity classes (loosely) following diff --git a/hibernate-core/src/main/java/org/hibernate/Interceptor.java b/hibernate-core/src/main/java/org/hibernate/Interceptor.java index f71df01f64..0ed8cba5d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/Interceptor.java +++ b/hibernate-core/src/main/java/org/hibernate/Interceptor.java @@ -9,6 +9,8 @@ package org.hibernate; import java.io.Serializable; import java.util.Iterator; +import org.hibernate.metamodel.RepresentationMode; +import org.hibernate.metamodel.spi.EntityRepresentationStrategy; import org.hibernate.type.Type; /** @@ -202,6 +204,7 @@ public interface Interceptor { Object[] previousState, String[] propertyNames, Type[] types); + /** * Instantiate the entity class. Return null to indicate that Hibernate should use * the default constructor of the class. The identifier property of the returned instance @@ -214,9 +217,24 @@ public interface Interceptor { * @return an instance of the class, or null to choose default behaviour * * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. + * + * @deprecated Use {@link #instantiate(String, EntityRepresentationStrategy, Object)} instead */ + @Deprecated Object instantiate(String entityName, EntityMode entityMode, Serializable id) throws CallbackException; + /** + * Instantiate the entity. Return null to indicate that Hibernate should use + * the default constructor of the class. The identifier property of the returned instance + * should be initialized with the given identifier. + */ + default Object instantiate( + String entityName, + EntityRepresentationStrategy representationStrategy, + Object id) throws CallbackException { + return instantiate( entityName, representationStrategy.getMode().getLegacyEntityMode(), (Serializable) id ); + } + /** * Get the entity name for a persistent or transient instance. * diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java index c9c247d019..f8ad0d4180 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java @@ -38,6 +38,8 @@ import org.hibernate.dialect.function.SQLFunction; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.jpa.internal.MutableJpaComplianceImpl; import org.hibernate.jpa.spi.MutableJpaCompliance; +import org.hibernate.metamodel.internal.StandardManagedTypeRepresentationResolver; +import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver; import org.hibernate.type.spi.TypeConfiguration; import org.jboss.jandex.IndexView; @@ -76,6 +78,7 @@ public class BootstrapContextImpl implements BootstrapContext { private ArrayList auxiliaryDatabaseObjectList; private HashMap attributeConverterDescriptorMap; private ArrayList cacheRegionDefinitions; + private ManagedTypeRepresentationResolver representationStrategySelector; public BootstrapContextImpl( StandardServiceRegistry serviceRegistry, @@ -109,6 +112,9 @@ public class BootstrapContextImpl implements BootstrapContext { ArchiveDescriptorFactory.class, configService.getSettings().get( AvailableSettings.SCANNER_ARCHIVE_INTERPRETER ) ); + + this.representationStrategySelector = StandardManagedTypeRepresentationResolver.INSTANCE; + this.typeConfiguration = new TypeConfiguration(); } @@ -237,6 +243,12 @@ public class BootstrapContextImpl implements BootstrapContext { } } + @Override + public ManagedTypeRepresentationResolver getRepresentationStrategySelector() { + return representationStrategySelector; + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Mutations diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/BootstrapContext.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/BootstrapContext.java index 0996c81a60..ae5c6660fa 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/BootstrapContext.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/BootstrapContext.java @@ -21,6 +21,7 @@ import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.dialect.function.SQLFunction; import org.hibernate.jpa.spi.MutableJpaCompliance; +import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver; import org.hibernate.type.spi.TypeConfiguration; import org.jboss.jandex.IndexView; @@ -171,4 +172,6 @@ public interface BootstrapContext { * @todo verify this ^^ */ void release(); + + ManagedTypeRepresentationResolver getRepresentationStrategySelector(); } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/DisallowedProxyFactory.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/DisallowedProxyFactory.java index 1ae529ffd9..9212384a75 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/DisallowedProxyFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/DisallowedProxyFactory.java @@ -11,7 +11,6 @@ import java.lang.reflect.Method; import java.util.Set; import org.hibernate.HibernateException; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.ProxyFactory; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/FetchStrategy.java b/hibernate-core/src/main/java/org/hibernate/engine/FetchStrategy.java index b29acf18f9..22f137d5e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/FetchStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/FetchStrategy.java @@ -12,6 +12,8 @@ package org.hibernate.engine; * @author Steve Ebersole */ public class FetchStrategy { + public static FetchStrategy IMMEDIATE_JOIN = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN ); + private final FetchTiming timing; private final FetchStyle style; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityKey.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityKey.java index 52a9cd8706..fd1c383ffe 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityKey.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityKey.java @@ -31,7 +31,7 @@ import org.hibernate.pretty.MessageHelper; */ public final class EntityKey implements Serializable { - private final Serializable identifier; + private final Object identifier; private final int hashCode; private final EntityPersister persister; @@ -45,7 +45,7 @@ public final class EntityKey implements Serializable { * @param id The entity id * @param persister The entity persister */ - public EntityKey(Serializable id, EntityPersister persister) { + public EntityKey(Object id, EntityPersister persister) { this.persister = persister; if ( id == null ) { throw new AssertionFailure( "null identifier" ); @@ -66,10 +66,14 @@ public final class EntityKey implements Serializable { return persister.isBatchLoadable(); } - public Serializable getIdentifier() { + public Object getIdentifierValue() { return identifier; } + public Serializable getIdentifier() { + return (Serializable) identifier; + } + public String getEntityName() { return persister.getEntityName(); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java index 432b8650db..9e24e89934 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java @@ -256,9 +256,7 @@ public class DefaultLoadEventListener implements LoadEventListener { .isEnhancementAsProxyEnabled(); final EntityMetamodel entityMetamodel = persister.getEntityMetamodel(); - final boolean entityHasHibernateProxyFactory = entityMetamodel - .getTuplizer() - .getProxyFactory() != null; + final boolean entityHasHibernateProxyFactory = persister.getRepresentationStrategy().getProxyFactory() != null; // Check for the case where we can use the entity itself as a proxy if ( options.isAllowProxyCreation() diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PostLoadEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PostLoadEvent.java index ca4aaedc73..fe0072068a 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/PostLoadEvent.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PostLoadEvent.java @@ -24,6 +24,12 @@ public class PostLoadEvent extends AbstractEvent { super(session); } + public void reset() { + entity = null; + id = null; + persister = null; + } + public Object getEntity() { return entity; } diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java index 8673d8b375..35664ea19a 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java @@ -26,6 +26,13 @@ public class PreLoadEvent extends AbstractEvent implements PermissionCheckEntity super(session); } + public void reset() { + entity = null; + state = null; + id = null; + persister = null; + } + @Override public Object getEntity() { return entity; diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index 012cc9fbc9..ded3258d81 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -34,10 +34,7 @@ import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.SessionEventListener; import org.hibernate.SessionException; import org.hibernate.Transaction; -import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.cache.spi.CacheTransactionSynchronization; -import org.hibernate.cfg.Environment; -import org.hibernate.dialect.Dialect; import org.hibernate.engine.internal.SessionEventListenerManagerImpl; import org.hibernate.engine.jdbc.LobCreationContext; import org.hibernate.engine.jdbc.LobCreator; @@ -645,12 +642,10 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont @Override public NativeQueryImplementor createNativeQuery(String sqlString) { - return getNativeQueryImplementor( sqlString, false ); + return getNativeQueryImplementor( sqlString ); } - protected NativeQueryImplementor getNativeQueryImplementor( - String queryString, - boolean isOrdinalParameterZeroBased) { + protected NativeQueryImplementor getNativeQueryImplementor(String queryString) { checkOpen(); pulseTransactionCoordinator(); delayedAfterCompletion(); 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 dccb07d5fb..a99c72969e 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -33,7 +33,6 @@ import javax.persistence.EntityNotFoundException; import javax.persistence.FlushModeType; import javax.persistence.LockModeType; import javax.persistence.PersistenceException; -import javax.persistence.PessimisticLockScope; import javax.persistence.StoredProcedureQuery; import javax.persistence.TransactionRequiredException; @@ -1377,7 +1376,7 @@ public final class SessionImpl pulseTransactionCoordinator(); Object result = getInterceptor().instantiate( persister.getEntityName(), - persister.getEntityMetamodel().getEntityMode(), + persister.getRepresentationStrategy(), id ); if ( result == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/LoggingHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/log/LoggingHelper.java new file mode 100644 index 0000000000..c99327ed45 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/LoggingHelper.java @@ -0,0 +1,101 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.internal.log; + +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.CollectionKey; +import org.hibernate.engine.spi.EntityKey; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.metamodel.model.domain.NavigableRole; +import org.hibernate.query.NavigablePath; + +/** + * Helper for logging collection, entity and embeddable information. Uses path collapsing + * for readability + * + * @author Steve Ebersole + */ +public class LoggingHelper { + private static final String NULL = ""; + private static final String UNREFERENCED = ""; + + public static String toLoggableString(NavigableRole role) { + if ( role == null ) { + return UNREFERENCED; + } + + if ( role.isRoot() ) { + return StringHelper.collapse( role.getFullPath() ); + } + else { + assert role.getParent() != null; + return StringHelper.collapse( role.getParent().getFullPath() ) + '.' + role.getNavigableName(); + } + } + + public static String toLoggableString(NavigablePath path) { + assert path != null; + + if ( path.isRoot() ) { + return StringHelper.collapse( path.getFullPath() ); + } + else { + assert path.getParent() != null; + return StringHelper.collapse( path.getParent().getFullPath() ) + '.' + path.getLocalName(); + } + } + + public static String toLoggableString(NavigableRole role, Object key) { + if ( role == null ) { + return UNREFERENCED; + } + + return toLoggableString( toLoggableString( role ), key ); + } + + public static String toLoggableString(NavigablePath path, Object key) { + assert path != null; + return toLoggableString( toLoggableString( path ), key ); + } + + public static String toLoggableString(CollectionKey collectionKey) { + return toLoggableString( collectionKey.getRole(), collectionKey.getKey() ); + } + + public static String toLoggableString(EntityKey entityKey) { + return toLoggableString( StringHelper.collapse( entityKey.getEntityName() ), entityKey.getIdentifierValue() ); + } + + private static String toLoggableString(String roleOrPath, Object key) { + assert roleOrPath != null; + + StringBuilder buffer = new StringBuilder(); + + buffer.append( roleOrPath ); + buffer.append( '#' ); + + if ( key == null ) { + buffer.append( NULL ); + } + else { + buffer.append( key ); + } + + return buffer.toString(); + } + + public static String toLoggableString(PersistentCollection collectionInstance) { + if ( collectionInstance == null ) { + return NULL; + } + + return toLoggableString( + collectionInstance.getRole(), + collectionInstance.getKey() + ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java index e85e000931..c08303d9f5 100755 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java @@ -212,4 +212,10 @@ public final class CollectionHelper { public static boolean isEmpty(Object[] objects) { return objects == null || objects.length == 0; } + + public static Set setOf(T... values) { + final HashSet set = new HashSet<>( determineProperSizing( values.length ) ); + Collections.addAll( set, values ); + return set; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/RepresentationMode.java b/hibernate-core/src/main/java/org/hibernate/metamodel/RepresentationMode.java index 62270d7c21..77e06a258f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/RepresentationMode.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/RepresentationMode.java @@ -8,6 +8,8 @@ package org.hibernate.metamodel; import java.util.Locale; +import org.hibernate.EntityMode; + /** * Enumeration of the built-in ways that Hibernate can represent the * application's domain model. @@ -15,25 +17,33 @@ import java.util.Locale; * @author Steve Ebersole */ public enum RepresentationMode { - POJO( "pojo" ), - MAP( "map", "dynamic-map" ); + POJO( "pojo", EntityMode.POJO ), + MAP( "map", "dynamic-map", EntityMode.MAP ); private final String externalName; private final String alternativeExternalName; - RepresentationMode(String externalName) { - this ( externalName, null ); + private final EntityMode legacyEntityMode; + + RepresentationMode(String externalName, EntityMode legacyEntityMode) { + this ( externalName, null, legacyEntityMode ); } - RepresentationMode(String externalName, String alternativeExternalName) { + RepresentationMode(String externalName, String alternativeExternalName, EntityMode legacyEntityMode) { this.externalName = externalName; this.alternativeExternalName = alternativeExternalName; + this.legacyEntityMode = legacyEntityMode; } public String getExternalName() { return externalName; } + @Deprecated + public EntityMode getLegacyEntityMode() { + return legacyEntityMode; + } + public static RepresentationMode fromExternalName(String externalName) { if ( externalName == null ) { return POJO; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java index 9d9134c517..b296e5ffbb 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java @@ -43,6 +43,7 @@ import org.hibernate.metamodel.model.domain.internal.MappedSuperclassTypeImpl; import org.hibernate.metamodel.model.domain.internal.PluralAttributeBuilder; import org.hibernate.metamodel.model.domain.internal.SingularAttributeImpl; import org.hibernate.metamodel.spi.ManagedTypeRepresentationStrategy; +import org.hibernate.persister.entity.EntityPersister; import org.hibernate.property.access.internal.PropertyAccessMapImpl; import org.hibernate.property.access.spi.Getter; import org.hibernate.tuple.entity.EntityMetamodel; @@ -289,6 +290,24 @@ public class AttributeFactory { return getDeclarerEntityMetamodel( ownerType, context ); } + private static EntityPersister getDeclaringEntity( + AbstractIdentifiableType ownerType, + MetadataContext metadataContext) { + final Type.PersistenceType persistenceType = ownerType.getPersistenceType(); + if ( persistenceType == Type.PersistenceType.ENTITY ) { + return metadataContext.getMetamodel() + .getEntityDescriptor( ownerType.getTypeName() ); + } + else if ( persistenceType == Type.PersistenceType.MAPPED_SUPERCLASS ) { + PersistentClass persistentClass = + metadataContext.getPersistentClassHostingProperties( (MappedSuperclassTypeImpl) ownerType ); + return metadataContext.getMetamodel() + .findEntityDescriptor( persistentClass.getClassName() ); + } + else { + throw new AssertionFailure( "Cannot get the metamodel for PersistenceType: " + persistenceType ); + } + } private static EntityMetamodel getDeclarerEntityMetamodel( AbstractIdentifiableType ownerType, MetadataContext metadataContext) { @@ -609,7 +628,8 @@ public class AttributeFactory { else if ( Type.PersistenceType.ENTITY == persistenceType || Type.PersistenceType.MAPPED_SUPERCLASS == persistenceType ) { final AbstractIdentifiableType identifiableType = (AbstractIdentifiableType) ownerType; - final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType, metadataContext ); + final EntityPersister declaringEntityMapping = getDeclaringEntity( identifiableType, metadataContext ); + final EntityMetamodel entityMetamodel = declaringEntityMapping.getEntityMetamodel(); final String propertyName = property.getName(); final Integer index = entityMetamodel.getPropertyIndexOrNull( propertyName ); if ( index == null ) { @@ -617,7 +637,7 @@ public class AttributeFactory { return virtualIdentifierMemberResolver.resolveMember( attributeContext, metadataContext ); } else { - final Getter getter = entityMetamodel.getTuplizer().getGetter( index ); + final Getter getter = declaringEntityMapping.getRepresentationStrategy().resolvePropertyAccess( property ).getGetter(); return getter instanceof PropertyAccessMapImpl.GetterImpl ? new MapMember( propertyName, property.getType().getReturnedClass() ) : getter.getMember(); @@ -630,14 +650,17 @@ public class AttributeFactory { private final MemberResolver identifierMemberResolver = (attributeContext, metadataContext) -> { final AbstractIdentifiableType identifiableType = (AbstractIdentifiableType) attributeContext.getOwnerType(); - final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType ); + final EntityPersister declaringEntityMapping = getDeclaringEntity( identifiableType, metadataContext ); + final EntityMetamodel entityMetamodel = declaringEntityMapping.getEntityMetamodel(); + if ( !attributeContext.getPropertyMapping().getName() .equals( entityMetamodel.getIdentifierProperty().getName() ) ) { // this *should* indicate processing part of an IdClass... return virtualIdentifierMemberResolver.resolveMember( attributeContext, metadataContext ); } - final Getter getter = entityMetamodel.getTuplizer().getIdentifierGetter(); - if ( PropertyAccessMapImpl.GetterImpl.class.isInstance( getter ) ) { + + final Getter getter = declaringEntityMapping.getRepresentationStrategy().resolvePropertyAccess( attributeContext.getPropertyMapping() ).getGetter(); + if ( getter instanceof PropertyAccessMapImpl.GetterImpl ) { return new MapMember( entityMetamodel.getIdentifierProperty().getName(), entityMetamodel.getIdentifierProperty().getType().getReturnedClass() @@ -654,14 +677,15 @@ public class AttributeFactory { AttributeContext attributeContext, MetadataContext metadataContext) { final AbstractIdentifiableType identifiableType = (AbstractIdentifiableType) attributeContext.getOwnerType(); - final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType ); + final EntityPersister declaringEntityMapping = getDeclaringEntity( identifiableType, metadataContext ); + final EntityMetamodel entityMetamodel = declaringEntityMapping.getEntityMetamodel(); final String versionPropertyName = attributeContext.getPropertyMapping().getName(); if ( !versionPropertyName.equals( entityMetamodel.getVersionProperty().getName() ) ) { // this should never happen, but to be safe... throw new IllegalArgumentException( "Given property did not match declared version property" ); } - final Getter getter = entityMetamodel.getTuplizer().getVersionGetter(); + final Getter getter = declaringEntityMapping.getRepresentationStrategy().resolvePropertyAccess( attributeContext.getPropertyMapping() ).getGetter(); if ( PropertyAccessMapImpl.GetterImpl.class.isInstance( getter ) ) { return new MapMember( versionPropertyName, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/DynamicMapInstantiator.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/DynamicMapInstantiator.java index ad5426a5ee..b1e1441748 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/DynamicMapInstantiator.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/DynamicMapInstantiator.java @@ -12,6 +12,8 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; +import org.hibernate.EntityNameResolver; +import org.hibernate.HibernateException; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.mapping.Component; @@ -22,6 +24,17 @@ import org.hibernate.metamodel.spi.Instantiator; * @author Steve Ebersole */ public class DynamicMapInstantiator implements Instantiator { + public static final EntityNameResolver ENTITY_NAME_RESOLVER = entity -> { + if ( ! (entity instanceof Map) ) { + return null; + } + final String entityName = extractEmbeddedEntityName( (Map) entity ); + if ( entityName == null ) { + throw new HibernateException( "Could not determine type of dynamic map entity" ); + } + return entityName; + }; + public static final String KEY = "$type$"; private final String roleName; @@ -72,4 +85,42 @@ public class DynamicMapInstantiator implements Instantiator { return false; } } + + public static class BasicEntityNameResolver implements EntityNameResolver { + public static final BasicEntityNameResolver INSTANCE = new BasicEntityNameResolver(); + + @Override + public String resolveEntityName(Object entity) { + if ( ! (entity instanceof Map) ) { + return null; + } + final String entityName = extractEmbeddedEntityName( (Map) entity ); + if ( entityName == null ) { + throw new HibernateException( "Could not determine type of dynamic map entity" ); + } + return entityName; + } + + @Override + public boolean equals(Object obj) { + return obj != null && getClass().equals( obj.getClass() ); + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } + } + + public static String extractEmbeddedEntityName(Map entity) { + if ( entity == null ) { + return null; + } + final String entityName = (String) entity.get( KEY ); + if ( entityName == null ) { + throw new HibernateException( "Could not determine type of dynamic map entity" ); + } + return entityName; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardManagedTypeRepresentationResolver.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardManagedTypeRepresentationResolver.java index 252a8462a6..416339dc84 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardManagedTypeRepresentationResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardManagedTypeRepresentationResolver.java @@ -33,7 +33,7 @@ public class StandardManagedTypeRepresentationResolver implements ManagedTypeRep // RepresentationMode representation = bootDescriptor.getExplicitRepresentationMode(); RepresentationMode representation = null; if ( representation == null ) { - if ( runtimeDescriptor.getMappedClass() == null ) { + if ( bootDescriptor.getMappedClass() == null ) { representation = RepresentationMode.MAP; } else { @@ -42,7 +42,7 @@ public class StandardManagedTypeRepresentationResolver implements ManagedTypeRep } if ( representation == RepresentationMode.MAP ) { - return new StandardMapEntityRepresentationStrategy( bootDescriptor, runtimeDescriptor, creationContext ); + return new StandardMapEntityRepresentationStrategy( bootDescriptor, creationContext ); } else { // todo (6.0) : fix this @@ -51,7 +51,7 @@ public class StandardManagedTypeRepresentationResolver implements ManagedTypeRep // // instead, resolve ReflectionOptimizer once - here - and pass along to // StandardPojoRepresentationStrategy - return new StandardPojoEntityRepresentationStrategy( bootDescriptor, runtimeDescriptor, creationContext ); + return new StandardPojoEntityRepresentationStrategy( bootDescriptor, creationContext ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardMapEmbeddableRepresentationStrategy.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardMapEmbeddableRepresentationStrategy.java index fdaa6b3043..fb1fa98653 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardMapEmbeddableRepresentationStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardMapEmbeddableRepresentationStrategy.java @@ -6,6 +6,7 @@ */ package org.hibernate.metamodel.internal; +import org.hibernate.bytecode.spi.ReflectionOptimizer; import org.hibernate.mapping.Component; import org.hibernate.mapping.Property; import org.hibernate.metamodel.RepresentationMode; @@ -32,6 +33,11 @@ public class StandardMapEmbeddableRepresentationStrategy implements EmbeddableRe return RepresentationMode.MAP; } + @Override + public ReflectionOptimizer getReflectionOptimizer() { + return null; + } + @Override public PropertyAccess resolvePropertyAccess(Property bootAttributeDescriptor) { return PropertyAccessStrategyMapImpl.INSTANCE.buildPropertyAccess( diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardMapEntityRepresentationStrategy.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardMapEntityRepresentationStrategy.java index 76fb00afd2..b338af9dd2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardMapEntityRepresentationStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardMapEntityRepresentationStrategy.java @@ -6,31 +6,89 @@ */ package org.hibernate.metamodel.internal; -import org.hibernate.mapping.Component; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; + +import org.hibernate.EntityNameResolver; +import org.hibernate.HibernateException; +import org.hibernate.bytecode.spi.ReflectionOptimizer; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.metamodel.RepresentationMode; import org.hibernate.metamodel.spi.EntityRepresentationStrategy; import org.hibernate.metamodel.spi.Instantiator; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; -import org.hibernate.persister.entity.EntityPersister; import org.hibernate.property.access.internal.PropertyAccessStrategyMapImpl; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.proxy.ProxyFactory; +import org.hibernate.proxy.map.MapProxyFactory; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Steve Ebersole */ public class StandardMapEntityRepresentationStrategy implements EntityRepresentationStrategy { + private static final CoreMessageLogger LOG = CoreLogging.messageLogger( StandardMapEntityRepresentationStrategy.class ); + + private final JavaTypeDescriptor mapJtd; + private final ProxyFactory proxyFactory; private final DynamicMapInstantiator instantiator; + private final Map propertyAccessMap = new ConcurrentHashMap<>(); + public StandardMapEntityRepresentationStrategy( - PersistentClass bootDescriptor, - EntityPersister runtimeDescriptor, + PersistentClass bootType, RuntimeModelCreationContext creationContext) { - this.proxyFactory = null; - this.instantiator = new DynamicMapInstantiator( bootDescriptor ); + this.mapJtd = creationContext.getTypeConfiguration() + .getJavaTypeDescriptorRegistry() + .getDescriptor( Map.class ); + + this.proxyFactory = createProxyFactory( bootType ); + this.instantiator = new DynamicMapInstantiator( bootType ); + + //noinspection unchecked + final Iterator itr = bootType.getPropertyClosureIterator(); + int i = 0; + while ( itr.hasNext() ) { + //TODO: redesign how PropertyAccessors are acquired... + final Property property = itr.next(); + final PropertyAccess propertyAccess = PropertyAccessStrategyMapImpl.INSTANCE.buildPropertyAccess( + null, + property.getName() + ); + + propertyAccessMap.put( property.getName(), propertyAccess ); + + i++; + } + + createProxyFactory( bootType ); + } + + private static ProxyFactory createProxyFactory(PersistentClass bootType) { + try { + ProxyFactory proxyFactory = new MapProxyFactory(); + + proxyFactory.postInstantiate( + bootType.getEntityName(), + null, + null, + null, + null, + null + ); + + return proxyFactory; + } + catch (HibernateException he) { + LOG.unableToCreateProxyFactory( bootType.getEntityName(), he ); + return null; + } } @Override @@ -38,6 +96,11 @@ public class StandardMapEntityRepresentationStrategy implements EntityRepresenta return RepresentationMode.MAP; } + @Override + public ReflectionOptimizer getReflectionOptimizer() { + return null; + } + @Override public PropertyAccess resolvePropertyAccess(Property bootAttributeDescriptor) { return PropertyAccessStrategyMapImpl.INSTANCE.buildPropertyAccess( @@ -47,13 +110,27 @@ public class StandardMapEntityRepresentationStrategy implements EntityRepresenta } @Override - public Instantiator getInstantiator() { - //noinspection unchecked - return (Instantiator) instantiator; + public Instantiator getInstantiator() { + return instantiator; } @Override public ProxyFactory getProxyFactory() { return proxyFactory; } + + @Override + public JavaTypeDescriptor getMappedJavaTypeDescriptor() { + return mapJtd; + } + + @Override + public JavaTypeDescriptor getProxyJavaTypeDescriptor() { + return null; + } + + @Override + public void visitEntityNameResolvers(Consumer consumer) { + consumer.accept( DynamicMapInstantiator.ENTITY_NAME_RESOLVER ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardPojoEmbeddableRepresentationStrategy.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardPojoEmbeddableRepresentationStrategy.java index 5d46925c66..1c1bdd30ce 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardPojoEmbeddableRepresentationStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardPojoEmbeddableRepresentationStrategy.java @@ -18,7 +18,6 @@ import org.hibernate.mapping.Component; import org.hibernate.mapping.IndexBackref; import org.hibernate.mapping.Property; import org.hibernate.metamodel.RepresentationMode; -import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy; import org.hibernate.metamodel.spi.Instantiator; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; @@ -30,11 +29,10 @@ import org.hibernate.property.access.spi.PropertyAccessStrategy; /** * @author Steve Ebersole */ -public class StandardPojoEmbeddableRepresentationStrategy - extends AbstractEmbeddableRepresentationStrategy - implements EmbeddableRepresentationStrategy { +public class StandardPojoEmbeddableRepresentationStrategy extends AbstractEmbeddableRepresentationStrategy { private final StrategySelector strategySelector; + private final ReflectionOptimizer reflectionOptimizer; private final Instantiator instantiator; public StandardPojoEmbeddableRepresentationStrategy( @@ -54,7 +52,7 @@ public class StandardPojoEmbeddableRepresentationStrategy .getServiceRegistry() .getService( StrategySelector.class ); - final ReflectionOptimizer reflectionOptimizer = buildReflectionOptimizer( bootDescriptor, creationContext ); + this.reflectionOptimizer = buildReflectionOptimizer( bootDescriptor, creationContext ); if ( reflectionOptimizer != null && reflectionOptimizer.getInstantiationOptimizer() != null ) { this.instantiator = new OptimizedPojoInstantiatorImpl<>( getEmbeddableJavaTypeDescriptor(), reflectionOptimizer ); @@ -64,6 +62,11 @@ public class StandardPojoEmbeddableRepresentationStrategy } } + @Override + public ReflectionOptimizer getReflectionOptimizer() { + return reflectionOptimizer; + } + @Override protected PropertyAccess buildPropertyAccess(Property bootAttributeDescriptor) { PropertyAccessStrategy strategy = null; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardPojoEntityRepresentationStrategy.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardPojoEntityRepresentationStrategy.java index 56bde789e9..fc3a2c6bc1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardPojoEntityRepresentationStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/StandardPojoEntityRepresentationStrategy.java @@ -6,73 +6,282 @@ */ package org.hibernate.metamodel.internal; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import org.hibernate.HibernateException; +import org.hibernate.MappingException; import org.hibernate.boot.registry.selector.spi.StrategySelector; +import org.hibernate.bytecode.spi.BytecodeProvider; +import org.hibernate.bytecode.spi.ReflectionOptimizer; +import org.hibernate.cfg.Environment; +import org.hibernate.classic.Lifecycle; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.StringHelper; import org.hibernate.mapping.Backref; import org.hibernate.mapping.IndexBackref; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; +import org.hibernate.mapping.Subclass; import org.hibernate.metamodel.RepresentationMode; import org.hibernate.metamodel.spi.EntityRepresentationStrategy; import org.hibernate.metamodel.spi.Instantiator; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; -import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.property.access.internal.PropertyAccessBasicImpl; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; +import org.hibernate.property.access.internal.PropertyAccessStrategyEmbeddedImpl; import org.hibernate.property.access.internal.PropertyAccessStrategyIndexBackRefImpl; import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccessStrategy; +import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.ProxyFactory; +import org.hibernate.type.CompositeType; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry; /** * @author Steve Ebersole */ public class StandardPojoEntityRepresentationStrategy implements EntityRepresentationStrategy { - private final EntityPersister runtimeDescriptor; - private final StrategySelector strategySelector; + private static final CoreMessageLogger LOG = CoreLogging.messageLogger( StandardPojoEntityRepresentationStrategy.class ); + private final JavaTypeDescriptor mappedJtd; + private final JavaTypeDescriptor proxyJtd; + + private final boolean isBytecodeEnhanced; + private final boolean lifecycleImplementor; + + private final ReflectionOptimizer reflectionOptimizer; private final ProxyFactory proxyFactory; private final Instantiator instantiator; + private final StrategySelector strategySelector; + + private final String identifierPropertyName; + private final PropertyAccess identifierPropertyAccess; + private final Map propertyAccessMap = new ConcurrentHashMap<>(); + public StandardPojoEntityRepresentationStrategy( PersistentClass bootDescriptor, - EntityPersister runtimeDescriptor, RuntimeModelCreationContext creationContext) { - this.runtimeDescriptor = runtimeDescriptor; + final SessionFactoryImplementor sessionFactory = creationContext.getSessionFactory(); + final JavaTypeDescriptorRegistry jtdRegistry = sessionFactory.getTypeConfiguration() + .getJavaTypeDescriptorRegistry(); - this.strategySelector = creationContext.getSessionFactory() - .getServiceRegistry() - .getService( StrategySelector.class ); + final Class mappedJavaType = bootDescriptor.getMappedClass(); + this.mappedJtd = jtdRegistry.getDescriptor( mappedJavaType ); - this.proxyFactory = null; - this.instantiator = null; + final Class proxyJavaType = bootDescriptor.getProxyInterface(); + this.proxyJtd = jtdRegistry.getDescriptor( proxyJavaType ); + + this.lifecycleImplementor = Lifecycle.class.isAssignableFrom( mappedJavaType ); + this.isBytecodeEnhanced = PersistentAttributeInterceptable.class.isAssignableFrom( mappedJavaType ); + + + final Property identifierProperty = bootDescriptor.getIdentifierProperty(); + if ( identifierProperty == null ) { + identifierPropertyName = null; + identifierPropertyAccess = PropertyAccessStrategyEmbeddedImpl.INSTANCE.buildPropertyAccess( + proxyJtd != null ? proxyJtd.getJavaType() : mappedJtd.getJavaType(), + "id" + ); + } + else { + identifierPropertyName = identifierProperty.getName(); + identifierPropertyAccess = makePropertyAccess( identifierProperty ); + } + +// final BytecodeProvider bytecodeProvider = creationContext.getBootstrapContext().getBytecodeProvider(); + final BytecodeProvider bytecodeProvider = Environment.getBytecodeProvider(); + + this.proxyFactory = createProxyFactory( bootDescriptor, bytecodeProvider, creationContext ); + + this.reflectionOptimizer = resolveReflectionOptimizer( bootDescriptor, bytecodeProvider ); + + if ( reflectionOptimizer != null && reflectionOptimizer.getInstantiationOptimizer() != null ) { + this.instantiator = new OptimizedPojoInstantiatorImpl<>( mappedJtd, reflectionOptimizer ); + } + else { + this.instantiator = new PojoInstantiatorImpl<>( mappedJtd ); + } + + this.strategySelector = sessionFactory.getServiceRegistry().getService( StrategySelector.class ); } - @Override - public RepresentationMode getMode() { - return RepresentationMode.POJO; + private PropertyAccess resolveIdentifierPropertyAccess(PersistentClass bootDescriptor) { + final Property identifierProperty = bootDescriptor.getIdentifierProperty(); + + if ( identifierProperty == null ) { + return PropertyAccessStrategyEmbeddedImpl.INSTANCE.buildPropertyAccess( + proxyJtd != null ? proxyJtd.getJavaType() : mappedJtd.getJavaType(), + "id" + ); + } + + return makePropertyAccess( identifierProperty ); } - @Override - public Instantiator getInstantiator() { + private ProxyFactory createProxyFactory( + PersistentClass bootDescriptor, + BytecodeProvider bytecodeProvider, + RuntimeModelCreationContext creationContext) { + /* + * We need to preserve the order of the interfaces they were put into the set, since javassist will choose the + * first one's class-loader to construct the proxy class with. This is also the reason why HibernateProxy.class + * should be the last one in the order (on JBossAS7 its class-loader will be org.hibernate module's class- + * loader, which will not see the classes inside deployed apps. See HHH-3078 + */ + final Set proxyInterfaces = new java.util.LinkedHashSet<>(); + + final Class mappedClass = mappedJtd.getJavaType(); + final Class proxyInterface = proxyJtd.getJavaType(); + + if ( proxyInterface != null && ! mappedClass.equals( proxyInterface ) ) { + if ( ! proxyInterface.isInterface() ) { + throw new MappingException( + "proxy must be either an interface, or the class itself: " + bootDescriptor.getEntityName() + ); + } + proxyInterfaces.add( proxyInterface ); + } + + if ( mappedClass.isInterface() ) { + proxyInterfaces.add( mappedClass ); + } + //noinspection unchecked - return instantiator; + final Iterator subclasses = bootDescriptor.getSubclassIterator(); + while ( subclasses.hasNext() ) { + final Subclass subclass = subclasses.next(); + final Class subclassProxy = subclass.getProxyInterface(); + final Class subclassClass = subclass.getMappedClass(); + if ( subclassProxy != null && !subclassClass.equals( subclassProxy ) ) { + if ( !subclassProxy.isInterface() ) { + throw new MappingException( + "proxy must be either an interface, or the class itself: " + subclass.getEntityName() + ); + } + proxyInterfaces.add( subclassProxy ); + } + } + + proxyInterfaces.add( HibernateProxy.class ); + + Iterator properties = bootDescriptor.getPropertyIterator(); + Class clazz = bootDescriptor.getMappedClass(); + while ( properties.hasNext() ) { + Property property = (Property) properties.next(); + Method method = property.getGetter( clazz ).getMethod(); + if ( method != null && Modifier.isFinal( method.getModifiers() ) ) { + LOG.gettersOfLazyClassesCannotBeFinal( bootDescriptor.getEntityName(), property.getName() ); + } + method = property.getSetter( clazz ).getMethod(); + if ( method != null && Modifier.isFinal( method.getModifiers() ) ) { + LOG.settersOfLazyClassesCannotBeFinal( bootDescriptor.getEntityName(), property.getName() ); + } + } + + final Method idGetterMethod = identifierPropertyAccess == null ? null : identifierPropertyAccess.getGetter().getMethod(); + final Method idSetterMethod = identifierPropertyAccess == null ? null : identifierPropertyAccess.getSetter().getMethod(); + + final Method proxyGetIdentifierMethod = idGetterMethod == null || proxyInterface == null + ? null + : ReflectHelper.getMethod( proxyInterface, idGetterMethod ); + final Method proxySetIdentifierMethod = idSetterMethod == null || proxyInterface == null + ? null + : ReflectHelper.getMethod( proxyInterface, idSetterMethod ); + + ProxyFactory pf = bytecodeProvider.getProxyFactoryFactory().buildProxyFactory( creationContext.getSessionFactory() ); + try { + pf.postInstantiate( + bootDescriptor.getEntityName(), + mappedClass, + proxyInterfaces, + proxyGetIdentifierMethod, + proxySetIdentifierMethod, + bootDescriptor.hasEmbeddedIdentifier() ? + (CompositeType) bootDescriptor.getIdentifier().getType() : + null + ); + + return pf; + } + catch (HibernateException he) { + LOG.unableToCreateProxyFactory( bootDescriptor.getEntityName(), he ); + return null; + } } - @Override - public ProxyFactory getProxyFactory() { - return proxyFactory; + private ReflectionOptimizer resolveReflectionOptimizer( + PersistentClass bootType, + BytecodeProvider bytecodeProvider) { + final Class javaTypeToReflect; + if ( proxyFactory != null ) { + assert proxyJtd != null; + javaTypeToReflect = proxyJtd.getJavaType(); + } + else { + javaTypeToReflect = mappedJtd.getJavaType(); + } + + final List getterNames = new ArrayList<>(); + final List setterNames = new ArrayList<>(); + final List getterTypes = new ArrayList<>(); + + boolean foundCustomAccessor = false; + + //noinspection unchecked + final Iterator itr = bootType.getPropertyClosureIterator(); + int i = 0; + while ( itr.hasNext() ) { + //TODO: redesign how PropertyAccessors are acquired... + final Property property = itr.next(); + final PropertyAccess propertyAccess = makePropertyAccess( property ); + + propertyAccessMap.put( property.getName(), propertyAccess ); + + if ( ! (propertyAccess instanceof PropertyAccessBasicImpl) ) { + foundCustomAccessor = true; + } + + getterNames.add( propertyAccess.getGetter().getMethodName() ); + getterTypes.add( propertyAccess.getGetter().getReturnType() ); + + setterNames.add( propertyAccess.getSetter().getMethodName() ); + + i++; + } + + if ( foundCustomAccessor || ! Environment.useReflectionOptimizer() ) { + return null; + } + + return bytecodeProvider.getReflectionOptimizer( + javaTypeToReflect, + getterNames.toArray( new String[0] ), + setterNames.toArray( new String[0] ), + getterTypes.toArray( new Class[0] ) + ); } - @Override - public PropertyAccess resolvePropertyAccess(Property bootAttributeDescriptor) { + private PropertyAccess makePropertyAccess(Property bootAttributeDescriptor) { PropertyAccessStrategy strategy = null; final String propertyAccessorName = bootAttributeDescriptor.getPropertyAccessorName(); - final BuiltInPropertyAccessStrategies namedStrategy = BuiltInPropertyAccessStrategies.interpret( propertyAccessorName ); + final BuiltInPropertyAccessStrategies namedStrategy = BuiltInPropertyAccessStrategies.interpret( + propertyAccessorName ); if ( namedStrategy != null ) { strategy = namedStrategy.getStrategy(); @@ -108,12 +317,61 @@ public class StandardPojoEntityRepresentationStrategy implements EntityRepresent String.format( Locale.ROOT, "Could not resolve PropertyAccess for attribute `%s#%s`", - runtimeDescriptor.getMappedClass().getName(), + mappedJtd.getJavaType().getName(), bootAttributeDescriptor.getName() ) ); } - return strategy.buildPropertyAccess( runtimeDescriptor.getMappedClass(), bootAttributeDescriptor.getName() ); + return strategy.buildPropertyAccess( mappedJtd.getJavaType(), bootAttributeDescriptor.getName() ); + } + + @Override + public RepresentationMode getMode() { + return RepresentationMode.POJO; + } + + @Override + public ReflectionOptimizer getReflectionOptimizer() { + return reflectionOptimizer; + } + + @Override + public Instantiator getInstantiator() { + return instantiator; + } + + @Override + public ProxyFactory getProxyFactory() { + return proxyFactory; + } + + @Override + public boolean isLifecycleImplementor() { + return lifecycleImplementor; + } + + @Override + public boolean isBytecodeEnhanced() { + return isBytecodeEnhanced; + } + + @Override + public JavaTypeDescriptor getMappedJavaTypeDescriptor() { + return mappedJtd; + } + + @Override + public JavaTypeDescriptor getProxyJavaTypeDescriptor() { + return proxyJtd; + } + + @Override + public PropertyAccess resolvePropertyAccess(Property bootAttributeDescriptor) { + if ( bootAttributeDescriptor.getName().equals( identifierPropertyName ) ) { + return identifierPropertyAccess; + } + + return propertyAccessMap.get( bootAttributeDescriptor.getName() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java index 994dbc19f9..be6cf3e4f7 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java @@ -13,4 +13,16 @@ package org.hibernate.metamodel.mapping; */ public interface AttributeMapping extends ModelPart, ValueMapping { String getAttributeName(); + + AttributeMetadataAccess getAttributeMetadataAccess(); + + ManagedMappingType getDeclaringType(); + + default boolean isDeclaredOnTypeOrSuperType(ManagedMappingType targetType) { + if ( getDeclaringType() instanceof EntityMappingType ) { + return ( (EntityMappingType) getDeclaringType() ).isTypeOrSuperType( targetType ); + } + + return false; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMetadata.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMetadata.java new file mode 100644 index 0000000000..b40a6dda56 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMetadata.java @@ -0,0 +1,38 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.metamodel.mapping; + +import org.hibernate.engine.spi.CascadeStyle; +import org.hibernate.engine.spi.CascadeStyles; +import org.hibernate.property.access.spi.PropertyAccess; +import org.hibernate.type.descriptor.java.MutabilityPlan; + +/** + * @author Steve Ebersole + */ +public interface AttributeMetadata { + PropertyAccess getPropertyAccess(); + + MutabilityPlan getMutabilityPlan(); + + boolean isNullable(); + + boolean isInsertable(); + + boolean isUpdatable(); + + boolean isIncludedInDirtyChecking(); + + boolean isIncludedInOptimisticLocking(); + + default CascadeStyle getCascadeStyle() { + // todo (6.0) - implement in each subclass. + // For now return a default NONE value for all contributors since this isn't + // to be supported as a part of Alpha1. + return CascadeStyles.NONE; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMetadataAccess.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMetadataAccess.java new file mode 100644 index 0000000000..1ae1931a68 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMetadataAccess.java @@ -0,0 +1,14 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.metamodel.mapping; + +/** + * @author Steve Ebersole + */ +public interface AttributeMetadataAccess { + AttributeMetadata resolveAttributeMetadata(EntityMappingType entityMappingType); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java index 8b5e331b2f..9dc43969da 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java @@ -6,9 +6,13 @@ */ package org.hibernate.metamodel.mapping; +import org.hibernate.property.access.spi.PropertyAccess; + /** * @author Steve Ebersole */ public interface EntityIdentifierMapping extends ValueMapping, ModelPart { String ROLE_LOCAL_NAME = "{id}"; + + PropertyAccess getPropertyAccess(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java index 516ef8b342..c02ca71a7b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java @@ -25,44 +25,86 @@ public interface EntityMappingType extends ManagedMappingType { */ EntityPersister getEntityPersister(); - EntityIdentifierMapping getIdentifierMapping(); - - EntityVersionMapping getVersionMapping(); - default String getEntityName() { return getEntityPersister().getEntityName(); } + EntityIdentifierMapping getIdentifierMapping(); + + EntityVersionMapping getVersionMapping(); + + NaturalIdMapping getNaturalIdMapping(); + + @Override + default boolean isTypeOrSuperType(ManagedMappingType targetType) { + if ( targetType instanceof EntityMappingType ) { + return isTypeOrSuperType( (EntityMappingType) targetType ); + } + + return false; + } + + default boolean isTypeOrSuperType(EntityMappingType targetType) { + return targetType == this; + } + + /** + * Visit the mappings, but limited to just attributes defined + * in the targetType or its super-type(s) if any. + * + * @apiNote Passing {@code null} indicates that subclasses should be included. This + * matches legacy non-TREAT behavior and meets the need for EntityGraph processing + */ + default void visitAttributeMappings(Consumer action, EntityMappingType targetType) { + getAttributeMappings().forEach( action ); + } + + /** + * Walk this type's attributes as well as its sub-type's + */ + default void visitSubTypeAttributeMappings(Consumer action) { + // by default do nothing + } + + /** + * Walk this type's attributes as well as its super-type's + */ + default void visitSuperTypeAttributeMappings(Consumer action) { + // by default do nothing + } + + + @Override + default void visitAttributeMappings(Consumer action) { + visitAttributeMappings( action, null ); + } + + /** + * Visit the mappings, but limited to just attributes defined + * in the targetType or its super-type(s) if any. + * + * @apiNote Passing {@code null} indicates that subclasses should be included. This + * matches legacy non-TREAT behavior and meets the need for EntityGraph processing + */ + default void visitStateArrayContributors(Consumer mappingConsumer, EntityMappingType targetType) { + visitAttributeMappings( + modelPart -> { + if ( modelPart instanceof StateArrayContributorMapping ) { + if ( targetType == null + || ( (StateArrayContributorMapping) modelPart ).isDeclaredOnTypeOrSuperType( targetType ) ) { + mappingConsumer.accept( ( (StateArrayContributorMapping) modelPart ) ); + } + } + }, + targetType + ); + } + + @Override + default void visitStateArrayContributors(Consumer mappingConsumer) { + visitStateArrayContributors( mappingConsumer, null ); + } + // todo (6.0) : not sure we actually need this distinction at the mapping model level... -// /** -// * For an entity, this form allows for Hibernate's "implicit treat" support - -// * meaning it should find a sub-part whether defined on the entity, its -// * super-type or even one of its sub-types. -// * -// * @see #findSubPartStrictly -// */ -// @Override -// ModelPart findSubPart(String name); -// -// /** -// * Same purpose as {@link #findSubPart} except that this form limits -// * the search to just this type and its super types. -// */ -// ModelPart findSubPartStrictly(String name); -// -// /** -// * Like {@link #findSubPart}, this form visits all parts defined on the -// * entity, its super-types and its sub-types. -// * -// * @see #findSubPartStrictly -// */ -// @Override -// void visitSubParts(Consumer consumer); -// -// /** -// * Same purpose as {@link #visitSubParts} except that this form limits -// * the visitation to just this type and its super types. -// */ -// void visitSubPartsStrictly(Consumer action); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityValuedModelPart.java new file mode 100644 index 0000000000..a041fbc7a0 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityValuedModelPart.java @@ -0,0 +1,90 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.metamodel.mapping; + +import java.util.function.Consumer; + +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.query.NavigablePath; +import org.hibernate.sql.ast.Clause; +import org.hibernate.sql.ast.tree.from.TableGroup; +import org.hibernate.sql.results.spi.DomainResult; +import org.hibernate.sql.results.spi.DomainResultCreationState; +import org.hibernate.sql.results.spi.FetchableContainer; +import org.hibernate.type.spi.TypeConfiguration; + +/** + * @author Steve Ebersole + */ +public interface EntityValuedModelPart extends FetchableContainer { + EntityMappingType getEntityMappingType(); + + @Override + default ModelPart findSubPart(String name) { + return getEntityMappingType().findSubPart( name ); + } + + @Override + default void visitSubParts(Consumer consumer) { + getEntityMappingType().visitSubParts( consumer ); + } + + @Override + default DomainResult createDomainResult( + NavigablePath navigablePath, + TableGroup tableGroup, + String resultVariable, + DomainResultCreationState creationState) { + // todo (6.0) : this is really only valid for root entity returns, not really many-to-ones, etc.. + return getEntityMappingType().createDomainResult( navigablePath, tableGroup, resultVariable, creationState ); + } + + @Override + default void applySqlSelections( + NavigablePath navigablePath, + TableGroup tableGroup, + DomainResultCreationState creationState) { + // todo (6.0) : this is really only valid for root entity returns, not really many-to-ones, etc.. + getEntityMappingType().applySqlSelections( navigablePath, tableGroup, creationState ); + } + + @Override + default int getJdbcTypeCount(TypeConfiguration typeConfiguration) { + return getEntityMappingType().getJdbcTypeCount( typeConfiguration ); + } + + @Override + default void visitJdbcTypes( + Consumer action, + Clause clause, + TypeConfiguration typeConfiguration) { + getEntityMappingType().getJdbcTypeCount( typeConfiguration ); + } + + @Override + default Object disassemble(Object value, SharedSessionContractImplementor session) { + return getEntityMappingType().disassemble( value, session ); + } + + @Override + default void visitDisassembledJdbcValues( + Object value, + Clause clause, + JdbcValuesConsumer valuesConsumer, + SharedSessionContractImplementor session) { + getEntityMappingType().visitDisassembledJdbcValues( value, clause, valuesConsumer, session ); + } + + @Override + default void visitJdbcValues( + Object value, + Clause clause, + JdbcValuesConsumer valuesConsumer, + SharedSessionContractImplementor session) { + getEntityMappingType().visitJdbcValues( value, clause, valuesConsumer, session ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityVersionMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityVersionMapping.java index 8be5beb147..3241838729 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityVersionMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityVersionMapping.java @@ -9,5 +9,6 @@ package org.hibernate.metamodel.mapping; /** * @author Steve Ebersole */ -public interface EntityVersionMapping extends SingularAttributeMapping, BasicValuedModelPart { +public interface EntityVersionMapping extends SingularAttributeMapping, + StateArrayContributorMapping, BasicValuedModelPart { } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java index 2e422e3b6c..60bf83840f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java @@ -9,15 +9,36 @@ package org.hibernate.metamodel.mapping; import java.util.Collection; import java.util.function.Consumer; +import org.hibernate.sql.results.spi.FetchableContainer; + /** * Commonality in regards to the mapping type system for all managed domain * types - entity types, mapped-superclass types, composite types, etc * * @author Steve Ebersole */ -public interface ManagedMappingType extends MappingType, ModelPartContainer { +public interface ManagedMappingType extends MappingType, FetchableContainer { Collection getAttributeMappings(); + + /** + * @todo (6.0) : consider dropping this in favor of a form passing the ManagedMappingType + * which indicates the type to limit the attribute search to (the type and its super-type) + */ void visitAttributeMappings(Consumer action); + /** + * @todo (6.0) : consider dropping this in favor of a form passing the ManagedMappingType + * which indicates the type to limit the attribute search to (the type and its super-type) + */ + default void visitStateArrayContributors(Consumer mappingConsumer) { + visitAttributeMappings( + modelPart -> { + if ( modelPart instanceof StateArrayContributorMapping ) { + mappingConsumer.accept( ( (StateArrayContributorMapping) modelPart ) ); + } + } + ); + } + boolean isTypeOrSuperType(ManagedMappingType targetType); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/MappingModelCreationContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/MappingModelCreationContext.java index d0dc2ead80..fc0bdaef92 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/MappingModelCreationContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/MappingModelCreationContext.java @@ -6,6 +6,7 @@ */ package org.hibernate.metamodel.mapping; +import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.spi.DomainMetamodel; @@ -22,4 +23,6 @@ public interface MappingModelCreationContext { DomainMetamodel getDomainModel(); MetadataImplementor getBootModel(); + + BootstrapContext getBootstrapContext(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/NaturalIdMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/NaturalIdMapping.java new file mode 100644 index 0000000000..e2aeda555f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/NaturalIdMapping.java @@ -0,0 +1,13 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.metamodel.mapping; + +/** + * @author Steve Ebersole + */ +public interface NaturalIdMapping extends SingularAttributeMapping, StateArrayContributorMapping { +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java index 8705a2509c..27e53b5283 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java @@ -11,7 +11,7 @@ import org.hibernate.persister.collection.CollectionPersister; /** * @author Steve Ebersole */ -public interface PluralAttributeMapping extends AttributeMapping { +public interface PluralAttributeMapping extends AttributeMapping, StateArrayContributorMapping { CollectionPersister getCollectionDescriptor(); ModelPart getValueDescriptor(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/Queryable.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/Queryable.java new file mode 100644 index 0000000000..77ef799071 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/Queryable.java @@ -0,0 +1,41 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.metamodel.mapping; + +import java.util.function.Consumer; + +import org.hibernate.boot.spi.SessionFactoryOptions; + +/** + * Defines a mapping model contract for things that can be queried in the HQL, + * Criteria, etc sense. Generally this + * + * todo (6.0) : consider whether collections are Queryable + * - depends how we envision Queryable being used. E.g. does it make + * sense to allow calls like `findSubPart( "index" )` or `findSubPart( "element" )`? + * + * @author Steve Ebersole + */ +public interface Queryable extends ModelPart { + /** + * For an entity, this form allows for Hibernate's "implicit treat" support - + * meaning it should find a sub-part whether defined on the entity, its + * super-type or even one of its sub-types. + * + * @implNote Logically the implementation should consider + * {@link org.hibernate.jpa.spi.JpaCompliance}. Not passed in because it + * is expected that implementors have access to the SessionFactory to access + * the JpaCompliance. See {@link SessionFactoryOptions#getJpaCompliance} + */ + ModelPart findSubPart(String name, EntityMappingType treatTargetType); + + /** + * Like {@link #findSubPart}, this form visits all parts defined on the + * entity, its super-types and its sub-types. + */ + void visitSubParts(Consumer consumer, EntityMappingType treatTargetType); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SingularAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SingularAttributeMapping.java index 771d57df61..6d31507c37 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SingularAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SingularAttributeMapping.java @@ -9,5 +9,5 @@ package org.hibernate.metamodel.mapping; /** * @author Steve Ebersole */ -public interface SingularAttributeMapping extends AttributeMapping { +public interface SingularAttributeMapping extends AttributeMapping, StateArrayContributorMapping { } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/StateArrayContributorMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/StateArrayContributorMapping.java new file mode 100644 index 0000000000..35a0d33a02 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/StateArrayContributorMapping.java @@ -0,0 +1,22 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.metamodel.mapping; + +import org.hibernate.sql.results.spi.Fetchable; + +/** + * @author Steve Ebersole + */ +public interface StateArrayContributorMapping extends AttributeMapping, Fetchable { + /** + * The attribute's position within the container's state array + */ + int getStateArrayPosition(); + + @Override + StateArrayContributorMetadataAccess getAttributeMetadataAccess(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/StateArrayContributorMetadata.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/StateArrayContributorMetadata.java new file mode 100644 index 0000000000..8c3f73d952 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/StateArrayContributorMetadata.java @@ -0,0 +1,13 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.metamodel.mapping; + +/** + * @author Steve Ebersole + */ +public interface StateArrayContributorMetadata extends AttributeMetadata { +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/StateArrayContributorMetadataAccess.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/StateArrayContributorMetadataAccess.java new file mode 100644 index 0000000000..6904c9332e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/StateArrayContributorMetadataAccess.java @@ -0,0 +1,15 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.metamodel.mapping; + +/** + * @author Steve Ebersole + */ +public interface StateArrayContributorMetadataAccess extends AttributeMetadataAccess { + @Override + StateArrayContributorMetadata resolveAttributeMetadata(EntityMappingType entityMappingType); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractAttributeMapping.java index 77d62edd23..4c282b67a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractAttributeMapping.java @@ -7,6 +7,7 @@ package org.hibernate.metamodel.mapping.internal; import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.metamodel.mapping.ManagedMappingType; import org.hibernate.metamodel.mapping.MappingType; /** @@ -16,10 +17,13 @@ public abstract class AbstractAttributeMapping implements AttributeMapping { private final String name; private final MappingType type; + private final ManagedMappingType declaringType; - public AbstractAttributeMapping(String name, MappingType type) { + @SuppressWarnings("WeakerAccess") + public AbstractAttributeMapping(String name, MappingType type, ManagedMappingType declaringType) { this.name = name; this.type = type; + this.declaringType = declaringType; } @Override @@ -31,4 +35,9 @@ public abstract class AbstractAttributeMapping implements AttributeMapping { public MappingType getMappedTypeDescriptor() { return type; } + + @Override + public ManagedMappingType getDeclaringType() { + return declaringType; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractManagedMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractManagedMappingType.java index 6377f8ff21..98bac3c649 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractManagedMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractManagedMappingType.java @@ -61,4 +61,10 @@ public class AbstractManagedMappingType implements ManagedMappingType { ); } } + + @Override + public boolean isTypeOrSuperType(ManagedMappingType targetType) { + // todo (6.0) : need to think through what this ought to indicate (if we allow it at all) + return targetType == this; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractSingularAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractSingularAttributeMapping.java index a449fdb82c..a27d84ebf8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractSingularAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractSingularAttributeMapping.java @@ -6,20 +6,36 @@ */ package org.hibernate.metamodel.mapping.internal; +import org.hibernate.LockMode; import org.hibernate.NotYetImplementedFor6Exception; +import org.hibernate.engine.FetchStrategy; +import org.hibernate.engine.FetchTiming; +import org.hibernate.metamodel.mapping.ManagedMappingType; import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.metamodel.mapping.SingularAttributeMapping; +import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess; import org.hibernate.query.NavigablePath; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.spi.DomainResult; import org.hibernate.sql.results.spi.DomainResultCreationState; +import org.hibernate.sql.results.spi.Fetch; +import org.hibernate.sql.results.spi.FetchParent; /** * @author Steve Ebersole */ -public class AbstractSingularAttributeMapping extends AbstractAttributeMapping implements SingularAttributeMapping { - public AbstractSingularAttributeMapping(String name, MappingType type) { - super( name, type ); +public class AbstractSingularAttributeMapping + extends AbstractStateArrayContributorMapping + implements SingularAttributeMapping { + + public AbstractSingularAttributeMapping( + String name, + int stateArrayPosition, + StateArrayContributorMetadataAccess attributeMetadataAccess, + FetchStrategy mappedFetchStrategy, + MappingType type, + ManagedMappingType declaringType) { + super( name, type, attributeMetadataAccess, mappedFetchStrategy, stateArrayPosition, declaringType ); } @Override @@ -30,4 +46,15 @@ public class AbstractSingularAttributeMapping extends AbstractAttributeMapping i DomainResultCreationState creationState) { throw new NotYetImplementedFor6Exception( getClass() ); } + + @Override + public Fetch generateFetch( + FetchParent fetchParent, + FetchTiming fetchTiming, + boolean selected, + LockMode lockMode, + String resultVariable, + DomainResultCreationState creationState) { + throw new NotYetImplementedFor6Exception( getClass() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractStateArrayContributorMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractStateArrayContributorMapping.java new file mode 100644 index 0000000000..4f02f94377 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractStateArrayContributorMapping.java @@ -0,0 +1,59 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.metamodel.mapping.internal; + +import org.hibernate.engine.FetchStrategy; +import org.hibernate.metamodel.mapping.ManagedMappingType; +import org.hibernate.metamodel.mapping.MappingType; +import org.hibernate.metamodel.mapping.StateArrayContributorMapping; +import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractStateArrayContributorMapping + extends AbstractAttributeMapping + implements StateArrayContributorMapping { + + private final StateArrayContributorMetadataAccess attributeMetadataAccess; + private final int stateArrayPosition; + private final FetchStrategy mappedFetchStrategy; + + + public AbstractStateArrayContributorMapping( + String name, + MappingType type, + StateArrayContributorMetadataAccess attributeMetadataAccess, + FetchStrategy mappedFetchStrategy, + int stateArrayPosition, + ManagedMappingType declaringType) { + super( name, type, declaringType ); + this.attributeMetadataAccess = attributeMetadataAccess; + this.mappedFetchStrategy = mappedFetchStrategy; + this.stateArrayPosition = stateArrayPosition; + } + + @Override + public int getStateArrayPosition() { + return stateArrayPosition; + } + + @Override + public StateArrayContributorMetadataAccess getAttributeMetadataAccess() { + return attributeMetadataAccess; + } + + @Override + public String getFetchableName() { + return getAttributeName(); + } + + @Override + public FetchStrategy getMappedFetchStrategy() { + return mappedFetchStrategy; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedSingularAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedSingularAttributeMapping.java index d06cd6c3e1..eac195aae2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedSingularAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedSingularAttributeMapping.java @@ -6,13 +6,15 @@ */ package org.hibernate.metamodel.mapping.internal; -import java.util.function.BiConsumer; import java.util.function.Consumer; +import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.ManagedMappingType; import org.hibernate.metamodel.mapping.SingularAttributeMapping; +import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess; import org.hibernate.metamodel.model.convert.spi.BasicValueConverter; import org.hibernate.query.NavigablePath; import org.hibernate.query.sqm.sql.SqlExpressionResolver; @@ -38,12 +40,16 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu public BasicValuedSingularAttributeMapping( String attributeName, + int stateArrayPosition, + StateArrayContributorMetadataAccess attributeMetadataAccess, + FetchStrategy mappedFetchStrategy, String tableExpression, String mappedColumnExpression, BasicValueConverter valueConverter, BasicType basicType, - JdbcMapping jdbcMapping) { - super( attributeName, basicType ); + JdbcMapping jdbcMapping, + ManagedMappingType declaringType) { + super( attributeName, stateArrayPosition, attributeMetadataAccess, mappedFetchStrategy, basicType, declaringType ); this.tableExpression = tableExpression; this.mappedColumnExpression = mappedColumnExpression; this.valueConverter = valueConverter; @@ -160,4 +166,9 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu TypeConfiguration typeConfiguration) { action.accept( getJdbcMapping() ); } + + @Override + public int getStateArrayPosition() { + return 0; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java index 7661c73183..301c154ed4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java @@ -6,7 +6,10 @@ */ package org.hibernate.metamodel.mapping.internal; +import org.hibernate.engine.FetchStrategy; import org.hibernate.metamodel.mapping.EntityVersionMapping; +import org.hibernate.metamodel.mapping.ManagedMappingType; +import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess; import org.hibernate.type.BasicType; /** @@ -15,9 +18,23 @@ import org.hibernate.type.BasicType; public class EntityVersionMappingImpl extends BasicValuedSingularAttributeMapping implements EntityVersionMapping { public EntityVersionMappingImpl( String attributeName, + int stateArrayPosition, + StateArrayContributorMetadataAccess attributeMetadataAccess, String containingTableExpression, String mappedColumnExpression, - BasicType basicType) { - super( attributeName, containingTableExpression, mappedColumnExpression, null, basicType, basicType ); + BasicType basicType, + ManagedMappingType declaringType) { + super( + attributeName, + stateArrayPosition, + attributeMetadataAccess, + FetchStrategy.IMMEDIATE_JOIN, + containingTableExpression, + mappedColumnExpression, + null, + basicType, + basicType, + declaringType + ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java index dbb6da0477..26fe9da5e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java @@ -9,12 +9,15 @@ package org.hibernate.metamodel.mapping.internal; import java.util.function.Consumer; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.query.NavigablePath; import org.hibernate.query.sqm.sql.SqlExpressionResolver; import org.hibernate.sql.ast.Clause; @@ -26,6 +29,7 @@ import org.hibernate.sql.results.internal.ScalarDomainResultImpl; import org.hibernate.sql.results.spi.DomainResult; import org.hibernate.sql.results.spi.DomainResultCreationState; import org.hibernate.type.BasicType; +import org.hibernate.type.CompositeType; import org.hibernate.type.spi.TypeConfiguration; /** @@ -44,7 +48,19 @@ public class MappingModelCreationHelper { String pkColumnName, BasicType idType, MappingModelCreationProcess creationProcess) { + final PersistentClass bootEntityDescriptor = creationProcess.getCreationContext() + .getBootModel() + .getEntityBinding( entityPersister.getEntityName() ); + + final PropertyAccess propertyAccess = entityPersister.getRepresentationStrategy() + .resolvePropertyAccess( bootEntityDescriptor.getIdentifierProperty() ); + return new EntityIdentifierMapping() { + @Override + public PropertyAccess getPropertyAccess() { + return propertyAccess; + } + @Override public MappingType getMappedTypeDescriptor() { return ( (BasicType) entityPersister.getIdentifierType() ).getMappedTypeDescriptor(); @@ -84,8 +100,8 @@ public class MappingModelCreationHelper { SqlExpressionResolver.createColumnReferenceKey( rootTable, pkColumnName ), sqlAstProcessingState -> new ColumnReference( pkColumnName, - rootTable, - ( (BasicValuedModelPart) entityPersister.getIdentifierType() ).getJdbcMapping(), + tableGroup.resolveTableReference( rootTable ).getIdentificationVariable(), + ( (BasicValuedMapping) entityPersister.getIdentifierType() ).getJdbcMapping(), creationProcess.getCreationContext().getSessionFactory() ) ); @@ -137,8 +153,25 @@ public class MappingModelCreationHelper { }; } - public static EntityIdentifierMapping buildEncapsulatedCompositeIdentifierMapping(EntityPersister entityPersister) { + public static EntityIdentifierMapping buildEncapsulatedCompositeIdentifierMapping( + EntityPersister entityPersister, + String rootTableName, + String[] rootTableKeyColumnNames, + CompositeType cidType, + MappingModelCreationProcess creationProcess) { + final PersistentClass bootEntityDescriptor = creationProcess.getCreationContext() + .getBootModel() + .getEntityBinding( entityPersister.getEntityName() ); + + final PropertyAccess propertyAccess = entityPersister.getRepresentationStrategy() + .resolvePropertyAccess( bootEntityDescriptor.getIdentifierProperty() ); + return new EntityIdentifierMapping() { + @Override + public PropertyAccess getPropertyAccess() { + return propertyAccess; + } + @Override public MappingType getMappedTypeDescriptor() { return ( (BasicValuedModelPart) entityPersister.getIdentifierType() ).getMappedTypeDescriptor(); @@ -172,9 +205,26 @@ public class MappingModelCreationHelper { }; } - public static EntityIdentifierMapping buildNonEncapsulatedCompositeIdentifierMapping(EntityPersister entityPersister) { + public static EntityIdentifierMapping buildNonEncapsulatedCompositeIdentifierMapping( + EntityPersister entityPersister, + String rootTableName, + String[] rootTableKeyColumnNames, + CompositeType cidType, + MappingModelCreationProcess creationProcess) { + final PersistentClass bootEntityDescriptor = creationProcess.getCreationContext() + .getBootModel() + .getEntityBinding( entityPersister.getEntityName() ); + + final PropertyAccess propertyAccess = entityPersister.getRepresentationStrategy() + .resolvePropertyAccess( bootEntityDescriptor.getIdentifierProperty() ); + return new EntityIdentifierMapping() { + @Override + public PropertyAccess getPropertyAccess() { + return propertyAccess; + } + @Override public MappingType getMappedTypeDescriptor() { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainMetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainMetamodelImpl.java index 9a88d40c93..1d0a1a1a66 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainMetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainMetamodelImpl.java @@ -55,6 +55,7 @@ import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.spi.DomainMetamodel; +import org.hibernate.metamodel.spi.EntityRepresentationStrategy; import org.hibernate.metamodel.spi.MetamodelImplementor; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.persister.collection.CollectionPersister; @@ -206,6 +207,11 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento public MetadataImplementor getBootModel() { return bootModel; } + + @Override + public BootstrapContext getBootstrapContext() { + return bootstrapContext; + } }; @@ -331,23 +337,16 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento private static void registerEntityNameResolvers( EntityPersister persister, Set entityNameResolvers) { - if ( persister.getEntityMetamodel() == null || persister.getEntityMetamodel().getTuplizer() == null ) { + if ( persister.getRepresentationStrategy() == null ) { return; } - registerEntityNameResolvers( persister.getEntityMetamodel().getTuplizer(), entityNameResolvers ); + registerEntityNameResolvers( persister.getRepresentationStrategy(), entityNameResolvers ); } private static void registerEntityNameResolvers( - EntityTuplizer tuplizer, + EntityRepresentationStrategy representationStrategy, Set entityNameResolvers) { - EntityNameResolver[] resolvers = tuplizer.getEntityNameResolvers(); - if ( resolvers == null ) { - return; - } - - for ( EntityNameResolver resolver : resolvers ) { - entityNameResolvers.add( resolver ); - } + representationStrategy.visitEntityNameResolvers( entityNameResolvers::add ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/EntityRepresentationStrategy.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/EntityRepresentationStrategy.java index e93b7f3289..9889ca17d5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/EntityRepresentationStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/EntityRepresentationStrategy.java @@ -6,7 +6,11 @@ */ package org.hibernate.metamodel.spi; +import java.util.function.Consumer; + +import org.hibernate.EntityNameResolver; import org.hibernate.proxy.ProxyFactory; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * Specialization of ManagedTypeRepresentationStrategy for an entity type @@ -18,10 +22,36 @@ public interface EntityRepresentationStrategy extends ManagedTypeRepresentationS /** * Create a delegate capable of instantiating instances of the represented type. */ - Instantiator getInstantiator(); + Instantiator getInstantiator(); /** * Create the delegate capable of producing proxies for the given entity */ ProxyFactory getProxyFactory(); + + default boolean isLifecycleImplementor() { + return false; + } + + default boolean isBytecodeEnhanced() { + return false; + } + + /** + * The Java type descriptor for the concrete entity type + */ + JavaTypeDescriptor getMappedJavaTypeDescriptor(); + + JavaTypeDescriptor getProxyJavaTypeDescriptor(); + + /** + * The Java type descriptor for the type returned when the entity is loaded + */ + default JavaTypeDescriptor getLoadJavaTypeDescriptor() { + return getMappedJavaTypeDescriptor(); + } + + default void visitEntityNameResolvers(Consumer consumer) { + // byt default do nothing + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/ManagedTypeRepresentationStrategy.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/ManagedTypeRepresentationStrategy.java index 73a1395326..4e2f85b002 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/ManagedTypeRepresentationStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/ManagedTypeRepresentationStrategy.java @@ -7,6 +7,7 @@ package org.hibernate.metamodel.spi; import org.hibernate.Incubating; +import org.hibernate.bytecode.spi.ReflectionOptimizer; import org.hibernate.mapping.Property; import org.hibernate.metamodel.RepresentationMode; import org.hibernate.property.access.spi.PropertyAccess; @@ -28,6 +29,8 @@ import org.hibernate.property.access.spi.PropertyAccess; public interface ManagedTypeRepresentationStrategy { RepresentationMode getMode(); + ReflectionOptimizer getReflectionOptimizer(); + /** * Create the property accessor object for the specified attribute */ diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index ef6a404567..9791acf67c 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -52,6 +52,7 @@ import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeDescriptor; import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributesMetadata; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.bytecode.spi.ReflectionOptimizer; import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.cache.spi.access.NaturalIdDataAccess; import org.hibernate.cache.spi.entry.CacheEntry; @@ -60,9 +61,13 @@ import org.hibernate.cache.spi.entry.ReferenceCacheEntryImpl; import org.hibernate.cache.spi.entry.StandardCacheEntryImpl; import org.hibernate.cache.spi.entry.StructuredCacheEntry; import org.hibernate.cache.spi.entry.UnstructuredCacheEntry; +import org.hibernate.classic.Lifecycle; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.lock.LockingStrategy; +import org.hibernate.engine.FetchStrategy; +import org.hibernate.engine.FetchStyle; +import org.hibernate.engine.FetchTiming; import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.internal.CacheHelper; import org.hibernate.engine.internal.ImmutableEntityEntryFactory; @@ -128,17 +133,27 @@ import org.hibernate.mapping.Subclass; import org.hibernate.mapping.Table; import org.hibernate.metadata.ClassMetadata; import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.metamodel.mapping.AttributeMetadata; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityVersionMapping; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.ManagedMappingType; +import org.hibernate.metamodel.mapping.MappingModelCreationContext; import org.hibernate.metamodel.mapping.ModelPart; +import org.hibernate.metamodel.mapping.NaturalIdMapping; +import org.hibernate.metamodel.mapping.Queryable; +import org.hibernate.metamodel.mapping.StateArrayContributorMapping; +import org.hibernate.metamodel.mapping.StateArrayContributorMetadata; +import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess; import org.hibernate.metamodel.mapping.internal.BasicValuedSingularAttributeMapping; import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType; import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper; import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess; import org.hibernate.metamodel.model.convert.spi.BasicValueConverter; import org.hibernate.metamodel.model.domain.NavigableRole; +import org.hibernate.metamodel.spi.EntityRepresentationStrategy; +import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.spi.PersisterCreationContext; import org.hibernate.persister.walking.internal.EntityIdentifierDefinitionHelper; @@ -146,6 +161,8 @@ import org.hibernate.persister.walking.spi.AttributeDefinition; import org.hibernate.persister.walking.spi.EntityIdentifierDefinition; import org.hibernate.pretty.MessageHelper; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; +import org.hibernate.property.access.spi.PropertyAccess; +import org.hibernate.property.access.spi.Setter; import org.hibernate.query.ComparisonOperator; import org.hibernate.query.NavigablePath; import org.hibernate.query.sqm.sql.SqlExpressionResolver; @@ -173,8 +190,11 @@ import org.hibernate.sql.ast.tree.from.TableReferenceJoin; import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate; import org.hibernate.sql.ast.tree.predicate.Junction; import org.hibernate.sql.ast.tree.predicate.Predicate; +import org.hibernate.sql.results.internal.domain.entity.EntityResultImpl; import org.hibernate.sql.results.spi.DomainResult; import org.hibernate.sql.results.spi.DomainResultCreationState; +import org.hibernate.sql.results.spi.Fetchable; +import org.hibernate.sql.results.spi.FetchableContainer; import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.tuple.GenerationTiming; import org.hibernate.tuple.InDatabaseValueGenerationStrategy; @@ -193,8 +213,7 @@ import org.hibernate.type.Type; import org.hibernate.type.TypeHelper; import org.hibernate.type.VersionType; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; -import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry; -import org.hibernate.type.spi.TypeConfiguration; +import org.hibernate.type.descriptor.java.MutabilityPlan; /** * Basic functionality for persisting an entity via JDBC @@ -204,14 +223,13 @@ import org.hibernate.type.spi.TypeConfiguration; */ public abstract class AbstractEntityPersister implements OuterJoinLoadable, Queryable, ClassMetadata, UniqueKeyLoadable, - SQLLoadable, LazyPropertyInitializer, PostInsertIdentityPersister, Lockable { + SQLLoadable, LazyPropertyInitializer, PostInsertIdentityPersister, Lockable, org.hibernate.persister.entity.Queryable { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractEntityPersister.class ); public static final String ENTITY_CLASS = "class"; - private final String sqlAliasStem; @@ -219,7 +237,6 @@ public abstract class AbstractEntityPersister - private final NavigableRole navigableRole; // moved up from AbstractEntityPersister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -232,7 +249,6 @@ public abstract class AbstractEntityPersister private final boolean isLazyPropertiesCacheable; private final CacheEntryHelper cacheEntryHelper; private final EntityMetamodel entityMetamodel; - private final EntityTuplizer entityTuplizer; private final EntityEntryFactory entityEntryFactory; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -603,21 +619,21 @@ public abstract class AbstractEntityPersister @SuppressWarnings("UnnecessaryBoxing") public AbstractEntityPersister( - final PersistentClass persistentClass, + final PersistentClass bootDescriptor, final EntityDataAccess cacheAccessStrategy, final NaturalIdDataAccess naturalIdRegionAccessStrategy, final PersisterCreationContext creationContext) throws HibernateException { this.factory = creationContext.getSessionFactory(); - this.sqlAliasStem = SqlAliasStemHelper.INSTANCE.generateStemFromEntityName( persistentClass.getEntityName() ); + this.sqlAliasStem = SqlAliasStemHelper.INSTANCE.generateStemFromEntityName( bootDescriptor.getEntityName() ); - this.navigableRole = new NavigableRole( persistentClass.getEntityName() ); + this.navigableRole = new NavigableRole( bootDescriptor.getEntityName() ); if ( creationContext.getSessionFactory().getSessionFactoryOptions().isSecondLevelCacheEnabled() ) { - this.canWriteToCache = determineCanWriteToCache( persistentClass, cacheAccessStrategy ); - this.canReadFromCache = determineCanReadFromCache( persistentClass, cacheAccessStrategy ); + this.canWriteToCache = determineCanWriteToCache( bootDescriptor, cacheAccessStrategy ); + this.canReadFromCache = determineCanReadFromCache( bootDescriptor, cacheAccessStrategy ); this.cacheAccessStrategy = cacheAccessStrategy; - this.isLazyPropertiesCacheable = persistentClass.getRootClass().isLazyPropertiesCacheable(); + this.isLazyPropertiesCacheable = bootDescriptor.getRootClass().isLazyPropertiesCacheable(); this.naturalIdRegionAccessStrategy = naturalIdRegionAccessStrategy; } else { @@ -628,8 +644,7 @@ public abstract class AbstractEntityPersister this.naturalIdRegionAccessStrategy = null; } - this.entityMetamodel = new EntityMetamodel( persistentClass, this, factory ); - this.entityTuplizer = this.entityMetamodel.getTuplizer(); + this.entityMetamodel = new EntityMetamodel( bootDescriptor, this, factory ); if ( entityMetamodel.isMutable() ) { this.entityEntryFactory = MutableEntityEntryFactory.INSTANCE; @@ -639,30 +654,37 @@ public abstract class AbstractEntityPersister } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + this.representationStrategy = creationContext.getBootstrapContext().getRepresentationStrategySelector() + .resolveStrategy( bootDescriptor, this, (RuntimeModelCreationContext) creationContext ); + + this.javaTypeDescriptor = representationStrategy.getLoadJavaTypeDescriptor(); + assert javaTypeDescriptor != null; + + final JdbcServices jdbcServices = factory.getServiceRegistry().getService( JdbcServices.class ); final Dialect dialect = jdbcServices.getJdbcEnvironment().getDialect(); - int batch = persistentClass.getBatchSize(); + int batch = bootDescriptor.getBatchSize(); if ( batch == -1 ) { batch = factory.getSessionFactoryOptions().getDefaultBatchFetchSize(); } batchSize = batch; - hasSubselectLoadableCollections = persistentClass.hasSubselectLoadableCollections(); + hasSubselectLoadableCollections = bootDescriptor.hasSubselectLoadableCollections(); propertyMapping = new BasicEntityPropertyMapping( this ); // IDENTIFIER - identifierColumnSpan = persistentClass.getIdentifier().getColumnSpan(); + identifierColumnSpan = bootDescriptor.getIdentifier().getColumnSpan(); rootTableKeyColumnNames = new String[identifierColumnSpan]; rootTableKeyColumnReaders = new String[identifierColumnSpan]; rootTableKeyColumnReaderTemplates = new String[identifierColumnSpan]; identifierAliases = new String[identifierColumnSpan]; - rowIdName = persistentClass.getRootTable().getRowId(); + rowIdName = bootDescriptor.getRootTable().getRowId(); - if ( persistentClass.getLoaderName() != null ) { - singleIdEntityLoader = new SingleIdEntityLoaderProvidedQueryImpl( this, persistentClass.getLoaderName() ); + if ( bootDescriptor.getLoaderName() != null ) { + singleIdEntityLoader = new SingleIdEntityLoaderProvidedQueryImpl( this, bootDescriptor.getLoaderName() ); } // todo (6.0) : account for batch-size and batch-load strategies else { @@ -671,11 +693,11 @@ public abstract class AbstractEntityPersister multiIdEntityLoader = new MultiIdEntityLoaderStandardImpl( this ); - naturalIdLoader = persistentClass.hasNaturalId() + naturalIdLoader = bootDescriptor.hasNaturalId() ? new NaturalIdLoaderStandardImpl( this ) : null; - Iterator iter = persistentClass.getIdentifier().getColumnIterator(); + Iterator iter = bootDescriptor.getIdentifier().getColumnIterator(); int i = 0; while ( iter.hasNext() ) { Column col = (Column) iter.next(); @@ -685,14 +707,14 @@ public abstract class AbstractEntityPersister dialect, factory.getSqlFunctionRegistry() ); - identifierAliases[i] = col.getAlias( dialect, persistentClass.getRootTable() ); + identifierAliases[i] = col.getAlias( dialect, bootDescriptor.getRootTable() ); i++; } // VERSION - if ( persistentClass.isVersioned() ) { - versionColumnName = ( (Column) persistentClass.getVersion().getColumnIterator().next() ).getQuotedName( dialect ); + if ( bootDescriptor.isVersioned() ) { + versionColumnName = ( (Column) bootDescriptor.getVersion().getColumnIterator().next() ).getQuotedName( dialect ); } else { versionColumnName = null; @@ -700,8 +722,8 @@ public abstract class AbstractEntityPersister //WHERE STRING - sqlWhereString = StringHelper.isNotEmpty( persistentClass.getWhere() ) ? - "( " + persistentClass.getWhere() + ") " : + sqlWhereString = StringHelper.isNotEmpty( bootDescriptor.getWhere() ) ? + "( " + bootDescriptor.getWhere() + ") " : null; sqlWhereStringTemplate = sqlWhereString == null ? null : @@ -734,7 +756,7 @@ public abstract class AbstractEntityPersister ArrayList lazyTypes = new ArrayList(); ArrayList lazyColAliases = new ArrayList(); - iter = persistentClass.getPropertyClosureIterator(); + iter = bootDescriptor.getPropertyClosureIterator(); i = 0; boolean foundFormula = false; while ( iter.hasNext() ) { @@ -831,7 +853,7 @@ public abstract class AbstractEntityPersister ArrayList columnSelectables = new ArrayList(); ArrayList propNullables = new ArrayList(); - iter = persistentClass.getSubclassPropertyClosureIterator(); + iter = bootDescriptor.getSubclassPropertyClosureIterator(); while ( iter.hasNext() ) { Property prop = (Property) iter.next(); names.add( prop.getName() ); @@ -937,7 +959,7 @@ public abstract class AbstractEntityPersister } // Handle any filters applied to the class level - filterHelper = new FilterHelper( persistentClass.getFilters(), factory ); + filterHelper = new FilterHelper( bootDescriptor.getFilters(), factory ); // Check if we can use Reference Cached entities in 2lc // todo : should really validate that the cache access type is read-only @@ -964,7 +986,7 @@ public abstract class AbstractEntityPersister this.cacheEntryHelper = buildCacheEntryHelper(); if ( creationContext.getSessionFactory().getSessionFactoryOptions().isSecondLevelCacheEnabled() ) { - this.invalidateCache = canWriteToCache && determineWhetherToInvalidateCache( persistentClass, creationContext ); + this.invalidateCache = canWriteToCache && determineWhetherToInvalidateCache( bootDescriptor, creationContext ); } else { this.invalidateCache = false; @@ -1127,6 +1149,34 @@ public abstract class AbstractEntityPersister return sqlAliasStem; } + @Override + public DomainResult createDomainResult( + NavigablePath navigablePath, + TableGroup tableGroup, + String resultVariable, + DomainResultCreationState creationState) { + //noinspection unchecked + return new EntityResultImpl( navigablePath, this, resultVariable, creationState ); + } + + @Override + public void applySqlSelections( + NavigablePath navigablePath, + TableGroup tableGroup, + DomainResultCreationState creationState) { + throw new NotYetImplementedFor6Exception( getClass() ); + } + + @Override + public NaturalIdMapping getNaturalIdMapping() { + return naturalIdMapping; + } + + @Override + public EntityMappingType getEntityMappingType() { + return this; + } + @Override public TableGroup createRootTableGroup( NavigablePath navigablePath, @@ -1262,7 +1312,7 @@ public abstract class AbstractEntityPersister } @Override - public ModelPart findSubPart(String name) { + public ModelPart findSubPart(String name, EntityMappingType treatTargetType) { LOG.tracef( "#findSubPart(`%s`)", name ); final AttributeMapping declaredAttribute = declaredAttributeMappings.get( name ); @@ -1291,12 +1341,98 @@ public abstract class AbstractEntityPersister } @Override - public void visitSubParts(Consumer consumer) { - consumer.accept( entityIdentifierDefinition ); + public void visitSubParts( + Consumer consumer, + EntityMappingType treatTargetType) { + consumer.accept( identifierMapping ); declaredAttributeMappings.values().forEach( consumer ); } + @Override + public Fetchable findFetchable(String name) { + final Fetchable declaredFetchable = (Fetchable) declaredAttributeMappings.get( name ); + if ( declaredFetchable != null ) { + return declaredFetchable; + } + + if ( superMappingType != null ) { + return superMappingType.findFetchable( name ); + } + + return null; + } + + @Override + public void visitKeyFetchables( + Consumer fetchableConsumer, + EntityMappingType treatTargetType) { + if ( getIdentifierMapping() instanceof FetchableContainer ) { + // essentially means the entity has a composite id - ask the embeddable to visit its fetchables + // - todo (6.0) : determine whether this should call `#visitFetchables` or `#visitKeyFetchables` + ( (FetchableContainer) getIdentifierMapping() ).visitFetchables( fetchableConsumer, treatTargetType ); + } + + // otherwise, nothing to do + } + + @Override + public void visitFetchables( + Consumer fetchableConsumer, + EntityMappingType treatTargetType) { + visitStateArrayContributors( + mapping -> { + if ( mapping.isDeclaredOnTypeOrSuperType( treatTargetType ) ) { + fetchableConsumer.accept( mapping ); + } + }, + treatTargetType + ); + } + + @Override + public void visitStateArrayContributors( + Consumer mappingConsumer, + EntityMappingType targetType) { + visitAttributeMappings( + attributeMapping -> { + if ( attributeMapping instanceof StateArrayContributorMapping ) { + mappingConsumer.accept( (StateArrayContributorMapping) attributeMapping ); + } + }, + targetType + ); + } + + @Override + public void visitAttributeMappings( + Consumer action, + EntityMappingType targetType) { + visitSuperTypeAttributeMappings( action ); + + declaredAttributeMappings.values().forEach( action ); + + if ( targetType == null ) { + visitSubTypeAttributeMappings( action ); + } + } + + @Override + public void visitSuperTypeAttributeMappings(Consumer action) { + if ( superMappingType != null ) { + superMappingType.visitSuperTypeAttributeMappings( action ); + } + } + + @Override + public void visitSubTypeAttributeMappings(Consumer action) { + if ( subclassMappingTypes != null ) { + subclassMappingTypes.values().forEach( + subclassMappingTypes -> subclassMappingTypes.visitSubTypeAttributeMappings( action ) + ); + } + } + public Object initializeLazyProperty(String fieldName, Object entity, SharedSessionContractImplementor session) { final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); final EntityEntry entry = persistenceContext.getEntry( entity ); @@ -5143,7 +5279,7 @@ public abstract class AbstractEntityPersister } public Object createProxy(Serializable id, SharedSessionContractImplementor session) throws HibernateException { - return entityMetamodel.getTuplizer().createProxy( id, session ); + return representationStrategy.getProxyFactory().getProxy( id, session ); } public String toString() { @@ -5243,27 +5379,58 @@ public abstract class AbstractEntityPersister } public final Class getMappedClass() { - return getEntityTuplizer().getMappedClass(); + return getMappedJavaTypeDescriptor().getJavaType(); } public boolean implementsLifecycle() { - return getEntityTuplizer().isLifecycleImplementor(); + return Lifecycle.class.isAssignableFrom( getMappedClass() ); } public Class getConcreteProxyClass() { - return getEntityTuplizer().getConcreteProxyClass(); + return getRepresentationStrategy().getProxyJavaTypeDescriptor().getJavaType(); } public void setPropertyValues(Object object, Object[] values) { - getEntityTuplizer().setPropertyValues( object, values ); + if ( accessOptimizer != null ) { + accessOptimizer.setPropertyValues( object, values ); + } + else { + visitAttributeMappings( + attributeMapping -> { + final Setter setter = attributeMapping.getAttributeMetadataAccess() + .resolveAttributeMetadata( this ) + .getPropertyAccess() + .getSetter(); + setter.set( object, values, getFactory() ); + } + ); + } } public void setPropertyValue(Object object, int i, Object value) { - getEntityTuplizer().setPropertyValue( object, i, value ); + final String propertyName = getPropertyNames()[i]; + + final AttributeMapping attributeMapping = (AttributeMapping) findSubPart( propertyName, this ); + final AttributeMetadata attributeMetadata = attributeMapping.getAttributeMetadataAccess().resolveAttributeMetadata( this ); + attributeMetadata.getPropertyAccess().getSetter().set( object, value, getFactory() ); } public Object[] getPropertyValues(Object object) { - return getEntityTuplizer().getPropertyValues( object ); + if ( accessOptimizer != null ) { + return accessOptimizer.getPropertyValues( object ); + } + else { + final List values = new ArrayList<>(); + + visitAttributeMappings( + attributeMapping -> { + final AttributeMetadata attributeMetadata = attributeMapping.getAttributeMetadataAccess() + .resolveAttributeMetadata( this ); + values.add( attributeMetadata.getPropertyAccess().getGetter().get( object ) ); + } + ); + return values.toArray(); + } } @Override @@ -5792,14 +5959,19 @@ public abstract class AbstractEntityPersister throw new AssertionFailure( "Table " + tableName + " not found" ); } + @Override + public EntityRepresentationStrategy getRepresentationStrategy() { + return representationStrategy; + } + @Override public EntityMode getEntityMode() { - return entityMetamodel.getEntityMode(); + return getRepresentationStrategy().getMode().getLegacyEntityMode(); } @Override public EntityTuplizer getEntityTuplizer() { - return entityTuplizer; + return null; } @Override @@ -5933,11 +6105,13 @@ public abstract class AbstractEntityPersister // org.hibernate.metamodel.mapping.EntityMappingType private JavaTypeDescriptor javaTypeDescriptor; + private EntityRepresentationStrategy representationStrategy; private EntityMappingType superMappingType; private SortedMap subclassMappingTypes; private EntityIdentifierMapping identifierMapping; + private NaturalIdMapping naturalIdMapping; private EntityVersionMapping versionMapping; private SortedMap declaredAttributeMappings = new TreeMap<>(); @@ -5957,28 +6131,38 @@ public abstract class AbstractEntityPersister subclassMappingTypes.put( sub.getEntityName(), sub ); } + @Override + public boolean isTypeOrSuperType(EntityMappingType targetType) { + if ( targetType == null ) { + // todo (6.0) : need to think through what this ought to indicate (if we allow it at all) + // - see `org.hibernate.metamodel.mapping.internal.AbstractManagedMappingType#isTypeOrSuperType` + return true; + } + + if ( targetType == this ) { + return true; + } + + if ( superMappingType != null ) { + return superMappingType.isTypeOrSuperType( targetType ); + } + + return false; + } + + private ReflectionOptimizer.AccessOptimizer accessOptimizer; + @Override public void prepareMappingModel(MappingModelCreationProcess creationProcess) { if ( identifierMapping != null ) { return; } - final TypeConfiguration typeConfiguration = creationProcess.getCreationContext() - .getSessionFactory() - .getTypeConfiguration(); - final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry(); + final MappingModelCreationContext creationContext = creationProcess.getCreationContext(); - if ( getConcreteProxyClass() != null ) { - //noinspection unchecked - javaTypeDescriptor = jtdRegistry.getDescriptor( getConcreteProxyClass() ); - } - else if ( getMappedClass() == null || getMappedClass() == Map.class ) { - javaTypeDescriptor = jtdRegistry.resolveDynamicDescriptor( getEntityName() ); - } - else { - //noinspection unchecked - javaTypeDescriptor = jtdRegistry.getDescriptor( getMappedClass() ); - } + final PersistentClass bootEntityDescriptor = creationContext + .getBootModel() + .getEntityBinding( getEntityName() ); // todo (6.0) : should we create these only on root? @@ -5987,6 +6171,8 @@ public abstract class AbstractEntityPersister (role, creationProcess1) -> generateIdentifierMapping( creationProcess ) ); + naturalIdMapping = null; + if ( getVersionType() == null ) { versionMapping = null; } @@ -6000,22 +6186,34 @@ public abstract class AbstractEntityPersister ); } - final PersistentClass bootEntityDescriptor = creationProcess.getCreationContext() - .getBootModel() - .getEntityBinding( getEntityName() ); - - final EntityMetamodel currentEntityMetamodel = this.getEntityMetamodel(); + int stateArrayPosition = superMappingType == null ? 0 : superMappingType.getAttributeMappings().size(); + for ( int i = 0; i < currentEntityMetamodel.getPropertySpan(); i++ ) { final NonIdentifierAttribute runtimeAttrDefinition = currentEntityMetamodel.getProperties()[i]; final Property bootProperty = bootEntityDescriptor.getProperty( runtimeAttrDefinition.getName() ); declaredAttributeMappings.put( runtimeAttrDefinition.getName(), - generateNonIdAttributeMapping( runtimeAttrDefinition, bootProperty, creationProcess ) + generateNonIdAttributeMapping( + runtimeAttrDefinition, + bootProperty, + stateArrayPosition++, + this, + creationProcess + ) ); } + + final ReflectionOptimizer reflectionOptimizer = representationStrategy.getReflectionOptimizer(); + + if ( reflectionOptimizer != null ) { + accessOptimizer = reflectionOptimizer.getAccessOptimizer(); + } + else { + accessOptimizer = null; + } } private EntityIdentifierMapping generateIdentifierMapping(MappingModelCreationProcess creationProcess) { @@ -6023,11 +6221,23 @@ public abstract class AbstractEntityPersister if ( idType instanceof CompositeType ) { final CompositeType cidType = (CompositeType) idType; - if ( !cidType.isEmbedded() ) { - return MappingModelCreationHelper.buildEncapsulatedCompositeIdentifierMapping( this ); + if ( ! cidType.isEmbedded() ) { + return MappingModelCreationHelper.buildEncapsulatedCompositeIdentifierMapping( + this, + getRootTableName(), + rootTableKeyColumnNames, + cidType, + creationProcess + ); } - return MappingModelCreationHelper.buildNonEncapsulatedCompositeIdentifierMapping( this ); + return MappingModelCreationHelper.buildNonEncapsulatedCompositeIdentifierMapping( + this, + getRootTableName(), + rootTableKeyColumnNames, + cidType, + creationProcess + ); } return MappingModelCreationHelper.buildSimpleIdentifierMapping( @@ -6048,11 +6258,19 @@ public abstract class AbstractEntityPersister private AttributeMapping generateNonIdAttributeMapping( NonIdentifierAttribute tupleAttrDefinition, Property bootProperty, + int stateArrayPosition, + ManagedMappingType declaringType, MappingModelCreationProcess creationProcess) { + final String attrName = tupleAttrDefinition.getName(); final Type attrType = tupleAttrDefinition.getType(); - final int propertyIndex = getPropertyIndex( attrName ); + final int propertyIndex = getPropertyIndex( bootProperty.getName() ); + + if ( propertyIndex == getVersionProperty() ) { + return getVersionMapping(); + } + final String tableExpression = getPropertyTableName( attrName ); final String[] attrColumnNames = getPropertyColumnNames( propertyIndex ); @@ -6060,6 +6278,60 @@ public abstract class AbstractEntityPersister final BasicValue.Resolution resolution = ( (BasicValue) bootProperty.getValue() ).resolve(); final BasicValueConverter valueConverter = resolution.getValueConverter(); + final StateArrayContributorMetadataAccess attributeMetadataAccess = entityMappingType -> new StateArrayContributorMetadata() { + private final PropertyAccess propertyAccess = getRepresentationStrategy().resolvePropertyAccess( bootProperty ); + private final MutabilityPlan mutabilityPlan = resolution.getMutabilityPlan(); + private final boolean nullable = bootProperty.getValue().isNullable(); + private final boolean insertable = bootProperty.isInsertable(); + private final boolean updateable = bootProperty.isUpdateable(); + private final boolean includeInOptimisticLocking = bootProperty.isOptimisticLocked(); + + @Override + public PropertyAccess getPropertyAccess() { + return propertyAccess; + } + + @Override + public MutabilityPlan getMutabilityPlan() { + return mutabilityPlan; + } + + @Override + public boolean isNullable() { + return nullable; + } + + @Override + public boolean isInsertable() { + return insertable; + } + + @Override + public boolean isUpdatable() { + return updateable; + } + + @Override + public boolean isIncludedInDirtyChecking() { + // todo (6.0) : do not believe this is correct + return updateable; + } + + @Override + public boolean isIncludedInOptimisticLocking() { + return includeInOptimisticLocking; + } + + @Override + public CascadeStyle getCascadeStyle() { + return tupleAttrDefinition.getCascadeStyle(); + } + }; + + final FetchStrategy fetchStrategy = bootProperty.isLazy() + ? new FetchStrategy( FetchTiming.DELAYED, FetchStyle.SELECT ) + : FetchStrategy.IMMEDIATE_JOIN; + if ( valueConverter != null ) { // we want to "decompose" the "type" into its various pieces as expected by the mapping assert valueConverter.getRelationalJavaDescriptor() == resolution.getRelationalJavaDescriptor(); @@ -6072,21 +6344,29 @@ public abstract class AbstractEntityPersister return new BasicValuedSingularAttributeMapping( attrName, + stateArrayPosition, + attributeMetadataAccess, + fetchStrategy, tableExpression, attrColumnNames[0], valueConverter, mappingBasicType, - mappingBasicType.getJdbcMapping() + mappingBasicType.getJdbcMapping(), + declaringType ); } else { return new BasicValuedSingularAttributeMapping( attrName, + stateArrayPosition, + attributeMetadataAccess, + fetchStrategy, tableExpression, attrColumnNames[0], null, (BasicType) attrType, - (BasicType) attrType + (BasicType) attrType, + declaringType ); } } @@ -6121,11 +6401,6 @@ public abstract class AbstractEntityPersister throw new NotYetImplementedFor6Exception( getClass() ); } - @Override - public void visitAttributeMappings(Consumer action) { - throw new NotYetImplementedFor6Exception( getClass() ); - } - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // EntityDefinition impl (walking model - deprecated) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java index 9d6de6ba60..d6b0cff2af 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java @@ -32,10 +32,12 @@ import org.hibernate.internal.FilterAliasGenerator; import org.hibernate.loader.spi.Loadable; import org.hibernate.metadata.ClassMetadata; import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.EntityValuedModelPart; import org.hibernate.metamodel.mapping.MappingModelCreationContext; import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType; import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess; import org.hibernate.metamodel.model.domain.NavigableRole; +import org.hibernate.metamodel.spi.EntityRepresentationStrategy; import org.hibernate.persister.walking.spi.EntityDefinition; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; import org.hibernate.sql.ast.spi.SqlAliasStemHelper; @@ -77,7 +79,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; * @see org.hibernate.persister.spi.PersisterFactory * @see org.hibernate.persister.spi.PersisterClassResolver */ -public interface EntityPersister extends EntityDefinition, InFlightEntityMappingType, Loadable, RootTableGroupProducer { +public interface EntityPersister extends EntityDefinition, EntityValuedModelPart, InFlightEntityMappingType, Loadable, RootTableGroupProducer { /** * The property name of the "special" identifier property in HQL @@ -850,7 +852,23 @@ public interface EntityPersister extends EntityDefinition, InFlightEntityMapping */ EntityPersister getSubclassEntityPersister(Object instance, SessionFactoryImplementor factory); + EntityRepresentationStrategy getRepresentationStrategy(); + + @Override + default EntityMappingType getEntityMappingType() { + return this; + } + + /** + * @deprecated Use {@link #getRepresentationStrategy()} + */ + @Deprecated EntityMode getEntityMode(); + + /** + * @deprecated Use {@link #getRepresentationStrategy()} + */ + @Deprecated EntityTuplizer getEntityTuplizer(); BytecodeEnhancementMetadata getInstrumentationMetadata(); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/Queryable.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/Queryable.java index 0ee6447fc8..bf8698fa23 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/Queryable.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/Queryable.java @@ -12,7 +12,10 @@ import org.hibernate.sql.SelectFragment; * operations required by the Hibernate Query Language * * @author Gavin King + * + * @deprecated See {@link org.hibernate.metamodel.mapping.Queryable} */ +@Deprecated public interface Queryable extends Loadable, PropertyMapping, Joinable { /** diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/EncapsulatedEntityIdentifierDefinition.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/EncapsulatedEntityIdentifierDefinition.java index 61df7cb352..01d1fecd87 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/EncapsulatedEntityIdentifierDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/EncapsulatedEntityIdentifierDefinition.java @@ -10,5 +10,5 @@ package org.hibernate.persister.walking.spi; * @author Steve Ebersole */ public interface EncapsulatedEntityIdentifierDefinition extends EntityIdentifierDefinition { - public AttributeDefinition getAttributeDefinition(); + AttributeDefinition getAttributeDefinition(); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/EntityIdentifierDefinition.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/EntityIdentifierDefinition.java index e7a95e6fd0..31ef850e71 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/EntityIdentifierDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/EntityIdentifierDefinition.java @@ -6,14 +6,12 @@ */ package org.hibernate.persister.walking.spi; -import org.hibernate.metamodel.mapping.ModelPart; - /** * Describes aspects of the identifier for an entity * * @author Steve Ebersole */ -public interface EntityIdentifierDefinition extends ModelPart { +public interface EntityIdentifierDefinition { /** * Is the entity identifier encapsulated? Meaning, is it represented by a single attribute? * diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/ProxyFactory.java b/hibernate-core/src/main/java/org/hibernate/proxy/ProxyFactory.java index 60a7965798..33045e1f9c 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/ProxyFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/ProxyFactory.java @@ -64,5 +64,4 @@ public interface ProxyFactory { * proxy. */ HibernateProxy getProxy(Serializable id, SharedSessionContractImplementor session) throws HibernateException; - } diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/map/MapProxyFactory.java b/hibernate-core/src/main/java/org/hibernate/proxy/map/MapProxyFactory.java index da50c6d39d..acc0cb0924 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/map/MapProxyFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/map/MapProxyFactory.java @@ -8,6 +8,7 @@ package org.hibernate.proxy.map; import java.io.Serializable; import java.lang.reflect.Method; +import java.util.Map; import java.util.Set; import org.hibernate.HibernateException; @@ -31,7 +32,6 @@ public class MapProxyFactory implements ProxyFactory { final Method setIdentifierMethod, CompositeType componentIdType) throws HibernateException { this.entityName = entityName; - } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/QueryTypeMismatchException.java b/hibernate-core/src/main/java/org/hibernate/query/QueryTypeMismatchException.java new file mode 100644 index 0000000000..903989beed --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/QueryTypeMismatchException.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.query; + +import org.hibernate.HibernateException; + +/** + * Indicates a problem with requested typed-Query result-type (e.g., JPA's {@link javax.persistence.TypedQuery}) + * + * @author Steve Ebersole + */ +public class QueryTypeMismatchException extends HibernateException { + public QueryTypeMismatchException(String message) { + super( message ); + } + + public QueryTypeMismatchException(String message, Throwable cause) { + super( message, cause ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java index 4b4c3d2979..e70ad310b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java @@ -13,6 +13,7 @@ import java.util.Map; import java.util.Set; import javax.persistence.Parameter; import javax.persistence.PersistenceException; +import javax.persistence.Tuple; import org.hibernate.LockMode; import org.hibernate.ScrollMode; @@ -25,6 +26,7 @@ import org.hibernate.graph.RootGraph; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.Query; +import org.hibernate.query.QueryTypeMismatchException; import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl; import org.hibernate.query.hql.internal.QuerySplitter; import org.hibernate.query.hql.spi.HqlQueryImplementor; @@ -36,10 +38,10 @@ import org.hibernate.query.spi.AbstractQuery; import org.hibernate.query.spi.MutableQueryOptions; import org.hibernate.query.spi.NonSelectQueryPlan; import org.hibernate.query.spi.ParameterMetadataImplementor; +import org.hibernate.query.spi.QueryInterpretationCache; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.query.spi.QueryParameterImplementor; -import org.hibernate.query.spi.QueryInterpretationCache; import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.query.spi.SelectQueryPlan; import org.hibernate.query.sqm.mutation.spi.DeleteHandler; @@ -48,6 +50,7 @@ import org.hibernate.query.sqm.tree.SqmDmlStatement; import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; +import org.hibernate.query.sqm.tree.select.SqmSelection; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.exec.spi.DomainParameterBindingContext; @@ -143,6 +146,9 @@ public class QuerySqmImpl SharedSessionContractImplementor producer) { super( producer ); + SqmUtil.verifyIsSelectStatement( sqmStatement ); + checkQueryReturnType( (SqmSelectStatement) sqmStatement, resultType, producer.getFactory() ); + if ( resultType != null ) { if ( sqmStatement instanceof SqmDmlStatement ) { throw new IllegalArgumentException( "Non-select queries cannot be typed" ); @@ -165,6 +171,51 @@ public class QuerySqmImpl this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, producer.getFactory() ); } + private static void checkQueryReturnType(SqmSelectStatement sqm, Class resultClass, SessionFactoryImplementor sessionFactory) { + if ( resultClass == null ) { + // nothing to check + return; + } + + final List selections = sqm.getQuerySpec().getSelectClause().getSelections(); + + if ( resultClass.isArray() ) { + // todo (6.0) : implement + } + else if ( Tuple.class.isAssignableFrom( resultClass ) ) { + // todo (6.0) : implement + } + else { + if ( selections.size() != 1 ) { + final String errorMessage = "Query result-type error - multiple selections: use Tuple or array"; + + if ( sessionFactory.getSessionFactoryOptions().getJpaCompliance().isJpaQueryComplianceEnabled() ) { + throw new IllegalArgumentException( errorMessage ); + } + else { + throw new QueryTypeMismatchException( errorMessage ); + } + } + + final SqmSelection sqmSelection = selections.get( 0 ); + + if ( ! resultClass.isAssignableFrom( sqmSelection.getNodeType().getExpressableJavaTypeDescriptor().getJavaType() ) ) { + final String errorMessage = String.format( + "Specified result type [%s] did not match Query selection type [%s] - multiple selections: use Tuple or array", + resultClass.getName(), + sqmSelection.getNodeType().getExpressableJavaTypeDescriptor().getJavaType().getName() + ); + + if ( sessionFactory.getSessionFactoryOptions().getJpaCompliance().isJpaQueryComplianceEnabled() ) { + throw new IllegalArgumentException( errorMessage ); + } + else { + throw new QueryTypeMismatchException( errorMessage ); + } + } + } + } + @Override public SessionFactoryImplementor getSessionFactory() { return getSession().getFactory(); @@ -305,7 +356,6 @@ public class QuerySqmImpl } @Override - @SuppressWarnings("unchecked") protected List doList() { SqmUtil.verifyIsSelectStatement( getSqmStatement() ); getSession().prepareForQueryExecution( requiresTxn( getLockOptions().findGreatestLockMode() ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java index a3d7e6d976..fb486c61ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java @@ -481,6 +481,8 @@ public class BaseSemanticQueryWalker implements SemanticQueryWalker { @Override public Object visitTreatedPath(SqmTreatedPath sqmTreatedPath) { + // todo (6.0) : determine how to best handle TREAT + // - see org.hibernate.query.sqm.sql.internal.SqmSelectToSqlAstConverter.visitFetches throw new NotYetImplementedFor6Exception(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/SqmSelectToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/SqmSelectToSqlAstConverter.java index 1d1a35dcc2..9009f58826 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/SqmSelectToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/SqmSelectToSqlAstConverter.java @@ -31,7 +31,7 @@ import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.query.sqm.internal.DomainParameterXref; import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter; import org.hibernate.query.sqm.sql.SqlAstCreationState; -import org.hibernate.query.sqm.sql.internal.instantiation.DynamicInstantiation; +import org.hibernate.sql.results.internal.domain.instantiation.DynamicInstantiation; import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; @@ -161,6 +161,7 @@ public class SqmSelectToSqlAstConverter try { fetchDepth++; final Fetch fetch = buildFetch( fetchParent, fetchable ); + if ( fetch != null ) { fetches.add( fetch ); } @@ -170,8 +171,11 @@ public class SqmSelectToSqlAstConverter } }; - fetchParent.getReferencedMappingContainer().visitKeyFetchables( fetchableConsumer ); - fetchParent.getReferencedMappingContainer().visitFetchables( fetchableConsumer ); +// todo (6.0) : determine how to best handle TREAT +// fetchParent.getReferencedMappingContainer().visitKeyFetchables( fetchableConsumer, treatTargetType ); +// fetchParent.getReferencedMappingContainer().visitFetchables( fetchableConsumer, treatTargetType ); + fetchParent.getReferencedMappingContainer().visitKeyFetchables( fetchableConsumer, null ); + fetchParent.getReferencedMappingContainer().visitFetchables( fetchableConsumer, null ); return fetches; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java index 4a32571b5a..734d0508a1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java @@ -8,6 +8,7 @@ package org.hibernate.query.sqm.tree.domain; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.query.sqm.NodeBuilder; +import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.tree.from.SqmRoot; /** @@ -57,4 +58,8 @@ public class SqmTreatedRoot extends SqmRoot implements SqmTre return wrappedPath.getLhs(); } + @Override + public X accept(SemanticQueryWalker walker) { + return walker.visitTreatedPath( this ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/NullValueAssembler.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/NullValueAssembler.java new file mode 100644 index 0000000000..829da5bc12 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/NullValueAssembler.java @@ -0,0 +1,33 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.internal; + +import org.hibernate.sql.results.spi.DomainResultAssembler; +import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions; +import org.hibernate.sql.results.spi.RowProcessingState; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; + +/** + * @author Steve Ebersole + */ +public class NullValueAssembler implements DomainResultAssembler { + private final JavaTypeDescriptor javaTypeDescriptor; + + public NullValueAssembler(JavaTypeDescriptor javaTypeDescriptor) { + this.javaTypeDescriptor = javaTypeDescriptor; + } + + @Override + public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) { + return null; + } + + @Override + public JavaTypeDescriptor getAssembledJavaTypeDescriptor() { + return javaTypeDescriptor; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java index a7d8ab1a11..c3de0d7df9 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java @@ -12,6 +12,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.named.RowReaderMemento; import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.results.spi.DomainResultAssembler; +import org.hibernate.sql.results.spi.EntityInitializer; import org.hibernate.sql.results.spi.Initializer; import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingState; @@ -96,6 +97,30 @@ public class StandardRowReader implements RowReader { RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) { + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // todo (6.0) : we may want to split handling of initializers into specific sub-type handling + // - meaning we'd have something like: + +// for ( EntityInitializer initializer : entityInitializers ) { +// initializer.resolveKey( rowProcessingState ); +// } +// +// for ( EntityInitializer initializer : collectionInitializers ) { +// initializer.resolveKey( rowProcessingState ); +// } +// +// for ( Initializer initializer : entityInitializers ) { +// initializer.resolveInstance( rowProcessingState ); +// } +// +// for ( EntityInitializer initializer : collectionInitializers ) { +// initializer.resolveInstance( rowProcessingState ); +// } + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // old + for ( Initializer initializer : initializers ) { initializer.resolveKey( rowProcessingState ); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/AbstractFetchParent.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/AbstractFetchParent.java new file mode 100644 index 0000000000..168afe9b44 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/AbstractFetchParent.java @@ -0,0 +1,62 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.internal.domain; + +import java.util.Collections; +import java.util.List; + +import org.hibernate.query.NavigablePath; +import org.hibernate.sql.results.spi.DomainResultCreationState; +import org.hibernate.sql.results.spi.Fetch; +import org.hibernate.sql.results.spi.FetchParent; +import org.hibernate.sql.results.spi.FetchableContainer; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractFetchParent implements FetchParent { + private final FetchableContainer fetchContainer; + private final NavigablePath navigablePath; + + private List fetches; + + public AbstractFetchParent(FetchableContainer fetchContainer, NavigablePath navigablePath) { + this.fetchContainer = fetchContainer; + this.navigablePath = navigablePath; + } + + protected void afterInitialize(DomainResultCreationState creationState) { + this.fetches = creationState.visitFetches( this ); + } + + @Override + public NavigablePath getNavigablePath() { + return navigablePath; + } + + @Override + public FetchableContainer getReferencedMappingContainer() { + return fetchContainer; + } + + @Override + public List getFetches() { + return fetches == null ? Collections.emptyList() : Collections.unmodifiableList( fetches ); + } + + @Override + public Fetch findFetch(String fetchableName) { + if ( fetches != null ) { + for ( Fetch fetch : fetches ) { + if ( fetch.getFetchedMapping().getFetchableName().equals( fetchableName ) ) { + return fetch; + } + } + } + return null; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/AbstractFetchParentAccess.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/AbstractFetchParentAccess.java new file mode 100644 index 0000000000..1e7e23cb6f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/AbstractFetchParentAccess.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.internal.domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import org.hibernate.sql.results.spi.FetchParentAccess; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractFetchParentAccess implements FetchParentAccess { + private List> listeners; + + @Override + public void registerResolutionListener(Consumer listener) { + if ( listeners == null ) { + listeners = new ArrayList<>(); + } + + listeners.add( listener ); + } + + protected void clearParentResolutionListeners() { + if ( listeners != null ) { + listeners.clear(); + } + } + + protected void notifyParentResolutionListeners(Object parentInstance) { + if ( listeners == null ) { + return; + } + + for ( Consumer listener : listeners ) { + listener.accept( parentInstance ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/AbstractEntityInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/AbstractEntityInitializer.java new file mode 100644 index 0000000000..c51d3f62a4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/AbstractEntityInitializer.java @@ -0,0 +1,661 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.internal.domain.entity; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import org.hibernate.LockMode; +import org.hibernate.NotYetImplementedFor6Exception; +import org.hibernate.WrongClassException; +import org.hibernate.cache.spi.access.EntityDataAccess; +import org.hibernate.cache.spi.entry.CacheEntry; +import org.hibernate.engine.spi.EntityEntry; +import org.hibernate.engine.spi.EntityKey; +import org.hibernate.engine.spi.PersistenceContext; +import org.hibernate.engine.spi.SessionEventListenerManager; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.engine.spi.Status; +import org.hibernate.event.service.spi.EventListenerGroup; +import org.hibernate.event.service.spi.EventListenerRegistry; +import org.hibernate.event.spi.EventType; +import org.hibernate.event.spi.PostLoadEvent; +import org.hibernate.event.spi.PostLoadEventListener; +import org.hibernate.event.spi.PreLoadEvent; +import org.hibernate.event.spi.PreLoadEventListener; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.metamodel.mapping.StateArrayContributorMapping; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.proxy.HibernateProxy; +import org.hibernate.query.NavigablePath; +import org.hibernate.sql.results.internal.NullValueAssembler; +import org.hibernate.sql.results.internal.domain.AbstractFetchParentAccess; +import org.hibernate.sql.results.spi.AssemblerCreationState; +import org.hibernate.sql.results.spi.DomainResult; +import org.hibernate.sql.results.spi.DomainResultAssembler; +import org.hibernate.sql.results.spi.EntityInitializer; +import org.hibernate.sql.results.spi.EntityMappingNode; +import org.hibernate.sql.results.spi.Fetch; +import org.hibernate.sql.results.spi.Initializer; +import org.hibernate.sql.results.spi.LoadingEntityEntry; +import org.hibernate.sql.results.spi.RowProcessingState; +import org.hibernate.type.TypeHelper; + +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractEntityInitializer extends AbstractFetchParentAccess implements EntityInitializer { + + // NOTE : even though we only keep the EntityDescriptor here, rather than EntityReference + // the "scope" of this initializer is a specific EntityReference. + // + // The full EntityReference is simply not needed here, and so we just keep + // the EntityDescriptor here to avoid chicken/egg issues in the creation of + // these + + private final EntityPersister entityDescriptor; + private final NavigablePath navigablePath; + private final LockMode lockMode; + + private final List identifierInitializers = new ArrayList<>(); + + private final DomainResultAssembler identifierAssembler; + private final DomainResultAssembler discriminatorAssembler; + private final DomainResultAssembler versionAssembler; + + private final Map assemblerMap = new HashMap<>(); + + // per-row state + private EntityPersister concreteDescriptor; + private EntityKey entityKey; + private Object entityInstance; + private boolean missing; + private Object[] resolvedEntityState; + + // todo (6.0) : ^^ need a better way to track whether we are loading the entity state or if something else is/has + + @SuppressWarnings("WeakerAccess") + protected AbstractEntityInitializer( + EntityMappingNode resultDescriptor, + NavigablePath navigablePath, + LockMode lockMode, + DomainResult identifierResult, + DomainResult discriminatorResult, + DomainResult versionResult, + Consumer initializerConsumer, + AssemblerCreationState creationState) { + super( ); + this.entityDescriptor = (EntityPersister) resultDescriptor.getEntityValuedModelPart().getEntityMappingType(); + this.navigablePath = navigablePath; + this.lockMode = lockMode; + + this.identifierAssembler = identifierResult.createResultAssembler( + identifierInitializers::add, + creationState + ); + + if ( discriminatorResult != null ) { + discriminatorAssembler = discriminatorResult.createResultAssembler( + initializer -> { + throw new UnsupportedOperationException( + "Registering an Initializer as part of Entity discriminator is illegal" ); + }, + creationState + ); + } + else { + discriminatorAssembler = null; + } + + if ( versionResult != null ) { + this.versionAssembler = versionResult.createResultAssembler( + initializer -> { + throw new UnsupportedOperationException( + "Registering an Initializer as part of Entity version is illegal" ); + }, + creationState + ); + } + else { + this.versionAssembler = null; + } + + entityDescriptor.visitStateArrayContributors( + attributeMapping -> { + // todo (6.0) : somehow we need to track whether all state is loaded/resolved + // note that lazy proxies or uninitialized collections count against + // that in the affirmative + + final Fetch fetch = resultDescriptor.findFetch( attributeMapping.getAttributeName() ); + + final DomainResultAssembler stateAssembler; + if ( fetch == null ) { + stateAssembler = new NullValueAssembler( attributeMapping.getMappedTypeDescriptor().getMappedJavaTypeDescriptor() ); + } + else { + stateAssembler = fetch.createAssembler( + this, + initializerConsumer, + creationState + ); + } + + assemblerMap.put( attributeMapping, stateAssembler ); + } + ); + + initializerConsumer.accept( this ); + } + + public NavigablePath getNavigablePath() { + return navigablePath; + } + + protected abstract boolean isEntityReturn(); + + @Override + public EntityPersister getEntityDescriptor() { + return entityDescriptor; + } + + @Override + public Object getEntityInstance() { + return entityInstance; + } + + @SuppressWarnings("unused") + public Object getKeyValue() { + return entityKey.getIdentifier(); + } + + @Override + public Object getFetchParentInstance() { + if ( entityInstance == null ) { + throw new IllegalStateException( "Unexpected state condition - entity instance not yet resolved" ); + } + + return entityInstance; + } + + // todo (6.0) : how to best handle possibility of null association? + + @Override + public void resolveKey(RowProcessingState rowProcessingState) { + // todo (6.0) : atm we do not handle sequential selects + // - see AbstractEntityPersister#hasSequentialSelect and + // AbstractEntityPersister#getSequentialSelect in 5.2 + + if ( entityInstance != null ) { + return; + } + + if ( EntityLoadingLogger.TRACE_ENABLED ) { + EntityLoadingLogger.INSTANCE.tracef( + "(%s) Beginning Initializer#resolveKey process for entity : %s", + StringHelper.collapse( this.getClass().getName() ), + getNavigablePath().getFullPath() + ); + } + + final SharedSessionContractImplementor session = rowProcessingState.getJdbcValuesSourceProcessingState().getSession(); + concreteDescriptor = determineConcreteEntityDescriptor( rowProcessingState, session ); + + initializeIdentifier( rowProcessingState ); + resolveEntityKey( rowProcessingState ); + + if ( entityKey == null ) { + EntityLoadingLogger.INSTANCE.debugf( + "(%s) EntityKey (%s) is null", + StringHelper.collapse( this.getClass().getName() ), + getNavigablePath() + ); + + assert missing; + + return; + } + + if ( EntityLoadingLogger.DEBUG_ENABLED ) { + EntityLoadingLogger.INSTANCE.debugf( + "(%s) Hydrated EntityKey (%s): %s", + StringHelper.collapse( this.getClass().getName() ), + getNavigablePath(), + entityKey.getIdentifier() + ); + } + } + + private EntityPersister determineConcreteEntityDescriptor( + RowProcessingState rowProcessingState, + SharedSessionContractImplementor persistenceContext) throws WrongClassException { + if ( discriminatorAssembler == null ) { + return entityDescriptor; + } + + throw new NotYetImplementedFor6Exception( getClass() ); +// final Object discriminatorValue = discriminatorAssembler.assemble( +// rowProcessingState, +// rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions() +// ); +// +// final String result = entityDescriptor.getDiscriminatorDescriptor() +// .getDiscriminatorMappings() +// .discriminatorValueToEntityName( discriminatorValue ); +// +// if ( result == null ) { +// // oops - we got an instance of another class hierarchy branch +// throw new WrongClassException( +// "Discriminator: " + discriminatorValue, +// entityKey.getIdentifier(), +// entityDescriptor.getEntityName() +// ); +// } +// +// return persistenceContext.getFactory().getMetamodel().findEntityDescriptor( result ); + } + + @SuppressWarnings("WeakerAccess") + protected void initializeIdentifier(RowProcessingState rowProcessingState) { + identifierInitializers.forEach( initializer -> initializer.resolveKey( rowProcessingState ) ); + identifierInitializers.forEach( initializer -> initializer.resolveInstance( rowProcessingState ) ); + identifierInitializers.forEach( initializer -> initializer.initializeInstance( rowProcessingState ) ); + } + + @SuppressWarnings("WeakerAccess") + protected void resolveEntityKey(RowProcessingState rowProcessingState) { + if ( entityKey != null ) { + // its already been resolved + return; + } + + final SharedSessionContractImplementor session = rowProcessingState.getJdbcValuesSourceProcessingState().getSession(); + + // 1) resolve the hydrated identifier value(s) into its identifier representation + final Object id = identifierAssembler.assemble( rowProcessingState, rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions() ); + + if ( id == null ) { + missing = true; + // EARLY EXIT!!! + return; + } + + // 2) build the EntityKey + this.entityKey = new EntityKey( id, concreteDescriptor ); + + // 3) schedule the EntityKey for batch loading, if possible + if ( concreteDescriptor.isBatchLoadable() ) { + if ( !session.getPersistenceContext().containsEntity( entityKey ) ) { + session.getPersistenceContext().getBatchFetchQueue().addBatchLoadableEntityKey( entityKey ); + } + } + + // todo (6.0) : subselect fetches similar to batch fetch handling above + } + + @Override + public void resolveInstance(RowProcessingState rowProcessingState) { + if ( missing ) { + return; + } + + final Object entityIdentifier = entityKey.getIdentifier(); + + if ( EntityLoadingLogger.TRACE_ENABLED ) { + EntityLoadingLogger.INSTANCE.tracef( + "(%s) Beginning Initializer#resolveInstance process for entity (%s) : %s", + StringHelper.collapse( this.getClass().getName() ), + getNavigablePath(), + entityIdentifier + ); + } + + final SharedSessionContractImplementor session = rowProcessingState.getJdbcValuesSourceProcessingState().getSession(); + + // look to see if another initializer from a parent load context or an earlier + // initializer is already loading the entity + + final LoadingEntityEntry existingLoadingEntry = session.getPersistenceContext() + .getLoadContexts() + .findLoadingEntityEntry( entityKey ); + + if ( existingLoadingEntry != null ) { + if ( EntityLoadingLogger.DEBUG_ENABLED ) { + EntityLoadingLogger.INSTANCE.debugf( + "(%s) Found existing loading entry [%s] - using loading instance", + StringHelper.collapse( this.getClass().getName() ), + toLoggableString( getNavigablePath(), entityIdentifier ) + ); + } + + this.entityInstance = existingLoadingEntry.getEntityInstance(); + + if ( existingLoadingEntry.getEntityInitializer() != this ) { + // the entity is already being loaded elsewhere + if ( EntityLoadingLogger.DEBUG_ENABLED ) { + EntityLoadingLogger.INSTANCE.debugf( + "(%s) Entity [%s] being loaded by another initializer [%s] - skipping processing", + StringHelper.collapse( this.getClass().getName() ), + toLoggableString( getNavigablePath(), entityIdentifier ), + existingLoadingEntry.getEntityInitializer() + ); + } + + // EARLY EXIT!!! + return; + } + } + + if ( entityInstance == null ) { + // this isEntityReturn bit is just for entity loaders, not hql/criteria + if ( isEntityReturn() ) { + final Object requestedEntityId = rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions().getEffectiveOptionalId(); + if ( requestedEntityId != null && requestedEntityId.equals( entityKey.getIdentifier() ) ) { + entityInstance = rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions().getEffectiveOptionalObject(); + } + } + } + + if ( entityInstance == null ) { + // see if it is managed in the Session already + final Object entity = session.getPersistenceContext().getEntity( entityKey ); + if ( entity != null ) { + this.entityInstance = entity; + } + } + + if ( entityInstance == null ) { + entityInstance = session.instantiate( concreteDescriptor.getEntityName(), entityKey.getIdentifier() ); + + if ( EntityLoadingLogger.DEBUG_ENABLED ) { + EntityLoadingLogger.INSTANCE.debugf( + "Created new entity instance [%s] : %s", + toLoggableString( getNavigablePath(), entityIdentifier ), + entityInstance + ); + } + + final LoadingEntityEntry loadingEntry = new LoadingEntityEntry( + this, + entityKey, + concreteDescriptor, + entityInstance + ); + + rowProcessingState.getJdbcValuesSourceProcessingState().registerLoadingEntity( + entityKey, + loadingEntry + ); + + } + + notifyParentResolutionListeners( entityInstance ); + + preLoad( rowProcessingState ); + } + + @Override + public void initializeInstance(RowProcessingState rowProcessingState) { + if ( missing ) { + return; + } + + final Serializable entityIdentifier = entityKey.getIdentifier(); + + if ( EntityLoadingLogger.TRACE_ENABLED ) { + EntityLoadingLogger.INSTANCE.tracef( + "Beginning Initializer#initializeInstance process for entity %s", + toLoggableString( getNavigablePath(), entityIdentifier ) + ); + } + + final SharedSessionContractImplementor session = rowProcessingState.getJdbcValuesSourceProcessingState().getSession(); + PersistenceContext persistenceContext = session.getPersistenceContext(); + + // todo (6.0): do we really need this check ? + if ( persistenceContext.containsEntity( entityKey ) ) { + Status status = persistenceContext.getEntry( persistenceContext.getEntity( entityKey ) ) + .getStatus(); + if ( status == Status.DELETED || status == Status.GONE ) { + return; + } + } + final Object rowId = null; +// todo (6.0) : rowId +// final Object rowId; +// if ( concreteDescriptor.getHierarchy().getRowIdDescriptor() != null ) { +// rowId = ro sqlSelectionMappings.getRowIdSqlSelection().hydrateStateArray( rowProcessingState ); +// +// if ( rowId == null ) { +// throw new HibernateException( +// "Could not read entity row-id from JDBC : " + entityKey +// ); +// } +// } +// else { +// rowId = null; +// } + + + + entityDescriptor.setIdentifier( entityInstance, entityIdentifier, session ); + + resolvedEntityState = new Object[ assemblerMap.size() ]; + assemblerMap.forEach( + (key, value) -> resolvedEntityState[ key.getStateArrayPosition() ] = value.assemble( rowProcessingState ) + ); + + entityDescriptor.setPropertyValues( entityInstance, resolvedEntityState ); + + persistenceContext.addEntity( + entityKey, + entityInstance + ); + + final Object version; + if ( versionAssembler != null ) { + version = versionAssembler.assemble( rowProcessingState ); + } + else { + version = null; + } + + final EntityEntry entityEntry = persistenceContext.addEntry( + entityInstance, + Status.LOADING, + resolvedEntityState, + rowId, + entityKey.getIdentifier(), + version, + lockMode, + true, + entityDescriptor, + false + ); + + final SessionFactoryImplementor factory = session.getFactory(); + final EntityDataAccess cacheAccess = entityDescriptor.getCacheAccessStrategy(); + if ( cacheAccess != null && session.getCacheMode().isPutEnabled() ) { + + if ( EntityLoadingLogger.DEBUG_ENABLED ) { + EntityLoadingLogger.INSTANCE.debugf( + "Adding entityInstance to second-level cache: %s", + toLoggableString( getNavigablePath(), entityIdentifier ) + ); + } + + final CacheEntry entry = entityDescriptor.buildCacheEntry( entityInstance, resolvedEntityState, version, session ); + final Object cacheKey = cacheAccess.generateCacheKey( + entityIdentifier, + entityDescriptor, + factory, + session.getTenantIdentifier() + ); + + // explicit handling of caching for rows just inserted and then somehow forced to be read + // from the database *within the same transaction*. usually this is done by + // 1) Session#refresh, or + // 2) Session#clear + some form of load + // + // we need to be careful not to clobber the lock here in the cache so that it can be rolled back if need be + if ( persistenceContext.wasInsertedDuringTransaction( entityDescriptor, entityIdentifier ) ) { + cacheAccess.update( + session, + cacheKey, + entityDescriptor.getCacheEntryStructure().structure( entry ), + version, + version + ); + } + else { + final SessionEventListenerManager eventListenerManager = session.getEventListenerManager(); + try { + eventListenerManager.cachePutStart(); + final boolean put = cacheAccess.putFromLoad( + session, + cacheKey, + entityDescriptor.getCacheEntryStructure().structure( entry ), + version, + //useMinimalPuts( session, entityEntry ) + false + ); + + if ( put && factory.getStatistics().isStatisticsEnabled() ) { + factory.getStatistics().entityCachePut( entityDescriptor.getNavigableRole(), cacheAccess.getRegion().getName() ); + } + } + finally { + eventListenerManager.cachePutEnd(); + } + } + } + + if ( entityDescriptor.getNaturalIdMapping() != null ) { + persistenceContext.getNaturalIdHelper().cacheNaturalIdCrossReferenceFromLoad( + entityDescriptor, + entityIdentifier, + persistenceContext + .getNaturalIdHelper().extractNaturalIdValues( resolvedEntityState, entityDescriptor ) + ); + } + + boolean isReallyReadOnly = isReadOnly( rowProcessingState, session ); + if ( ! entityDescriptor.isMutable() ) { + isReallyReadOnly = true; + } + else { + final Object proxy = persistenceContext.getProxy( entityKey ); + if ( proxy != null ) { + // there is already a proxy for this impl + // only set the status to read-only if the proxy is read-only + isReallyReadOnly = ( (HibernateProxy) proxy ).getHibernateLazyInitializer().isReadOnly(); + } + } + if ( isReallyReadOnly ) { + //no need to take a snapshot - this is a + //performance optimization, but not really + //important, except for entities with huge + //mutable property values + persistenceContext.setEntryStatus( entityEntry, Status.READ_ONLY ); + } + else { + //take a snapshot + TypeHelper.deepCopy( + entityDescriptor, + resolvedEntityState, + resolvedEntityState, + attributeMapping -> attributeMapping.getAttributeMetadataAccess().resolveAttributeMetadata( concreteDescriptor ).isUpdatable() + ); + persistenceContext.setEntryStatus( entityEntry, Status.MANAGED ); + } + + entityDescriptor.afterInitialize( entityInstance, session ); + + if ( EntityLoadingLogger.DEBUG_ENABLED ) { + EntityLoadingLogger.INSTANCE.debugf( + "Done materializing entityInstance : %s", + toLoggableString( getNavigablePath(), entityIdentifier ) + ); + } + + if ( factory.getStatistics().isStatisticsEnabled() ) { + factory.getStatistics().loadEntity( entityDescriptor.getEntityName() ); + } + + postLoad( rowProcessingState ); + } + + private boolean isReadOnly( + RowProcessingState rowProcessingState, + SharedSessionContractImplementor persistenceContext) { + if ( persistenceContext.isDefaultReadOnly() ) { + return true; + } + + + final Boolean queryOption = rowProcessingState.getJdbcValuesSourceProcessingState().getQueryOptions().isReadOnly(); + + return queryOption == null ? false : queryOption; + } + + private void preLoad(RowProcessingState rowProcessingState) { + final SharedSessionContractImplementor session = rowProcessingState.getJdbcValuesSourceProcessingState().getSession(); + + final PreLoadEvent preLoadEvent = rowProcessingState.getJdbcValuesSourceProcessingState().getPreLoadEvent(); + preLoadEvent.reset(); + + // Must occur after resolving identifiers! + if ( session.isEventSource() ) { + preLoadEvent.setEntity( entityInstance ) + .setId( entityKey.getIdentifier() ) + .setPersister( concreteDescriptor ); + + final EventListenerGroup listenerGroup = session.getFactory() + .getServiceRegistry() + .getService( EventListenerRegistry.class ) + .getEventListenerGroup( EventType.PRE_LOAD ); + for ( PreLoadEventListener listener : listenerGroup.listeners() ) { + listener.onPreLoad( preLoadEvent ); + } + } + } + + private void postLoad(RowProcessingState rowProcessingState) { + final PostLoadEvent postLoadEvent = rowProcessingState.getJdbcValuesSourceProcessingState().getPostLoadEvent(); + postLoadEvent.reset(); + + postLoadEvent.setEntity( entityInstance ) + .setId( entityKey.getIdentifier() ) + .setPersister( concreteDescriptor ); + + final EventListenerGroup listenerGroup = entityDescriptor.getFactory() + .getServiceRegistry() + .getService( EventListenerRegistry.class ) + .getEventListenerGroup( EventType.POST_LOAD ); + for ( PostLoadEventListener listener : listenerGroup.listeners() ) { + listener.onPostLoad( postLoadEvent ); + } + } + + @Override + public void finishUpRow(RowProcessingState rowProcessingState) { + // reset row state + concreteDescriptor = null; + entityKey = null; + entityInstance = null; + missing = false; + resolvedEntityState = null; + + clearParentResolutionListeners(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/AbstractEntityMappingNode.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/AbstractEntityMappingNode.java new file mode 100644 index 0000000000..726a33d81a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/AbstractEntityMappingNode.java @@ -0,0 +1,139 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.internal.domain.entity; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.LockMode; +import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.EntityValuedModelPart; +import org.hibernate.metamodel.mapping.EntityVersionMapping; +import org.hibernate.query.NavigablePath; +import org.hibernate.sql.ast.tree.from.TableGroup; +import org.hibernate.sql.results.internal.domain.AbstractFetchParent; +import org.hibernate.sql.results.spi.DomainResult; +import org.hibernate.sql.results.spi.DomainResultCreationState; +import org.hibernate.sql.results.spi.EntityMappingNode; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractEntityMappingNode extends AbstractFetchParent implements EntityMappingNode { + private final EntityValuedModelPart referencedModelPart; + private final DomainResult identifierResult; + private final DomainResult discriminatorResult; + private final DomainResult versionResult; + private final LockMode lockMode; + + private final EntityMappingType targetType; + + private final List attributeDomainResults = new ArrayList<>(); + + public AbstractEntityMappingNode( + EntityValuedModelPart referencedModelPart, + LockMode lockMode, + NavigablePath navigablePath, + DomainResultCreationState creationState) { + this( referencedModelPart, lockMode, navigablePath, null, creationState ); + } + + public AbstractEntityMappingNode( + EntityValuedModelPart referencedModelPart, + LockMode lockMode, + NavigablePath navigablePath, + EntityMappingType targetType, + DomainResultCreationState creationState) { + super( referencedModelPart, navigablePath ); + this.referencedModelPart = referencedModelPart; + this.lockMode = lockMode; + this.targetType = targetType; + + final EntityMappingType entityDescriptor = referencedModelPart.getEntityMappingType(); + + final TableGroup entityTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess().findTableGroup( navigablePath ); + + identifierResult = entityDescriptor.getIdentifierMapping().createDomainResult( + navigablePath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME ), + entityTableGroup, + null, + creationState + ); + +// final DiscriminatorMappDescriptor discriminatorDescriptor = entityDescriptor.getHierarchy().getDiscriminatorDescriptor(); +// if ( discriminatorDescriptor == null ) { +// discriminatorResult = null; +// } +// else { +// discriminatorResult = discriminatorDescriptor.createDomainResult( +// navigablePath.append( DiscriminatorDescriptor.NAVIGABLE_NAME ), +// null, +// creationState +// ); +// } + discriminatorResult = null; + + final EntityVersionMapping versionDescriptor = entityDescriptor.getVersionMapping(); + if ( versionDescriptor == null ) { + versionResult = null; + } + else { + versionResult = versionDescriptor.createDomainResult( + navigablePath.append( versionDescriptor.getAttributeName() ), + entityTableGroup, + null, + creationState + ); + } + + entityDescriptor.visitAttributeMappings( + mapping -> attributeDomainResults.add( + mapping.createDomainResult( + navigablePath.append( mapping.getAttributeName() ), + entityTableGroup, + null, + creationState + ) + ) + ); + + // todo (6.0) : handle other special navigables such as discriminator, row-id, tenant-id, etc + } + + @Override + public EntityValuedModelPart getReferencedMappingContainer() { + return getEntityValuedModelPart(); + } + + @Override + public EntityValuedModelPart getEntityValuedModelPart() { + return referencedModelPart; + } + + @Override + public JavaTypeDescriptor getResultJavaTypeDescriptor() { + return getEntityValuedModelPart().getEntityMappingType().getMappedJavaTypeDescriptor(); + } + + public LockMode getLockMode() { + return lockMode; + } + + protected DomainResult getIdentifierResult() { + return identifierResult; + } + + protected DomainResult getDiscriminatorResult() { + return discriminatorResult; + } + + protected DomainResult getVersionResult() { + return versionResult; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityAssembler.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityAssembler.java new file mode 100644 index 0000000000..747c84b93f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityAssembler.java @@ -0,0 +1,38 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.internal.domain.entity; + +import org.hibernate.sql.results.spi.DomainResultAssembler; +import org.hibernate.sql.results.spi.EntityInitializer; +import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions; +import org.hibernate.sql.results.spi.RowProcessingState; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; + +/** + * @author Steve Ebersole + */ +public class EntityAssembler implements DomainResultAssembler { + private final JavaTypeDescriptor javaTypeDescriptor; + private final EntityInitializer initializer; + + public EntityAssembler( + JavaTypeDescriptor javaTypeDescriptor, + EntityInitializer initializer) { + this.javaTypeDescriptor = javaTypeDescriptor; + this.initializer = initializer; + } + + @Override + public JavaTypeDescriptor getAssembledJavaTypeDescriptor() { + return javaTypeDescriptor; + } + + @Override + public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) { + return initializer.getEntityInstance(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityLoadingLogger.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityLoadingLogger.java new file mode 100644 index 0000000000..10b5a95e13 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityLoadingLogger.java @@ -0,0 +1,35 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.internal.domain.entity; + +import org.hibernate.sql.results.SqlResultsLogger; + +import org.jboss.logging.BasicLogger; +import org.jboss.logging.Logger; +import org.jboss.logging.annotations.MessageLogger; +import org.jboss.logging.annotations.ValidIdRange; + +/** + * @author Steve Ebersole + */ +@MessageLogger( projectCode = "HHH" ) +@ValidIdRange( min = 90005201, max = 90005300 ) +public interface EntityLoadingLogger extends BasicLogger { + String LOGGER_NAME = SqlResultsLogger.LOGGER_NAME + "loading.entity"; + + /** + * Static access to the logging instance + */ + EntityLoadingLogger INSTANCE = Logger.getMessageLogger( + EntityLoadingLogger.class, + LOGGER_NAME + ); + + boolean TRACE_ENABLED = INSTANCE.isTraceEnabled(); + boolean DEBUG_ENABLED = INSTANCE.isDebugEnabled(); + boolean INFO_ENABLED = INSTANCE.isInfoEnabled(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityResultImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityResultImpl.java new file mode 100644 index 0000000000..fc6b9db60f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityResultImpl.java @@ -0,0 +1,82 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.internal.domain.entity; + +import java.util.function.Consumer; + +import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.EntityValuedModelPart; +import org.hibernate.query.NavigablePath; +import org.hibernate.sql.results.spi.AssemblerCreationState; +import org.hibernate.sql.results.spi.DomainResultAssembler; +import org.hibernate.sql.results.spi.DomainResultCreationState; + +import org.hibernate.sql.results.spi.EntityResult; +import org.hibernate.sql.results.spi.Initializer; + +/** + * Standard ReturnEntity impl + * + * @author Steve Ebersole + */ +public class EntityResultImpl extends AbstractEntityMappingNode implements EntityResult { + private final String resultVariable; + + + + public EntityResultImpl( + NavigablePath navigablePath, + EntityValuedModelPart entityValuedModelPart, + String resultVariable, + DomainResultCreationState creationState) { + this( navigablePath, entityValuedModelPart, resultVariable, null, creationState ); + } + + public EntityResultImpl( + NavigablePath navigablePath, + EntityValuedModelPart entityValuedModelPart, + String resultVariable, + EntityMappingType targetType, + DomainResultCreationState creationState) { + super( + entityValuedModelPart, + creationState.getSqlAstCreationState().determineLockMode( resultVariable ), + navigablePath, + creationState + ); + + this.resultVariable = resultVariable; + + afterInitialize( creationState ); + } + + @Override + public String getResultVariable() { + return resultVariable; + } + + @Override + public DomainResultAssembler createResultAssembler( + Consumer initializerCollector, + AssemblerCreationState creationState) { + // todo (6.0) : seems like here is where we ought to determine the SQL selection mappings + + final EntityRootInitializer initializer = new EntityRootInitializer( + this, + getNavigablePath(), + getLockMode(), + getIdentifierResult(), + getDiscriminatorResult(), + getVersionResult(), + initializerCollector, + creationState + ); + + return new EntityAssembler( getResultJavaTypeDescriptor(), initializer ); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityRootInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityRootInitializer.java new file mode 100644 index 0000000000..9c10d24856 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/entity/EntityRootInitializer.java @@ -0,0 +1,54 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.internal.domain.entity; + +import java.util.function.Consumer; + +import org.hibernate.LockMode; +import org.hibernate.query.NavigablePath; +import org.hibernate.sql.results.spi.AssemblerCreationState; +import org.hibernate.sql.results.spi.DomainResult; +import org.hibernate.sql.results.spi.EntityMappingNode; +import org.hibernate.sql.results.spi.Initializer; + +/** + * Initializer for cases where the entity is a root domain selection + * + * @author Steve Ebersole + */ +public class EntityRootInitializer extends AbstractEntityInitializer { + public EntityRootInitializer( + EntityMappingNode resultDescriptor, + NavigablePath navigablePath, + LockMode lockMode, + DomainResult identifierResult, + DomainResult discriminatorResult, + DomainResult versionResult, + Consumer initializerConsumer, + AssemblerCreationState creationState) { + super( + resultDescriptor, + navigablePath, + lockMode, + identifierResult, + discriminatorResult, + versionResult, + initializerConsumer, + creationState + ); + } + + @Override + protected boolean isEntityReturn() { + return true; + } + + @Override + public String toString() { + return "EntityRootInitializer(" + getNavigablePath().getFullPath() + ")"; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/ArgumentDomainResult.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/ArgumentDomainResult.java similarity index 94% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/ArgumentDomainResult.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/ArgumentDomainResult.java index cb7beee855..2168778d49 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/ArgumentDomainResult.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/ArgumentDomainResult.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import java.util.function.Consumer; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/ArgumentReader.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/ArgumentReader.java similarity index 95% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/ArgumentReader.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/ArgumentReader.java index bd35b2b210..a2ae7c9f1b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/ArgumentReader.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/ArgumentReader.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import org.hibernate.sql.results.spi.DomainResultAssembler; import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjection.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjection.java similarity index 92% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjection.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjection.java index abcfdae267..413ef44d38 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjection.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjection.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import org.hibernate.sql.results.spi.DomainResultAssembler; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjector.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjector.java similarity index 88% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjector.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjector.java index 532f1ffebc..7af4dcebd4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjector.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjector.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; /** * Unified contract for injecting a single argument for a dynamic instantiation diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjectorField.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjectorField.java similarity index 91% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjectorField.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjectorField.java index 9c478c5c47..e90c59453b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjectorField.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjectorField.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import java.lang.reflect.Field; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjectorSetter.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjectorSetter.java similarity index 93% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjectorSetter.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjectorSetter.java index 9aa9bdd8ed..caa130e083 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/BeanInjectorSetter.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/BeanInjectorSetter.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiation.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiation.java similarity index 99% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiation.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiation.java index a08e6451c1..7678ab224a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiation.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiation.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import java.lang.reflect.Constructor; import java.util.ArrayList; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationArgument.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationArgument.java similarity index 93% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationArgument.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationArgument.java index dd62611acd..feb8a29ef6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationArgument.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationArgument.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import org.hibernate.query.sqm.sql.internal.DomainResultProducer; import org.hibernate.sql.results.spi.DomainResultCreationState; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationAssembler.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationAssembler.java similarity index 94% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationAssembler.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationAssembler.java index f2567dd57a..1ff6742dd3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationAssembler.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationAssembler.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import java.util.List; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationConstructorAssemblerImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationConstructorAssemblerImpl.java similarity index 97% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationConstructorAssemblerImpl.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationConstructorAssemblerImpl.java index 190e4a9bc6..e749c9f66a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationConstructorAssemblerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationConstructorAssemblerImpl.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationInjectionAssemblerImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationInjectionAssemblerImpl.java similarity index 98% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationInjectionAssemblerImpl.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationInjectionAssemblerImpl.java index eadbf40870..66dba3d8ac 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationInjectionAssemblerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationInjectionAssemblerImpl.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationListAssemblerImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationListAssemblerImpl.java similarity index 96% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationListAssemblerImpl.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationListAssemblerImpl.java index 92bc4aceb8..12aa9ba6f9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationListAssemblerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationListAssemblerImpl.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import java.util.ArrayList; import java.util.List; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationMapAssemblerImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationMapAssemblerImpl.java similarity index 97% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationMapAssemblerImpl.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationMapAssemblerImpl.java index de3dcec0d8..c86e7a576a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationMapAssemblerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationMapAssemblerImpl.java @@ -5,7 +5,7 @@ * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import java.util.HashMap; import java.util.HashSet; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationResult.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationResultImpl.java similarity index 95% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationResult.java rename to hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationResultImpl.java index 1337509426..24022cedf3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/instantiation/DynamicInstantiationResult.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/instantiation/DynamicInstantiationResultImpl.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.query.sqm.sql.internal.instantiation; +package org.hibernate.sql.results.internal.domain.instantiation; import java.lang.reflect.Constructor; import java.util.ArrayList; @@ -17,8 +17,8 @@ import org.hibernate.internal.util.StringHelper; import org.hibernate.query.DynamicInstantiationNature; import org.hibernate.query.sqm.tree.expression.Compatibility; import org.hibernate.sql.results.spi.AssemblerCreationState; -import org.hibernate.sql.results.spi.DomainResult; import org.hibernate.sql.results.spi.DomainResultAssembler; +import org.hibernate.sql.results.spi.DynamicInstantiationResult; import org.hibernate.sql.results.spi.Initializer; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @@ -27,8 +27,8 @@ import org.jboss.logging.Logger; /** * @author Steve Ebersole */ -public class DynamicInstantiationResult implements DomainResult { - private static final Logger log = Logger.getLogger( DynamicInstantiationResult.class ); +public class DynamicInstantiationResultImpl implements DynamicInstantiationResult { + private static final Logger log = Logger.getLogger( DynamicInstantiationResultImpl.class ); private final String resultVariable; @@ -36,7 +36,7 @@ public class DynamicInstantiationResult implements DomainResult { private final JavaTypeDescriptor javaTypeDescriptor; private final List argumentResults; - public DynamicInstantiationResult( + public DynamicInstantiationResultImpl( String resultVariable, DynamicInstantiationNature nature, JavaTypeDescriptor javaTypeDescriptor, diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/DomainResult.java b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/DomainResult.java index 35aa7f107f..15681cb72b 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/DomainResult.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/DomainResult.java @@ -22,7 +22,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; * QueryResult is distinctly different from a {@link Fetch} and so modeled as * completely separate hierarchy. * - * @see ScalarResult + * @see ScalarDomainResult * @see DynamicInstantiationResult * @see EntityResult * @see CollectionResult diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/DynamicInstantiationResult.java b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/DynamicInstantiationResult.java new file mode 100644 index 0000000000..aa3de946a6 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/DynamicInstantiationResult.java @@ -0,0 +1,13 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.spi; + +/** + * @author Steve Ebersole + */ +public interface DynamicInstantiationResult extends DomainResult { +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/EntityMappingNode.java b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/EntityMappingNode.java new file mode 100644 index 0000000000..2dd2391b8e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/EntityMappingNode.java @@ -0,0 +1,33 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.spi; + +import org.hibernate.metamodel.mapping.EntityValuedModelPart; +import org.hibernate.query.NavigablePath; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; + +/** + * Represents a reference to an entity either as a return, fetch, or collection element or index. + * + * @author Steve Ebersole + */ +public interface EntityMappingNode extends ResultSetMappingNode, FetchParent { + @Override + NavigablePath getNavigablePath(); + + EntityValuedModelPart getEntityValuedModelPart(); + + @Override + default JavaTypeDescriptor getResultJavaTypeDescriptor() { + return getEntityValuedModelPart().getEntityMappingType().getMappedJavaTypeDescriptor(); + } + + @Override + default EntityValuedModelPart getReferencedMappingContainer() { + return getEntityValuedModelPart(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/EntityResult.java b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/EntityResult.java new file mode 100644 index 0000000000..9fd89f84b4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/EntityResult.java @@ -0,0 +1,19 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.spi; + +import org.hibernate.metamodel.mapping.EntityValuedModelPart; + +/** + * Further defines a first-level Return that is a reference to an entity + * + * @author Steve Ebersole + */ +public interface EntityResult extends EntityMappingNode, DomainResult { + @Override + EntityValuedModelPart getReferencedMappingContainer(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/Fetch.java b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/Fetch.java index 19e045e433..c803e9b95b 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/Fetch.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/Fetch.java @@ -40,7 +40,7 @@ public interface Fetch { /** * The value mapping being fetched */ - ModelPart getFetchedMapping(); + Fetchable getFetchedMapping(); /** * Get the property path to this fetch diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/FetchParent.java b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/FetchParent.java index 17b6e711eb..b6f360b366 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/FetchParent.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/FetchParent.java @@ -27,4 +27,6 @@ public interface FetchParent { * Retrieve the fetches owned by this fetch source. */ List getFetches(); + + Fetch findFetch(String fetchableName); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/FetchableContainer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/FetchableContainer.java index 5a9506ffbf..df9f10f24d 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/FetchableContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/FetchableContainer.java @@ -8,6 +8,7 @@ package org.hibernate.sql.results.spi; import java.util.function.Consumer; +import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ModelPartContainer; /** @@ -18,10 +19,17 @@ public interface FetchableContainer extends ModelPartContainer { return (Fetchable) findSubPart( name ); } - default void visitKeyFetchables(Consumer fetchableConsumer) { + default void visitKeyFetchables( + Consumer fetchableConsumer, + EntityMappingType treatTargetType) { // by default, nothing to do } - void visitFetchables(Consumer fetchableConsumer); + default void visitFetchables( + Consumer fetchableConsumer, + EntityMappingType treatTargetType) { + //noinspection unchecked + visitSubParts( (Consumer) fetchableConsumer ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java index 5de7424fa8..dddb5101c6 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java @@ -36,7 +36,10 @@ import org.hibernate.property.access.spi.Getter; * @see org.hibernate.tuple.component.ComponentTuplizer * * @author Steve Ebersole + * + * @deprecated See {@link org.hibernate.metamodel.spi.ManagedTypeRepresentationStrategy} */ +@Deprecated public interface Tuplizer { /** * Extract the current values contained on the given entity. diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java index 104c35362b..d6e43bbed8 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java @@ -125,8 +125,6 @@ public class EntityMetamodel implements Serializable { private final Set subclassEntityNames = new HashSet(); private final Map entityNameByInheritenceClassMap = new HashMap(); - private final EntityMode entityMode; - private final EntityTuplizer entityTuplizer; private final BytecodeEnhancementMetadata bytecodeEnhancementMetadata; public EntityMetamodel( @@ -410,16 +408,6 @@ public class EntityMetamodel implements Serializable { entityNameByInheritenceClassMap.put( pc.getMappedClass(), pc.getEntityName() ); } } - - entityMode = persistentClass.hasPojoRepresentation() ? EntityMode.POJO : EntityMode.MAP; - final EntityTuplizerFactory entityTuplizerFactory = sessionFactory.getSessionFactoryOptions().getEntityTuplizerFactory(); - final String tuplizerClassName = persistentClass.getTuplizerImplClassName( entityMode ); - if ( tuplizerClassName == null ) { - entityTuplizer = entityTuplizerFactory.constructDefaultTuplizer( entityMode, this, persistentClass ); - } - else { - entityTuplizer = entityTuplizerFactory.constructTuplizer( tuplizerClassName, this, persistentClass ); - } } private static GenerationStrategyPair buildGenerationStrategyPair( @@ -768,10 +756,6 @@ public class EntityMetamodel implements Serializable { } } - public EntityTuplizer getTuplizer() { - return entityTuplizer; - } - public boolean isNaturalIdentifierInsertGenerated() { // the intention is for this call to replace the usage of the old ValueInclusion stuff (as exposed from // persister) in SelectGenerator to determine if it is safe to use the natural identifier to find the @@ -1036,10 +1020,6 @@ public class EntityMetamodel implements Serializable { return inDatabaseValueGenerationStrategies; } - public EntityMode getEntityMode() { - return entityMode; - } - /** * Whether or not this class can be lazy (ie intercepted) */ diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java index f9a79e2e8c..17cd1ceb11 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java @@ -28,7 +28,10 @@ import org.hibernate.tuple.Tuplizer; * * @author Gavin King * @author Steve Ebersole + * + * @deprecated See {@link org.hibernate.metamodel.spi.EntityRepresentationStrategy} */ +@Deprecated public interface EntityTuplizer extends Tuplizer { /** * Return the entity-mode handled by this tuplizer instance. diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java index 57c61115c8..2d8f4c1423 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java @@ -315,6 +315,7 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer { @Override public EntityNameResolver[] getEntityNameResolvers() { + // the fallback is to check class name which is exactly what we'd do here return null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java b/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java index 4e34b1bfcd..cf7f762391 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java @@ -6,15 +6,19 @@ */ package org.hibernate.type; +import java.io.Serializable; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Predicate; + import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.util.collections.ArrayHelper; +import org.hibernate.metamodel.mapping.ManagedMappingType; +import org.hibernate.metamodel.mapping.StateArrayContributorMapping; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; import org.hibernate.tuple.NonIdentifierAttribute; -import java.io.Serializable; -import java.util.Map; - /** * Collection of convenience methods relating to operations across arrays of types... * @@ -30,6 +34,47 @@ public class TypeHelper { private TypeHelper() { } + public static final BiFunction DEEP_COPY_VALUE_PRODUCER = (navigable, sourceValue) -> { + if ( sourceValue == LazyPropertyInitializer.UNFETCHED_PROPERTY + || sourceValue == PropertyAccessStrategyBackRefImpl.UNKNOWN ) { + return sourceValue; + } + else { + return navigable.getAttributeMetadataAccess().resolveAttributeMetadata( null ).getMutabilityPlan().deepCopy( sourceValue ); + } + }; + + @SuppressWarnings("unchecked") + public static void deepCopy( + ManagedMappingType containerDescriptor, + Object[] source, + Object[] target, + Predicate copyConditions) { + deepCopy( + containerDescriptor, + source, + target, + copyConditions, + DEEP_COPY_VALUE_PRODUCER + ); + } + + public static void deepCopy( + ManagedMappingType containerDescriptor, + Object[] source, + Object[] target, + Predicate copyConditions, + BiFunction targetValueProducer) { + containerDescriptor.visitStateArrayContributors( + contributor -> { + if ( copyConditions.test( contributor ) ) { + final int position = contributor.getStateArrayPosition(); + target[position] = targetValueProducer.apply( contributor, source[position] ); + } + } + ); + } + /** * Deep copy a series of values from one array to another... * diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java index a19882401a..32687e8fe9 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java @@ -44,9 +44,12 @@ import org.hibernate.mapping.PersistentClass; import org.hibernate.metadata.ClassMetadata; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityVersionMapping; +import org.hibernate.metamodel.mapping.NaturalIdMapping; import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess; import org.hibernate.metamodel.model.domain.NavigableRole; +import org.hibernate.metamodel.spi.EntityRepresentationStrategy; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.MultiLoadOptions; @@ -615,6 +618,11 @@ public class PersisterClassProviderTest { return null; } + @Override + public EntityRepresentationStrategy getRepresentationStrategy() { + return null; + } + @Override public FilterAliasGenerator getFilterAliasGenerator(String rootAlias) { return null; @@ -685,6 +693,16 @@ public class PersisterClassProviderTest { return null; } + @Override + public NaturalIdMapping getNaturalIdMapping() { + return null; + } + + @Override + public boolean isTypeOrSuperType(EntityMappingType targetType) { + return targetType == this; + } + @Override public java.util.Collection getAttributeMappings() { return null; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/ast/SmokeTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/ast/SmokeTests.java index ec059c7b48..542dbcbb59 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/ast/SmokeTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/ast/SmokeTests.java @@ -236,4 +236,24 @@ public class SmokeTests { } ); } + + @Test + public void testSelectRootHqlExecution(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + final QueryImplementor query = session.createQuery( "select e from SimpleEntity e", SimpleEntity.class ); + query.list(); + } + ); + } + + @Test + public void testBadQueryResultType(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + final QueryImplementor query = session.createQuery( "select e from SimpleEntity e", Gender.class ); + query.list(); + } + ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/access/xml/XmlAccessTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/access/xml/XmlAccessTest.java index ac3b150841..2d8a058433 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/access/xml/XmlAccessTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/access/xml/XmlAccessTest.java @@ -15,6 +15,7 @@ import javax.persistence.AccessType; import org.hibernate.cfg.Configuration; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.property.access.spi.Getter; import org.hibernate.property.access.spi.GetterFieldImpl; import org.hibernate.property.access.spi.GetterMethodImpl; import org.hibernate.tuple.entity.EntityTuplizer; @@ -178,19 +179,21 @@ public class XmlAccessTest extends BaseUnitTestCase { // uses the first getter of the tupelizer for the assertions private void assertAccessType(SessionFactoryImplementor factory, Class classUnderTest, AccessType accessType) { - EntityTuplizer tuplizer = factory.getEntityPersister( classUnderTest.getName() ) - .getEntityMetamodel() - .getTuplizer(); + final Getter idGetter = factory.getDomainModel().findEntityDescriptor( classUnderTest.getName() ) + .getIdentifierMapping() + .getPropertyAccess() + .getGetter(); + if ( AccessType.FIELD.equals( accessType ) ) { Assert.assertTrue( "Field access was expected.", - tuplizer.getGetter( 0 ) instanceof GetterFieldImpl + idGetter instanceof GetterFieldImpl ); } else { Assert.assertTrue( "Property access was expected.", - tuplizer.getGetter( 0 ) instanceof GetterMethodImpl + idGetter instanceof GetterMethodImpl ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java index 8271a9e9ba..c81e1b684b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java @@ -43,9 +43,12 @@ import org.hibernate.metadata.ClassMetadata; import org.hibernate.metadata.CollectionMetadata; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityVersionMapping; +import org.hibernate.metamodel.mapping.NaturalIdMapping; import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess; import org.hibernate.metamodel.model.domain.NavigableRole; +import org.hibernate.metamodel.spi.EntityRepresentationStrategy; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.MultiLoadOptions; @@ -626,6 +629,21 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver { return null; } + @Override + public NaturalIdMapping getNaturalIdMapping() { + return null; + } + + @Override + public boolean isTypeOrSuperType(EntityMappingType targetType) { + return targetType == this; + } + + @Override + public EntityRepresentationStrategy getRepresentationStrategy() { + return null; + } + @Override public EntityIdentifierDefinition getEntityKeyDefinition() { return null; //To change body of implemented methods use File | Settings | File Templates. diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java index e3341b5276..5f0840d50a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java @@ -48,9 +48,12 @@ import org.hibernate.mapping.PersistentClass; import org.hibernate.metadata.ClassMetadata; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityVersionMapping; +import org.hibernate.metamodel.mapping.NaturalIdMapping; import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess; import org.hibernate.metamodel.model.domain.NavigableRole; +import org.hibernate.metamodel.spi.EntityRepresentationStrategy; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.MultiLoadOptions; import org.hibernate.persister.spi.PersisterCreationContext; @@ -738,6 +741,21 @@ public class CustomPersister implements EntityPersister { return null; } + @Override + public NaturalIdMapping getNaturalIdMapping() { + return null; + } + + @Override + public boolean isTypeOrSuperType(EntityMappingType targetType) { + return targetType == this; + } + + @Override + public EntityRepresentationStrategy getRepresentationStrategy() { + return null; + } + @Override public EntityIdentifierDefinition getEntityKeyDefinition() { throw new NotYetImplementedException(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/access/jpa/AccessMappingTest.java b/hibernate-core/src/test_legacy/org/hibernate/test/annotations/access/jpa/AccessMappingTest.java similarity index 100% rename from hibernate-core/src/test/java/org/hibernate/test/annotations/access/jpa/AccessMappingTest.java rename to hibernate-core/src/test_legacy/org/hibernate/test/annotations/access/jpa/AccessMappingTest.java diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/boot/BootstrapContextImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/boot/BootstrapContextImpl.java index b8576344c3..0e172a8f36 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/boot/BootstrapContextImpl.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/boot/BootstrapContextImpl.java @@ -25,6 +25,8 @@ import org.hibernate.boot.spi.ClassLoaderAccess; import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.dialect.function.SQLFunction; import org.hibernate.jpa.spi.MutableJpaCompliance; +import org.hibernate.metamodel.internal.StandardManagedTypeRepresentationResolver; +import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver; import org.hibernate.type.spi.TypeConfiguration; import org.jboss.jandex.IndexView; @@ -143,4 +145,9 @@ public class BootstrapContextImpl implements BootstrapContext { public void release() { delegate.release(); } + + @Override + public ManagedTypeRepresentationResolver getRepresentationStrategySelector() { + return StandardManagedTypeRepresentationResolver.INSTANCE; + } }