Initial working support for selecting a "query root" - i.e. `select e from TheEntity e`

This commit is contained in:
Steve Ebersole 2019-09-11 13:41:17 -05:00 committed by Andrea Boriero
parent a4e4cb7260
commit 76b42a94c3
103 changed files with 3136 additions and 269 deletions

View File

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

View File

@ -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 <tt>null</tt> 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 <tt>null</tt> 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 <tt>null</tt> 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.
*

View File

@ -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<AuxiliaryDatabaseObject> auxiliaryDatabaseObjectList;
private HashMap<Class, ConverterDescriptor> attributeConverterDescriptorMap;
private ArrayList<CacheRegionDefinition> 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 ) {

View File

@ -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 = "<null>";
private static final String UNREFERENCED = "<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()
);
}
}

View File

@ -212,4 +212,10 @@ public final class CollectionHelper {
public static boolean isEmpty(Object[] objects) {
return objects == null || objects.length == 0;
}
public static <T> Set<T> setOf(T... values) {
final HashSet<T> set = new HashSet<>( determineProperSizing( values.length ) );
Collections.addAll( set, values );
return set;
}
}

View File

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

View File

@ -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,

View File

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

View File

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

View File

@ -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(

View File

@ -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<Map> mapJtd;
private final ProxyFactory proxyFactory;
private final DynamicMapInstantiator instantiator;
private final Map<String, PropertyAccess> 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<Property> 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 <J> Instantiator<J> 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<EntityNameResolver> consumer) {
consumer.accept( DynamicMapInstantiator.ENTITY_NAME_RESOLVER );
}
}

View File

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

View File

@ -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<String, PropertyAccess> 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 <J> Instantiator<J> 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<Class> 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<Subclass> 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<String> getterNames = new ArrayList<>();
final List<String> setterNames = new ArrayList<>();
final List<Class> getterTypes = new ArrayList<>();
boolean foundCustomAccessor = false;
//noinspection unchecked
final Iterator<Property> 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() );
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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<AttributeMapping> action, EntityMappingType targetType) {
getAttributeMappings().forEach( action );
}
/**
* Walk this type's attributes as well as its sub-type's
*/
default void visitSubTypeAttributeMappings(Consumer<AttributeMapping> action) {
// by default do nothing
}
/**
* Walk this type's attributes as well as its super-type's
*/
default void visitSuperTypeAttributeMappings(Consumer<AttributeMapping> action) {
// by default do nothing
}
@Override
default void visitAttributeMappings(Consumer<AttributeMapping> 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<StateArrayContributorMapping> 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<StateArrayContributorMapping> 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<ModelPart> consumer);
//
// /**
// * Same purpose as {@link #visitSubParts} except that this form limits
// * the visitation to just this type and its super types.
// */
// void visitSubPartsStrictly(Consumer<ModelPart> action);
}

View File

@ -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<ModelPart> consumer) {
getEntityMappingType().visitSubParts( consumer );
}
@Override
default <T> DomainResult<T> 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<JdbcMapping> 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 );
}
}

View File

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

View File

@ -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<AttributeMapping> 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<AttributeMapping> 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<StateArrayContributorMapping> mappingConsumer) {
visitAttributeMappings(
modelPart -> {
if ( modelPart instanceof StateArrayContributorMapping ) {
mappingConsumer.accept( ( (StateArrayContributorMapping) modelPart ) );
}
}
);
}
boolean isTypeOrSuperType(ManagedMappingType targetType);
}

View File

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

View File

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

View File

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

View File

@ -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<ModelPart> consumer, EntityMappingType treatTargetType);
}

View File

@ -9,5 +9,5 @@ package org.hibernate.metamodel.mapping;
/**
* @author Steve Ebersole
*/
public interface SingularAttributeMapping extends AttributeMapping {
public interface SingularAttributeMapping extends AttributeMapping, StateArrayContributorMapping {
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<EntityNameResolver> 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<EntityNameResolver> entityNameResolvers) {
EntityNameResolver[] resolvers = tuplizer.getEntityNameResolvers();
if ( resolvers == null ) {
return;
}
for ( EntityNameResolver resolver : resolvers ) {
entityNameResolvers.add( resolver );
}
representationStrategy.visitEntityNameResolvers( entityNameResolvers::add );
}
@Override

View File

@ -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.
*/
<J> Instantiator<J> 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<EntityNameResolver> consumer) {
// byt default do nothing
}
}

View File

@ -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
*/

View File

@ -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 <T> DomainResult<T> 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<ModelPart> consumer) {
consumer.accept( entityIdentifierDefinition );
public void visitSubParts(
Consumer<ModelPart> 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<Fetchable> 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<Fetchable> fetchableConsumer,
EntityMappingType treatTargetType) {
visitStateArrayContributors(
mapping -> {
if ( mapping.isDeclaredOnTypeOrSuperType( treatTargetType ) ) {
fetchableConsumer.accept( mapping );
}
},
treatTargetType
);
}
@Override
public void visitStateArrayContributors(
Consumer<StateArrayContributorMapping> mappingConsumer,
EntityMappingType targetType) {
visitAttributeMappings(
attributeMapping -> {
if ( attributeMapping instanceof StateArrayContributorMapping ) {
mappingConsumer.accept( (StateArrayContributorMapping) attributeMapping );
}
},
targetType
);
}
@Override
public void visitAttributeMappings(
Consumer<AttributeMapping> action,
EntityMappingType targetType) {
visitSuperTypeAttributeMappings( action );
declaredAttributeMappings.values().forEach( action );
if ( targetType == null ) {
visitSubTypeAttributeMappings( action );
}
}
@Override
public void visitSuperTypeAttributeMappings(Consumer<AttributeMapping> action) {
if ( superMappingType != null ) {
superMappingType.visitSuperTypeAttributeMappings( action );
}
}
@Override
public void visitSubTypeAttributeMappings(Consumer<AttributeMapping> 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<Object> 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<String, EntityMappingType> subclassMappingTypes;
private EntityIdentifierMapping identifierMapping;
private NaturalIdMapping naturalIdMapping;
private EntityVersionMapping versionMapping;
private SortedMap<String, AttributeMapping> 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<AttributeMapping> action) {
throw new NotYetImplementedFor6Exception( getClass() );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// EntityDefinition impl (walking model - deprecated)

View File

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

View File

@ -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 {
/**

View File

@ -10,5 +10,5 @@ package org.hibernate.persister.walking.spi;
* @author Steve Ebersole
*/
public interface EncapsulatedEntityIdentifierDefinition extends EntityIdentifierDefinition {
public AttributeDefinition getAttributeDefinition();
AttributeDefinition getAttributeDefinition();
}

View File

@ -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?
*

View File

@ -64,5 +64,4 @@ public interface ProxyFactory {
* proxy.
*/
HibernateProxy getProxy(Serializable id, SharedSessionContractImplementor session) throws HibernateException;
}

View File

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

View File

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

View File

@ -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<R>
SharedSessionContractImplementor producer) {
super( producer );
SqmUtil.verifyIsSelectStatement( sqmStatement );
checkQueryReturnType( (SqmSelectStatement<R>) 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<R>
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, producer.getFactory() );
}
private static <T> void checkQueryReturnType(SqmSelectStatement<T> sqm, Class<T> resultClass, SessionFactoryImplementor sessionFactory) {
if ( resultClass == null ) {
// nothing to check
return;
}
final List<SqmSelection> 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<R>
}
@Override
@SuppressWarnings("unchecked")
protected List<R> doList() {
SqmUtil.verifyIsSelectStatement( getSqmStatement() );
getSession().prepareForQueryExecution( requiresTxn( getLockOptions().findGreatestLockMode() ) );

View File

@ -481,6 +481,8 @@ public class BaseSemanticQueryWalker implements SemanticQueryWalker<Object> {
@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();
}

View File

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

View File

@ -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<T, S extends T> extends SqmRoot<S> implements SqmTre
return wrappedPath.getLhs();
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitTreatedPath( this );
}
}

View File

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

View File

@ -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<T> implements RowReader<T> {
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 );
}

View File

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

View File

@ -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<Consumer<Object>> listeners;
@Override
public void registerResolutionListener(Consumer<Object> 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<Object> listener : listeners ) {
listener.accept( parentInstance );
}
}
}

View File

@ -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<Initializer> identifierInitializers = new ArrayList<>();
private final DomainResultAssembler identifierAssembler;
private final DomainResultAssembler discriminatorAssembler;
private final DomainResultAssembler versionAssembler;
private final Map<StateArrayContributorMapping, DomainResultAssembler> 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<Initializer> 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<PreLoadEventListener> 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<PostLoadEventListener> 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();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<R> implements DomainResult<R> {
private static final Logger log = Logger.getLogger( DynamicInstantiationResult.class );
public class DynamicInstantiationResultImpl<R> implements DynamicInstantiationResult<R> {
private static final Logger log = Logger.getLogger( DynamicInstantiationResultImpl.class );
private final String resultVariable;
@ -36,7 +36,7 @@ public class DynamicInstantiationResult<R> implements DomainResult<R> {
private final JavaTypeDescriptor<R> javaTypeDescriptor;
private final List<ArgumentDomainResult> argumentResults;
public DynamicInstantiationResult(
public DynamicInstantiationResultImpl(
String resultVariable,
DynamicInstantiationNature nature,
JavaTypeDescriptor<R> javaTypeDescriptor,

View File

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

View File

@ -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<R> extends DomainResult<R> {
}

View File

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

View File

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

View File

@ -40,7 +40,7 @@ public interface Fetch {
/**
* The value mapping being fetched
*/
ModelPart getFetchedMapping();
Fetchable getFetchedMapping();
/**
* Get the property path to this fetch

View File

@ -27,4 +27,6 @@ public interface FetchParent {
* Retrieve the fetches owned by this fetch source.
*/
List<Fetch> getFetches();
Fetch findFetch(String fetchableName);
}

View File

@ -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<Fetchable> fetchableConsumer) {
default void visitKeyFetchables(
Consumer<Fetchable> fetchableConsumer,
EntityMappingType treatTargetType) {
// by default, nothing to do
}
void visitFetchables(Consumer<Fetchable> fetchableConsumer);
default void visitFetchables(
Consumer<Fetchable> fetchableConsumer,
EntityMappingType treatTargetType) {
//noinspection unchecked
visitSubParts( (Consumer) fetchableConsumer );
}
}

View File

@ -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.

View File

@ -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)
*/

View File

@ -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.

View File

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

View File

@ -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<StateArrayContributorMapping,Object,Object> DEEP_COPY_VALUE_PRODUCER = (navigable, sourceValue) -> {
if ( sourceValue == LazyPropertyInitializer.UNFETCHED_PROPERTY
|| sourceValue == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
return sourceValue;
}
else {
return navigable.getAttributeMetadataAccess().resolveAttributeMetadata( null ).getMutabilityPlan().deepCopy( sourceValue );
}
};
@SuppressWarnings("unchecked")
public static void deepCopy(
ManagedMappingType containerDescriptor,
Object[] source,
Object[] target,
Predicate<StateArrayContributorMapping> copyConditions) {
deepCopy(
containerDescriptor,
source,
target,
copyConditions,
DEEP_COPY_VALUE_PRODUCER
);
}
public static void deepCopy(
ManagedMappingType containerDescriptor,
Object[] source,
Object[] target,
Predicate<StateArrayContributorMapping> copyConditions,
BiFunction<StateArrayContributorMapping, Object, Object> targetValueProducer) {
containerDescriptor.visitStateArrayContributors(
contributor -> {
if ( copyConditions.test( contributor ) ) {
final int position = contributor.getStateArrayPosition();
target[position] = targetValueProducer.apply( contributor, source[position] );
}
}
);
}
/**
* Deep copy a series of values from one array to another...
*

View File

@ -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<AttributeMapping> getAttributeMappings() {
return null;

View File

@ -236,4 +236,24 @@ public class SmokeTests {
}
);
}
@Test
public void testSelectRootHqlExecution(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<SimpleEntity> query = session.createQuery( "select e from SimpleEntity e", SimpleEntity.class );
query.list();
}
);
}
@Test
public void testBadQueryResultType(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<Gender> query = session.createQuery( "select e from SimpleEntity e", Gender.class );
query.list();
}
);
}
}

View File

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

View File

@ -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.

Some files were not shown because too many files have changed in this diff Show More