Initial working support for selecting a "query root" - i.e. `select e from TheEntity e`
This commit is contained in:
parent
a4e4cb7260
commit
76b42a94c3
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -9,5 +9,5 @@ package org.hibernate.metamodel.mapping;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SingularAttributeMapping extends AttributeMapping {
|
||||
public interface SingularAttributeMapping extends AttributeMapping, StateArrayContributorMapping {
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,5 +10,5 @@ package org.hibernate.persister.walking.spi;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface EncapsulatedEntityIdentifierDefinition extends EntityIdentifierDefinition {
|
||||
public AttributeDefinition getAttributeDefinition();
|
||||
AttributeDefinition getAttributeDefinition();
|
||||
}
|
||||
|
|
|
@ -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?
|
||||
*
|
||||
|
|
|
@ -64,5 +64,4 @@ public interface ProxyFactory {
|
|||
* proxy.
|
||||
*/
|
||||
HibernateProxy getProxy(Serializable id, SharedSessionContractImplementor session) throws HibernateException;
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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() ) );
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
|
@ -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() + ")";
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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,
|
|
@ -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
|
||||
|
|
|
@ -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> {
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -40,7 +40,7 @@ public interface Fetch {
|
|||
/**
|
||||
* The value mapping being fetched
|
||||
*/
|
||||
ModelPart getFetchedMapping();
|
||||
Fetchable getFetchedMapping();
|
||||
|
||||
/**
|
||||
* Get the property path to this fetch
|
||||
|
|
|
@ -27,4 +27,6 @@ public interface FetchParent {
|
|||
* Retrieve the fetches owned by this fetch source.
|
||||
*/
|
||||
List<Fetch> getFetches();
|
||||
|
||||
Fetch findFetch(String fetchableName);
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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...
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue