From 0ce1c35d9549e0f8755c161819100ce0bf0955c8 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Fri, 24 May 2019 14:59:30 +0100 Subject: [PATCH] 6 - SQM based on JPA type system --- .../engine/spi/SessionFactoryImplementor.java | 2 +- .../internal/SessionFactoryImpl.java | 2 +- .../metamodel/model/domain/JpaMetamodel.java | 12 +- .../internal/AbstractPluralAttribute.java | 2 +- .../domain}/internal/AttributeFactory.java | 33 +- .../domain}/internal/DomainMetamodelImpl.java | 495 ++++++------------ .../domain/internal/JpaMetamodelImpl.java | 394 +++++++++++++- .../domain/internal/MapAttributeImpl.java | 2 +- .../domain}/internal/MetadataContext.java | 56 +- .../metamodel/spi/DomainMetamodel.java | 5 +- .../hibernate/type/spi/TypeConfiguration.java | 2 +- .../jpa/test/criteria/QueryBuilderTest.java | 2 +- .../jpa/test/metadata/MetadataTest.java | 2 +- 13 files changed, 633 insertions(+), 376 deletions(-) rename hibernate-core/src/main/java/org/hibernate/metamodel/{ => model/domain}/internal/AttributeFactory.java (96%) rename hibernate-core/src/main/java/org/hibernate/metamodel/{ => model/domain}/internal/DomainMetamodelImpl.java (59%) rename hibernate-core/src/main/java/org/hibernate/metamodel/{ => model/domain}/internal/MetadataContext.java (92%) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java index 6bc0ad9e42..cc6332779a 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java @@ -42,12 +42,12 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.query.spi.NamedQueryRepository; import org.hibernate.query.spi.QueryParameterBindingTypeResolver; +import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.type.Type; import org.hibernate.type.TypeResolver; - /** * Defines the internal contract between the SessionFactory and other parts of * Hibernate such as implementors of Type. diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index f36a873c6a..cdffea8eb1 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -103,7 +103,7 @@ import org.hibernate.jpa.internal.PersistenceUnitUtilImpl; import org.hibernate.mapping.RootClass; import org.hibernate.metadata.ClassMetadata; import org.hibernate.metadata.CollectionMetadata; -import org.hibernate.metamodel.internal.DomainMetamodelImpl; +import org.hibernate.metamodel.model.domain.internal.DomainMetamodelImpl; import org.hibernate.metamodel.spi.MetamodelImplementor; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Loadable; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/JpaMetamodel.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/JpaMetamodel.java index b39a510ec4..910d55f399 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/JpaMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/JpaMetamodel.java @@ -6,12 +6,14 @@ */ package org.hibernate.metamodel.model.domain; +import java.util.List; import java.util.Set; import java.util.function.Consumer; import javax.persistence.metamodel.EmbeddableType; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.ManagedType; +import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.metamodel.spi.DomainMetamodel; import org.hibernate.service.ServiceRegistry; import org.hibernate.type.spi.TypeConfiguration; @@ -19,9 +21,8 @@ import org.hibernate.type.spi.TypeConfiguration; /** * Hibernate extension to the JPA {@link javax.persistence.metamodel.Metamodel} contract * - * @see DomainMetamodel - * * @author Steve Ebersole + * @see DomainMetamodel */ public interface JpaMetamodel extends javax.persistence.metamodel.Metamodel { @@ -55,6 +56,7 @@ public interface JpaMetamodel extends javax.persistence.metamodel.Metamodel { void visitManagedTypes(Consumer> action); void visitEntityTypes(Consumer> action); + void visitRootEntityTypes(Consumer> action); void visitEmbeddables(Consumer> action); @@ -84,4 +86,10 @@ public interface JpaMetamodel extends javax.persistence.metamodel.Metamodel { @Override Set> getEmbeddables(); + + void addNamedEntityGraph(String graphName, RootGraphImplementor entityGraph); + + RootGraphImplementor findEntityGraphByName(String name); + + List> findEntityGraphsByJavaType(Class entityClass); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java index 4e749f1a2e..6555aaa2dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java @@ -136,7 +136,7 @@ public abstract class AbstractPluralAttribute } @Override - public SimpleDomainType getKeyGraphType() { + public SimpleDomainType getKeyGraphType() { return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AttributeFactory.java similarity index 96% rename from hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java rename to hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AttributeFactory.java index 199bfa53ca..4eb6efccea 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AttributeFactory.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.metamodel.internal; +package org.hibernate.metamodel.model.domain.internal; import java.lang.reflect.Field; import java.lang.reflect.Member; @@ -40,11 +40,6 @@ import org.hibernate.metamodel.model.domain.PersistentAttribute; import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; import org.hibernate.metamodel.model.domain.SimpleDomainType; import org.hibernate.metamodel.model.domain.SingularPersistentAttribute; -import org.hibernate.metamodel.model.domain.internal.EmbeddableTypeImpl; -import org.hibernate.metamodel.model.domain.internal.MapMember; -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.property.access.internal.PropertyAccessMapImpl; import org.hibernate.property.access.spi.Getter; import org.hibernate.tuple.entity.EntityMetamodel; @@ -109,7 +104,7 @@ public class AttributeFactory { false, false, property.isOptional(), - context.getSessionFactory().getQueryEngine().getCriteriaBuilder() + context.getCriteriaBuilder() ); } @@ -152,7 +147,7 @@ public class AttributeFactory { determineSimpleType( attributeMetadata.getValueContext() ), attributeMetadata.getMember(), attributeMetadata.getAttributeClassification(), - context.getSessionFactory().getQueryEngine().getCriteriaBuilder() + context.getCriteriaBuilder() ); } @@ -183,14 +178,13 @@ public class AttributeFactory { attributeMetadata.getAttributeClassification(), determineSimpleType( attributeMetadata.getValueContext() ), attributeMetadata.getMember(), - context.getSessionFactory().getQueryEngine().getCriteriaBuilder() + context.getCriteriaBuilder() ); } @SuppressWarnings("unchecked") private PluralPersistentAttribute buildPluralAttribute(PluralAttributeMetadata attributeMetadata) { - final JavaTypeDescriptor javaTypeDescriptor = context.getSessionFactory() - .getMetamodel() + final JavaTypeDescriptor javaTypeDescriptor = context .getTypeConfiguration() .getJavaTypeDescriptorRegistry() .getDescriptor( attributeMetadata.getJavaType() ); @@ -200,7 +194,7 @@ public class AttributeFactory { determineSimpleType( attributeMetadata.getElementValueContext() ), javaTypeDescriptor, determineListIndexOrMapKeyType( attributeMetadata ), - context.getSessionFactory().getQueryEngine().getCriteriaBuilder() + context.getCriteriaBuilder() ); return info @@ -246,7 +240,7 @@ public class AttributeFactory { embeddableClass = component.getComponentClass(); } else { - embeddableClass = context.getSessionFactory() + embeddableClass = context.getTypeConfiguration() .getServiceRegistry() .getService( ClassLoaderService.class ) .classForName( component.getComponentClassName() ); @@ -257,15 +251,13 @@ public class AttributeFactory { return cached; } - final JavaTypeDescriptorRegistry registry = context.getSessionFactory() - .getMetamodel() - .getTypeConfiguration() + final JavaTypeDescriptorRegistry registry = context.getTypeConfiguration() .getJavaTypeDescriptorRegistry(); final JavaTypeDescriptor javaTypeDescriptor = registry.resolveDescriptor( embeddableClass ); embeddableType = new EmbeddableTypeImpl( javaTypeDescriptor, - context.getSessionFactory().getQueryEngine().getCriteriaBuilder() + context.getCriteriaBuilder() ); context.registerEmbeddableType( embeddableType ); @@ -275,7 +267,7 @@ public class AttributeFactory { else { embeddableType = new EmbeddableTypeImpl( component.getRoleName(), - context.getSessionFactory().getQueryEngine().getCriteriaBuilder() + context.getCriteriaBuilder() ); } @@ -309,9 +301,8 @@ public class AttributeFactory { else if ( persistenceType == Type.PersistenceType.MAPPED_SUPERCLASS ) { PersistentClass persistentClass = context.getPersistentClassHostingProperties( (MappedSuperclassTypeImpl) ownerType ); - return context.getSessionFactory() - .getMetamodel() - .entityPersister( persistentClass.getClassName() ) + return context.getMetamodel() + .resolveEntityPersister( persistentClass.getClassName() ) .getEntityMetamodel(); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/DomainMetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainMetamodelImpl.java similarity index 59% rename from hibernate-core/src/main/java/org/hibernate/metamodel/internal/DomainMetamodelImpl.java rename to hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainMetamodelImpl.java index 6c047a7bd5..06138cfb99 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/DomainMetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainMetamodelImpl.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.metamodel.internal; +package org.hibernate.metamodel.model.domain.internal; import java.io.Serializable; import java.util.ArrayList; @@ -17,16 +17,11 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArraySet; +import java.util.function.Consumer; import javax.persistence.EntityGraph; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.NamedSubgraph; -import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.EmbeddableType; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.ManagedType; -import javax.persistence.metamodel.MappedSuperclassType; import org.hibernate.EntityNameResolver; import org.hibernate.HibernateException; @@ -41,30 +36,22 @@ import org.hibernate.cache.spi.access.AccessType; import org.hibernate.cache.spi.access.CollectionDataAccess; import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.cache.spi.access.NaturalIdDataAccess; -import org.hibernate.cfg.annotations.NamedEntityGraphDefinition; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.graph.internal.RootGraphImpl; -import org.hibernate.graph.spi.AttributeNodeImplementor; -import org.hibernate.graph.spi.GraphImplementor; +import org.hibernate.graph.RootGraph; import org.hibernate.graph.spi.RootGraphImplementor; -import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.internal.EntityManagerMessageLogger; import org.hibernate.internal.HEMLogging; -import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.ArrayHelper; -import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.mapping.Collection; -import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.RootClass; +import org.hibernate.metamodel.internal.JpaMetaModelPopulationSetting; +import org.hibernate.metamodel.internal.JpaStaticMetaModelPopulationSetting; +import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.NavigableRole; -import org.hibernate.metamodel.model.domain.internal.EntityTypeImpl; -import org.hibernate.metamodel.model.domain.internal.MappedSuperclassTypeImpl; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; -import org.hibernate.metamodel.model.domain.IdentifiableDomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType; -import org.hibernate.metamodel.model.domain.MappedSuperclassDomainType; import org.hibernate.metamodel.spi.DomainMetamodel; import org.hibernate.metamodel.spi.MetamodelImplementor; import org.hibernate.persister.collection.CollectionPersister; @@ -75,7 +62,6 @@ import org.hibernate.persister.spi.PersisterFactory; import org.hibernate.tuple.entity.EntityTuplizer; import org.hibernate.type.AssociationType; import org.hibernate.type.Type; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.spi.TypeConfiguration; /** @@ -98,27 +84,28 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // JpaMetamodel + private final JpaMetamodelImpl jpaMetamodel; - private final Map, EntityDomainType> jpaEntityTypeMap = new ConcurrentHashMap<>(); - private final Map> jpaEntityTypesByEntityName = new ConcurrentHashMap<>(); - private final Map, MappedSuperclassType> jpaMappedSuperclassTypeMap = new ConcurrentHashMap<>(); - private final Set> jpaEmbeddableTypes = new CopyOnWriteArraySet<>(); - private final Map entityProxyInterfaceMap = new ConcurrentHashMap<>(); - private final Map imports = new ConcurrentHashMap<>(); + // private final Map, EntityDomainType> jpaEntityTypeMap = new ConcurrentHashMap<>(); +// private final Map> jpaEntityTypesByEntityName = new ConcurrentHashMap<>(); +// private final Map, MappedSuperclassType> jpaMappedSuperclassTypeMap = new ConcurrentHashMap<>(); +// private final Set> jpaEmbeddableTypes = new CopyOnWriteArraySet<>(); + private final Map entityProxyInterfaceMap = new ConcurrentHashMap<>(); + private final Map imports = new ConcurrentHashMap<>(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // RuntimeModel - private final Map entityPersisterMap = new ConcurrentHashMap<>(); - private final Map collectionPersisterMap = new ConcurrentHashMap<>(); - private final Map> collectionRolesByEntityParticipant = new ConcurrentHashMap<>(); + private final Map entityPersisterMap = new ConcurrentHashMap<>(); + private final Map collectionPersisterMap = new ConcurrentHashMap<>(); + private final Map> collectionRolesByEntityParticipant = new ConcurrentHashMap<>(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DomainMetamodel - private final ConcurrentMap entityNameResolvers = new ConcurrentHashMap<>(); + private final ConcurrentMap entityNameResolvers = new ConcurrentHashMap<>(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -146,15 +133,13 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento * That's not strictly correct in the JPA standard since for a given Java type we could have * multiple instances of an embeddable type. Some embeddable might override attributes, but we * can only return a single EmbeddableTypeImpl for a given Java object class. - * + *

* A better approach would be if the parent class and attribute name would be included as well * when trying to locate the embeddable type. */ - private final Map, EmbeddableDomainType> jpaEmbeddableTypeMap = new ConcurrentHashMap<>(); +// private final Map, EmbeddableDomainType> jpaEmbeddableTypeMap = new ConcurrentHashMap<>(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - private final transient Map entityGraphMap = new ConcurrentHashMap<>(); - private final TypeConfiguration typeConfiguration; private final Map implementorsCache = new ConcurrentHashMap<>(); @@ -162,6 +147,7 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento public DomainMetamodelImpl(SessionFactoryImplementor sessionFactory, TypeConfiguration typeConfiguration) { this.sessionFactory = sessionFactory; this.typeConfiguration = typeConfiguration; + this.jpaMetamodel = new JpaMetamodelImpl( typeConfiguration ); } /** @@ -171,7 +157,9 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento * @param mappingMetadata The mapping information * @param jpaMetaModelPopulationSetting Should the JPA Metamodel be built as well? */ - public void initialize(MetadataImplementor mappingMetadata, JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting) { + public void initialize( + MetadataImplementor mappingMetadata, + JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting) { this.imports.putAll( mappingMetadata.getImports() ); primeSecondLevelCacheRegions( mappingMetadata ); @@ -188,12 +176,14 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento } }; - final PersisterFactory persisterFactory = sessionFactory.getServiceRegistry().getService( PersisterFactory.class ); + final PersisterFactory persisterFactory = sessionFactory.getServiceRegistry() + .getService( PersisterFactory.class ); for ( final PersistentClass model : mappingMetadata.getEntityBindings() ) { final NavigableRole rootEntityRole = new NavigableRole( model.getRootClass().getEntityName() ); final EntityDataAccess accessStrategy = sessionFactory.getCache().getEntityRegionAccess( rootEntityRole ); - final NaturalIdDataAccess naturalIdAccessStrategy = sessionFactory.getCache().getNaturalIdCacheRegionAccessStrategy( rootEntityRole ); + final NaturalIdDataAccess naturalIdAccessStrategy = sessionFactory.getCache() + .getNaturalIdCacheRegionAccessStrategy( rootEntityRole ); final EntityPersister cp = persisterFactory.createEntityPersister( model, @@ -214,7 +204,11 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento // this part handles an odd case in the Hibernate test suite where we map an interface // as the class and the proxy. I cannot think of a real life use case for that // specific test, but.. - log.debugf( "Entity [%s] mapped same interface [%s] as class and proxy", cp.getEntityName(), cp.getMappedClass() ); + log.debugf( + "Entity [%s] mapped same interface [%s] as class and proxy", + cp.getEntityName(), + cp.getMappedClass() + ); } else { final String old = entityProxyInterfaceMap.put( cp.getConcreteProxyClass(), cp.getEntityName() ); @@ -257,7 +251,7 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento } Type elementType = persister.getElementType(); if ( elementType.isAssociationType() && !elementType.isAnyType() ) { - String entityName = ( ( AssociationType ) elementType ).getAssociatedEntityName( sessionFactory ); + String entityName = ( (AssociationType) elementType ).getAssociatedEntityName( sessionFactory ); Set roles = collectionRolesByEntityParticipant.get( entityName ); if ( roles == null ) { roles = new HashSet<>(); @@ -276,31 +270,13 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento } collectionPersisterMap.values().forEach( CollectionPersister::postInstantiate ); - if ( jpaMetaModelPopulationSetting != JpaMetaModelPopulationSetting.DISABLED ) { - MetadataContext context = new MetadataContext( - sessionFactory, - mappingMetadata.getMappedSuperclassMappingsCopy(), - jpaMetaModelPopulationSetting - ); - - for ( PersistentClass entityBinding : mappingMetadata.getEntityBindings() ) { - locateOrBuildEntityType( entityBinding, context ); - } - handleUnusedMappedSuperclasses( context ); - - context.wrapUp(); - - this.jpaEntityTypeMap.putAll( context.getEntityTypeMap() ); - this.jpaEmbeddableTypes.addAll( context.getEmbeddableTypeSet() ); - for ( EmbeddableDomainType embeddable: jpaEmbeddableTypes ) { - this.jpaEmbeddableTypeMap.put( embeddable.getJavaType(), embeddable ); - } - this.jpaMappedSuperclassTypeMap.putAll( context.getMappedSuperclassTypeMap() ); - this.jpaEntityTypesByEntityName.putAll( context.getEntityTypesByEntityName() ); - - applyNamedEntityGraphs( mappingMetadata.getNamedEntityGraphs().values() ); - } - + jpaMetamodel.initialize( + this, + mappingMetadata, + sessionFactory.getQueryEngine().getCriteriaBuilder(), + jpaMetaModelPopulationSetting, + JpaStaticMetaModelPopulationSetting.determineJpaMetaModelPopulationSetting( sessionFactory.getProperties() ) + ); } private void primeSecondLevelCacheRegions(MetadataImplementor mappingMetadata) { @@ -313,14 +289,20 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento if ( accessType != null ) { if ( bootEntityDescriptor.isCached() ) { - regionConfigBuilders.computeIfAbsent( bootEntityDescriptor.getRootClass().getCacheRegionName(), DomainDataRegionConfigImpl.Builder::new ) + regionConfigBuilders.computeIfAbsent( + bootEntityDescriptor.getRootClass().getCacheRegionName(), + DomainDataRegionConfigImpl.Builder::new + ) .addEntityConfig( bootEntityDescriptor, accessType ); } if ( RootClass.class.isInstance( bootEntityDescriptor ) && bootEntityDescriptor.hasNaturalId() && bootEntityDescriptor.getNaturalIdCacheRegionName() != null ) { - regionConfigBuilders.computeIfAbsent( bootEntityDescriptor.getNaturalIdCacheRegionName(), DomainDataRegionConfigImpl.Builder::new ) + regionConfigBuilders.computeIfAbsent( + bootEntityDescriptor.getNaturalIdCacheRegionName(), + DomainDataRegionConfigImpl.Builder::new + ) .addNaturalIdConfig( (RootClass) bootEntityDescriptor, accessType ); } } @@ -329,7 +311,10 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento for ( Collection collection : mappingMetadata.getCollectionBindings() ) { final AccessType accessType = AccessType.fromExternalName( collection.getCacheConcurrencyStrategy() ); if ( accessType != null ) { - regionConfigBuilders.computeIfAbsent( collection.getCacheRegionName(), DomainDataRegionConfigImpl.Builder::new ) + regionConfigBuilders.computeIfAbsent( + collection.getCacheRegionName(), + DomainDataRegionConfigImpl.Builder::new + ) .addCollectionConfig( collection, accessType ); } } @@ -348,98 +333,24 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento getSessionFactory().getCache().prime( regionConfigs ); } - @SuppressWarnings("unchecked") - private void applyNamedEntityGraphs(java.util.Collection namedEntityGraphs) { - for ( NamedEntityGraphDefinition definition : namedEntityGraphs ) { - log.debugf( - "Applying named entity graph [name=%s, entity-name=%s, jpa-entity-name=%s", - definition.getRegisteredName(), - definition.getEntityName(), - definition.getJpaEntityName() - ); - final EntityDomainType entityType = entity( definition.getEntityName() ); - if ( entityType == null ) { - throw new IllegalArgumentException( - "Attempted to register named entity graph [" + definition.getRegisteredName() - + "] for unknown entity ["+ definition.getEntityName() + "]" - - ); - } - - final RootGraphImpl entityGraph = new RootGraphImpl( - definition.getRegisteredName(), - entityType, - getJpaMetamodel() - ); - - final NamedEntityGraph namedEntityGraph = definition.getAnnotation(); - - if ( namedEntityGraph.includeAllAttributes() ) { - for ( Object attributeObject : entityType.getAttributes() ) { - entityGraph.addAttributeNodes( (Attribute) attributeObject ); - } - } - - if ( namedEntityGraph.attributeNodes() != null ) { - applyNamedAttributeNodes( namedEntityGraph.attributeNodes(), namedEntityGraph, entityGraph ); - } - - entityGraphMap.put( definition.getRegisteredName(), entityGraph ); - } - } - - private void applyNamedAttributeNodes( - NamedAttributeNode[] namedAttributeNodes, - NamedEntityGraph namedEntityGraph, - GraphImplementor graphNode) { - for ( NamedAttributeNode namedAttributeNode : namedAttributeNodes ) { - final String value = namedAttributeNode.value(); - AttributeNodeImplementor attributeNode = graphNode.addAttributeNode( value ); - if ( StringHelper.isNotEmpty( namedAttributeNode.subgraph() ) ) { - final SubGraphImplementor subgraph = attributeNode.makeSubGraph(); - applyNamedSubgraphs( - namedEntityGraph, - namedAttributeNode.subgraph(), - subgraph - ); - } - if ( StringHelper.isNotEmpty( namedAttributeNode.keySubgraph() ) ) { - final SubGraphImplementor subgraph = attributeNode.makeKeySubGraph(); - - applyNamedSubgraphs( - namedEntityGraph, - namedAttributeNode.keySubgraph(), - subgraph - ); - } - } - } - - private void applyNamedSubgraphs(NamedEntityGraph namedEntityGraph, String subgraphName, SubGraphImplementor subgraph) { - for ( NamedSubgraph namedSubgraph : namedEntityGraph.subgraphs() ) { - if ( subgraphName.equals( namedSubgraph.name() ) ) { - applyNamedAttributeNodes( - namedSubgraph.attributeNodes(), - namedEntityGraph, - subgraph - ); - } - } - } @Override public java.util.Collection getEntityNameResolvers() { return entityNameResolvers.keySet(); } - private static void registerEntityNameResolvers(EntityPersister persister, Map entityNameResolvers) { + private static void registerEntityNameResolvers( + EntityPersister persister, + Map entityNameResolvers) { if ( persister.getEntityMetamodel() == null || persister.getEntityMetamodel().getTuplizer() == null ) { return; } registerEntityNameResolvers( persister.getEntityMetamodel().getTuplizer(), entityNameResolvers ); } - private static void registerEntityNameResolvers(EntityTuplizer tuplizer, Map entityNameResolvers) { + private static void registerEntityNameResolvers( + EntityTuplizer tuplizer, + Map entityNameResolvers) { EntityNameResolver[] resolvers = tuplizer.getEntityNameResolvers(); if ( resolvers == null ) { return; @@ -450,98 +361,6 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento } } - private static void handleUnusedMappedSuperclasses(MetadataContext context) { - final Set unusedMappedSuperclasses = context.getUnusedMappedSuperclasses(); - if ( !unusedMappedSuperclasses.isEmpty() ) { - for ( MappedSuperclass mappedSuperclass : unusedMappedSuperclasses ) { - log.unusedMappedSuperclass( mappedSuperclass.getMappedClass().getName() ); - locateOrBuildMappedSuperclassType( mappedSuperclass, context ); - } - } - } - - private static EntityDomainType locateOrBuildEntityType(PersistentClass persistentClass, MetadataContext context) { - EntityDomainType entityType = context.locateEntityType( persistentClass ); - if ( entityType == null ) { - entityType = buildEntityType( persistentClass, context ); - } - return entityType; - } - - //TODO remove / reduce @SW scope - @SuppressWarnings("unchecked") - private static EntityTypeImpl buildEntityType(PersistentClass persistentClass, MetadataContext context) { - final Class javaType = persistentClass.getMappedClass(); - context.pushEntityWorkedOn( persistentClass ); - final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass(); - IdentifiableDomainType superType = superMappedSuperclass == null - ? null - : locateOrBuildMappedSuperclassType( superMappedSuperclass, context ); - //no mappedSuperclass, check for a super entity - if ( superType == null ) { - final PersistentClass superPersistentClass = persistentClass.getSuperclass(); - superType = superPersistentClass == null - ? null - : locateOrBuildEntityType( superPersistentClass, context ); - } - - final JavaTypeDescriptor javaTypeDescriptor = context.getSessionFactory() - .getMetamodel() - .getTypeConfiguration() - .getJavaTypeDescriptorRegistry() - .getDescriptor( javaType ); - EntityTypeImpl entityType = new EntityTypeImpl( - javaTypeDescriptor, - superType, - persistentClass, - context.getSessionFactory().getMetamodel() - ); - - context.registerEntityType( persistentClass, entityType ); - context.popEntityWorkedOn( persistentClass ); - return entityType; - } - - private static MappedSuperclassDomainType locateOrBuildMappedSuperclassType( - MappedSuperclass mappedSuperclass, MetadataContext context) { - MappedSuperclassDomainType mappedSuperclassType = context.locateMappedSuperclassType( mappedSuperclass ); - if ( mappedSuperclassType == null ) { - mappedSuperclassType = buildMappedSuperclassType( mappedSuperclass, context ); - } - return mappedSuperclassType; - } - - //TODO remove / reduce @SW scope - @SuppressWarnings("unchecked") - private static MappedSuperclassTypeImpl buildMappedSuperclassType( - MappedSuperclass mappedSuperclass, - MetadataContext context) { - final MappedSuperclass superMappedSuperclass = mappedSuperclass.getSuperMappedSuperclass(); - IdentifiableDomainType superType = superMappedSuperclass == null - ? null - : locateOrBuildMappedSuperclassType( superMappedSuperclass, context ); - //no mappedSuperclass, check for a super entity - if ( superType == null ) { - final PersistentClass superPersistentClass = mappedSuperclass.getSuperPersistentClass(); - superType = superPersistentClass == null - ? null - : locateOrBuildEntityType( superPersistentClass, context ); - } - final JavaTypeDescriptor javaTypeDescriptor = context.getSessionFactory() - .getMetamodel() - .getTypeConfiguration() - .getJavaTypeDescriptorRegistry() - .getDescriptor( mappedSuperclass.getMappedClass() ); - MappedSuperclassTypeImpl mappedSuperclassType = new MappedSuperclassTypeImpl( - javaTypeDescriptor, - mappedSuperclass, - superType, - context.getSessionFactory().getMetamodel() - ); - context.registerMappedSuperclassType( mappedSuperclass, mappedSuperclassType ); - return mappedSuperclassType; - } - // /** // * Instantiate the metamodel. // * @@ -580,73 +399,116 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento return typeConfiguration; } + @Override + public JpaMetamodel getJpaMetamodel() { + return this.jpaMetamodel; + } + + @Override + public EntityPersister resolveEntityPersister(Object entity) { + return findEntityDescriptor(entity.getClass()); + } + + @Override + public void visitEntityDescriptors(Consumer action){ + entityPersisterMap.values().forEach( action ); + } + + @Override + public EntityPersister getEntityDescriptor(String entityName){ + final EntityPersister entityPersister = entityPersisterMap.get( entityName ); + if ( entityPersister == null ) { + throw new IllegalArgumentException( "Unable to locate persister: " + entityName ); + } + return entityPersister; + } + + @Override + public EntityPersister findEntityDescriptor(String entityName){ + return entityPersisterMap.get( entityName ); + } + + @Override + public EntityPersister findEntityDescriptor(Class entityJavaType){ + return findEntityDescriptor( entityJavaType.getName() ); + } + @Override public SessionFactoryImplementor getSessionFactory() { return sessionFactory; } @Override - @SuppressWarnings({"unchecked"}) + public EntityPersister getEntityDescriptor(Class entityJavaType){ + EntityPersister entityPersister = entityPersisterMap.get( entityJavaType.getName() ); + if ( entityPersister == null ) { + String mappedEntityName = entityProxyInterfaceMap.get( entityJavaType ); + if ( mappedEntityName != null ) { + entityPersister = entityPersisterMap.get( mappedEntityName ); + } + } + + if ( entityPersister == null ) { + throw new IllegalArgumentException( "Unable to locate persister: " + entityJavaType.getName() ); + } + + return entityPersister; + } + + @Override + public EntityPersister locateEntityDescriptor(Class byClass){ + EntityPersister entityPersister = entityPersisterMap.get( byClass.getName() ); + if ( entityPersister == null ) { + String mappedEntityName = entityProxyInterfaceMap.get( byClass ); + if ( mappedEntityName != null ) { + entityPersister = entityPersisterMap.get( mappedEntityName ); + } + } + + if ( entityPersister == null ) { + throw new UnknownEntityTypeException( "Unable to locate persister: " + byClass.getName() ); + } + + return entityPersister; + } + + @Override + @SuppressWarnings({ "unchecked" }) public EntityDomainType entity(Class cls) { - final EntityType entityType = jpaEntityTypeMap.get( cls ); - if ( entityType == null ) { - throw new IllegalArgumentException( "Not an entity: " + cls ); - } - return (EntityDomainType) entityType; + return getJpaMetamodel().entity( cls ); } @Override - @SuppressWarnings({"unchecked"}) + @SuppressWarnings({ "unchecked" }) public ManagedDomainType managedType(Class cls) { - ManagedType type = jpaEntityTypeMap.get( cls ); - if ( type == null ) { - type = jpaMappedSuperclassTypeMap.get( cls ); - } - if ( type == null ) { - type = jpaEmbeddableTypeMap.get( cls ); - } - if ( type == null ) { - throw new IllegalArgumentException( "Not a managed type: " + cls ); - } - return (ManagedDomainType) type; + return getJpaMetamodel().managedType( cls ); } @Override - @SuppressWarnings({"unchecked"}) + @SuppressWarnings({ "unchecked" }) public EmbeddableDomainType embeddable(Class cls) { - final EmbeddableDomainType embeddableType = jpaEmbeddableTypeMap.get( cls ); - if ( embeddableType == null ) { - throw new IllegalArgumentException( "Not an embeddable: " + cls ); - } - return (EmbeddableDomainType) embeddableType; + return getJpaMetamodel().embeddable( cls ); } @Override public Set> getManagedTypes() { - final int setSize = CollectionHelper.determineProperSizing( - jpaEntityTypeMap.size() + jpaMappedSuperclassTypeMap.size() + jpaEmbeddableTypes.size() - ); - final Set> managedTypes = new HashSet<>( setSize ); - managedTypes.addAll( jpaEntityTypesByEntityName.values() ); - managedTypes.addAll( jpaMappedSuperclassTypeMap.values() ); - managedTypes.addAll( jpaEmbeddableTypes ); - return managedTypes; + return getJpaMetamodel().getManagedTypes(); } @Override public Set> getEntities() { - return new HashSet<>( jpaEntityTypesByEntityName.values() ); + return getJpaMetamodel().getEntities(); } @Override public Set> getEmbeddables() { - return new HashSet<>( jpaEmbeddableTypes ); + return getJpaMetamodel().getEmbeddables(); } @Override @SuppressWarnings("unchecked") public EntityDomainType entity(String entityName) { - return (EntityDomainType) jpaEntityTypesByEntityName.get( entityName ); + return getJpaMetamodel().entity( entityName ); } @Override @@ -658,7 +520,7 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento imports.put( className, className ); return className; } - catch ( ClassLoadingException cnfe ) { + catch (ClassLoadingException cnfe) { imports.put( className, INVALID_IMPORT ); return null; } @@ -685,7 +547,9 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento } try { - final Class clazz = getSessionFactory().getServiceRegistry().getService( ClassLoaderService.class ).classForName( className ); + final Class clazz = getSessionFactory().getServiceRegistry() + .getService( ClassLoaderService.class ) + .classForName( className ); implementors = doGetImplementors( clazz ); if ( implementors.length > 0 ) { implementorsCache.putIfAbsent( className, implementors ); @@ -696,7 +560,7 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento } } catch (ClassLoadingException e) { - return new String[]{ className }; // we don't cache anything for dynamic classes + return new String[] { className }; // we don't cache anything for dynamic classes } } @@ -733,24 +597,6 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento return result; } - - @Override - public EntityPersister locateEntityPersister(Class byClass) { - EntityPersister entityPersister = entityPersisterMap.get( byClass.getName() ); - if ( entityPersister == null ) { - String mappedEntityName = entityProxyInterfaceMap.get( byClass ); - if ( mappedEntityName != null ) { - entityPersister = entityPersisterMap.get( mappedEntityName ); - } - } - - if ( entityPersister == null ) { - throw new UnknownEntityTypeException( "Unable to locate persister: " + byClass.getName() ); - } - - return entityPersister; - } - @Override public EntityPersister locateEntityPersister(String byName) { final EntityPersister entityPersister = entityPersisterMap.get( byName ); @@ -760,6 +606,29 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento return entityPersister; } + public String getImportedName(String name){ + return imports.get( name ); + } + + @Override + public void visitCollectionDescriptors(Consumer action){ + collectionPersisterMap.values().forEach( action ); + } + + @Override + public CollectionPersister getCollectionDescriptor(String role){ + CollectionPersister collectionPersister = collectionPersisterMap.get( role ); + if(collectionPersister == null){ + throw new IllegalArgumentException( "Unable to locate persister: " + role ); + } + return collectionPersister; + } + + @Override + public CollectionPersister findCollectionDescriptor(String role){ + return collectionPersisterMap.get( role ); + } + @Override public Set getCollectionRolesByEntityParticipant(String entityName) { return collectionRolesByEntityParticipant.get( entityName ); @@ -777,14 +646,7 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento @Override public void addNamedEntityGraph(String graphName, RootGraphImplementor entityGraph) { - final EntityGraph old = entityGraphMap.put( - graphName, - entityGraph.makeImmutableCopy( graphName ) - ); - - if ( old != null ) { - log.debugf( "EntityGraph being replaced on EntityManagerFactory for name %s", graphName ); - } + jpaMetamodel.addNamedEntityGraph( graphName, entityGraph ); } @Override @@ -795,31 +657,18 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento @Override @SuppressWarnings("unchecked") public RootGraphImplementor findEntityGraphByName(String name) { - return entityGraphMap.get( name ); + return getJpaMetamodel().findEntityGraphByName( name ); } @Override @SuppressWarnings("unchecked") public List> findEntityGraphsByJavaType(Class entityClass) { - final EntityDomainType entityType = entity( entityClass ); - if ( entityType == null ) { - throw new IllegalArgumentException( "Given class is not an entity : " + entityClass.getName() ); - } + return getJpaMetamodel().findEntityGraphsByJavaType( entityClass ); + } - final List> results = new ArrayList<>(); - - for ( EntityGraph entityGraph : entityGraphMap.values() ) { - if ( !RootGraphImplementor.class.isInstance( entityGraph ) ) { - continue; - } - - final RootGraphImplementor egi = (RootGraphImplementor) entityGraph; - if ( egi.appliesTo( entityType ) ) { - results.add( egi ); - } - } - - return results; + @Override + public RootGraph findNamedGraph(String name){ + return findEntityGraphByName( name ); } @Override @@ -838,7 +687,7 @@ public class DomainMetamodelImpl implements DomainMetamodel, MetamodelImplemento final boolean isMappedClass = clazz.getName().equals( checkQueryableEntityName ); if ( checkQueryable.isExplicitPolymorphism() ) { if ( isMappedClass ) { - return new String[]{ clazz.getName() }; // NOTE EARLY EXIT + return new String[] { clazz.getName() }; // NOTE EARLY EXIT } } else { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java index 25abba6f33..8f83060998 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java @@ -6,39 +6,300 @@ */ package org.hibernate.metamodel.model.domain.internal; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.function.Consumer; + +import javax.persistence.EntityGraph; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.NamedSubgraph; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.EmbeddableType; +import javax.persistence.metamodel.EntityType; +import javax.persistence.metamodel.ManagedType; +import javax.persistence.metamodel.MappedSuperclassType; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.annotations.NamedEntityGraphDefinition; +import org.hibernate.graph.internal.RootGraphImpl; +import org.hibernate.graph.spi.AttributeNodeImplementor; +import org.hibernate.graph.spi.GraphImplementor; +import org.hibernate.graph.spi.RootGraphImplementor; +import org.hibernate.graph.spi.SubGraphImplementor; +import org.hibernate.internal.EntityManagerMessageLogger; +import org.hibernate.internal.HEMLogging; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.mapping.MappedSuperclass; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.metamodel.internal.JpaMetaModelPopulationSetting; +import org.hibernate.metamodel.internal.JpaStaticMetaModelPopulationSetting; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.metamodel.model.domain.IdentifiableDomainType; import org.hibernate.metamodel.model.domain.JpaMetamodel; +import org.hibernate.metamodel.model.domain.ManagedDomainType; +import org.hibernate.metamodel.model.domain.MappedSuperclassDomainType; +import org.hibernate.metamodel.spi.DomainMetamodel; +import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder; import org.hibernate.query.sqm.tree.domain.SqmPolymorphicRootDescriptor; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.spi.TypeConfiguration; /** * @author Steve Ebersole */ public class JpaMetamodelImpl implements JpaMetamodel { + private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( JpaMetamodel.class ); private static final String INVALID_IMPORT = ""; private final TypeConfiguration typeConfiguration; - private final Map> entityDescriptorMap; - private final Map> strictEntityDescriptorMap; - private final Map> embeddableDescriptorMap; - private final Map entityProxyInterfaceMap = new ConcurrentHashMap<>(); + private final Map> entityDescriptorMap = new ConcurrentHashMap<>(); + private final Map> strictEntityDescriptorMap = new ConcurrentHashMap<>(); + private final Map, MappedSuperclassType> mappedSuperclassTypeMap = new ConcurrentHashMap<>(); + + private final Map> embeddableDescriptorMap = new ConcurrentHashMap<>(); + private final Set> embeddableDescriptors = new CopyOnWriteArraySet<>(); - private final Map nameToImportNameMap = new ConcurrentHashMap<>(); private final Map> polymorphicEntityReferenceMap = new ConcurrentHashMap<>(); + private final Map nameToImportNameMap = new ConcurrentHashMap<>(); + + private final transient Map entityGraphMap = new ConcurrentHashMap<>(); + public JpaMetamodelImpl(TypeConfiguration typeConfiguration) { this.typeConfiguration = typeConfiguration; } + public void initialize( + DomainMetamodel metamodel, + MetadataImplementor mappingMetadata, + SqmCriteriaNodeBuilder criteriaBuilder, + JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting, + JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting + ) { + if ( jpaMetaModelPopulationSetting != JpaMetaModelPopulationSetting.DISABLED ) { + MetadataContext context = new MetadataContext( + metamodel, + criteriaBuilder, + mappingMetadata.getMappedSuperclassMappingsCopy(), + typeConfiguration, + jpaMetaModelPopulationSetting, + jpaStaticMetaModelPopulationSetting + ); + + for ( PersistentClass entityBinding : mappingMetadata.getEntityBindings() ) { + locateOrBuildEntityType( entityBinding, context ); + } + handleUnusedMappedSuperclasses( context ); + + context.wrapUp(); + + strictEntityDescriptorMap.putAll( context.getEntityTypeMap() ); + this.embeddableDescriptors.addAll( context.getEmbeddableTypeSet() ); + for ( EmbeddableDomainType embeddable : embeddableDescriptors ) { + this.embeddableDescriptorMap.put( embeddable.getJavaType(), embeddable ); + } + this.entityDescriptorMap.putAll( context.getEntityTypesByEntityName() ); + this.mappedSuperclassTypeMap.putAll( context.getMappedSuperclassTypeMap() ); + + applyNamedEntityGraphs( mappingMetadata.getNamedEntityGraphs().values() ); + } + } + + @SuppressWarnings("unchecked") + private void applyNamedEntityGraphs(java.util.Collection namedEntityGraphs) { + for ( NamedEntityGraphDefinition definition : namedEntityGraphs ) { + log.debugf( + "Applying named entity graph [name=%s, entity-name=%s, jpa-entity-name=%s", + definition.getRegisteredName(), + definition.getEntityName(), + definition.getJpaEntityName() + ); + final EntityDomainType entityType = entity( definition.getEntityName() ); + if ( entityType == null ) { + throw new IllegalArgumentException( + "Attempted to register named entity graph [" + definition.getRegisteredName() + + "] for unknown entity [" + definition.getEntityName() + "]" + + ); + } + + final RootGraphImpl entityGraph = new RootGraphImpl( + definition.getRegisteredName(), + entityType, + this + ); + + final NamedEntityGraph namedEntityGraph = definition.getAnnotation(); + + if ( namedEntityGraph.includeAllAttributes() ) { + for ( Object attributeObject : entityType.getAttributes() ) { + entityGraph.addAttributeNodes( (Attribute) attributeObject ); + } + } + + if ( namedEntityGraph.attributeNodes() != null ) { + applyNamedAttributeNodes( namedEntityGraph.attributeNodes(), namedEntityGraph, entityGraph ); + } + + entityGraphMap.put( definition.getRegisteredName(), entityGraph ); + } + } + + private void applyNamedAttributeNodes( + NamedAttributeNode[] namedAttributeNodes, + NamedEntityGraph namedEntityGraph, + GraphImplementor graphNode) { + for ( NamedAttributeNode namedAttributeNode : namedAttributeNodes ) { + final String value = namedAttributeNode.value(); + AttributeNodeImplementor attributeNode = graphNode.addAttributeNode( value ); + if ( StringHelper.isNotEmpty( namedAttributeNode.subgraph() ) ) { + final SubGraphImplementor subgraph = attributeNode.makeSubGraph(); + applyNamedSubgraphs( + namedEntityGraph, + namedAttributeNode.subgraph(), + subgraph + ); + } + if ( StringHelper.isNotEmpty( namedAttributeNode.keySubgraph() ) ) { + final SubGraphImplementor subgraph = attributeNode.makeKeySubGraph(); + + applyNamedSubgraphs( + namedEntityGraph, + namedAttributeNode.keySubgraph(), + subgraph + ); + } + } + } + + private void applyNamedSubgraphs( + NamedEntityGraph namedEntityGraph, + String subgraphName, + SubGraphImplementor subgraph) { + for ( NamedSubgraph namedSubgraph : namedEntityGraph.subgraphs() ) { + if ( subgraphName.equals( namedSubgraph.name() ) ) { + applyNamedAttributeNodes( + namedSubgraph.attributeNodes(), + namedEntityGraph, + subgraph + ); + } + } + } + + private static void handleUnusedMappedSuperclasses(MetadataContext context) { + final Set unusedMappedSuperclasses = context.getUnusedMappedSuperclasses(); + if ( !unusedMappedSuperclasses.isEmpty() ) { + for ( MappedSuperclass mappedSuperclass : unusedMappedSuperclasses ) { + log.unusedMappedSuperclass( mappedSuperclass.getMappedClass().getName() ); + locateOrBuildMappedSuperclassType( mappedSuperclass, context ); + } + } + } + + private static MappedSuperclassDomainType locateOrBuildMappedSuperclassType( + MappedSuperclass mappedSuperclass, MetadataContext context) { + MappedSuperclassDomainType mappedSuperclassType = context.locateMappedSuperclassType( mappedSuperclass ); + if ( mappedSuperclassType == null ) { + mappedSuperclassType = buildMappedSuperclassType( mappedSuperclass, context ); + } + return mappedSuperclassType; + } + + //TODO remove / reduce @SW scope + @SuppressWarnings("unchecked") + private static MappedSuperclassTypeImpl buildMappedSuperclassType( + MappedSuperclass mappedSuperclass, + MetadataContext context) { + final MappedSuperclass superMappedSuperclass = mappedSuperclass.getSuperMappedSuperclass(); + IdentifiableDomainType superType = superMappedSuperclass == null + ? null + : locateOrBuildMappedSuperclassType( superMappedSuperclass, context ); + //no mappedSuperclass, check for a super entity + if ( superType == null ) { + final PersistentClass superPersistentClass = mappedSuperclass.getSuperPersistentClass(); + superType = superPersistentClass == null + ? null + : locateOrBuildEntityType( superPersistentClass, context ); + } + final JavaTypeDescriptor javaTypeDescriptor = context.getTypeConfiguration() + .getJavaTypeDescriptorRegistry() + .getDescriptor( mappedSuperclass.getMappedClass() ); + MappedSuperclassTypeImpl mappedSuperclassType = new MappedSuperclassTypeImpl( + javaTypeDescriptor, + mappedSuperclass, + superType, + context.getMetamodel().getJpaMetamodel() + ); + context.registerMappedSuperclassType( mappedSuperclass, mappedSuperclassType ); + return mappedSuperclassType; + } + + + private static EntityDomainType locateOrBuildEntityType( + PersistentClass persistentClass, + MetadataContext context) { + EntityDomainType entityType = context.locateEntityType( persistentClass ); + if ( entityType == null ) { + entityType = buildEntityType( persistentClass, context ); + } + return entityType; + } + + //TODO remove / reduce @SW scope + @SuppressWarnings("unchecked") + private static EntityTypeImpl buildEntityType(PersistentClass persistentClass, MetadataContext context) { + final Class javaType = persistentClass.getMappedClass(); + context.pushEntityWorkedOn( persistentClass ); + final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass(); + IdentifiableDomainType superType = superMappedSuperclass == null + ? null + : locateOrBuildMappedSuperclassType( superMappedSuperclass, context ); + //no mappedSuperclass, check for a super entity + if ( superType == null ) { + final PersistentClass superPersistentClass = persistentClass.getSuperclass(); + superType = superPersistentClass == null + ? null + : locateOrBuildEntityType( superPersistentClass, context ); + } + + final JavaTypeDescriptor javaTypeDescriptor = context.getTypeConfiguration() + .getJavaTypeDescriptorRegistry() + .getDescriptor( javaType ); + EntityTypeImpl entityType = new EntityTypeImpl( + javaTypeDescriptor, + superType, + persistentClass, + context.getMetamodel().getJpaMetamodel() + ); + + context.registerEntityType( persistentClass, entityType ); + context.popEntityWorkedOn( persistentClass ); + return entityType; + } + + + @Override + public TypeConfiguration getTypeConfiguration() { + return typeConfiguration; + } + + @Override + public EntityDomainType entity(String entityName) { + return (EntityDomainType) entityDescriptorMap.get( entityName ); + } + @Override public EntityDomainType resolveHqlEntityReference(String entityName) { final String rename = resolveImportedName( entityName ); @@ -59,6 +320,127 @@ public class JpaMetamodelImpl implements JpaMetamodel { throw new IllegalArgumentException( "Could not resolve entity reference " + entityName ); } + @Override + public void visitManagedTypes(Consumer> action) { + visitEntityTypes( (Consumer) action ); + visitEmbeddables( (Consumer) action ); + mappedSuperclassTypeMap.values().forEach( (Consumer) action ); + } + + @Override + public void visitEntityTypes(Consumer> action) { + entityDescriptorMap.values().forEach( action ); + } + + @Override + public void visitRootEntityTypes(Consumer> action) { + entityDescriptorMap.values().forEach( entityDomainType -> { + if ( entityDomainType.getSuperType() == null ) { + action.accept( entityDomainType ); + } + } ); + } + + @Override + public void visitEmbeddables(Consumer> action) { + embeddableDescriptors.forEach( action ); + } + + @Override + public ManagedDomainType managedType(Class cls) { + ManagedType type = strictEntityDescriptorMap.get( cls ); + if ( type == null ) { + type = mappedSuperclassTypeMap.get( cls ); + } + if ( type == null ) { + type = embeddableDescriptorMap.get( cls ); + } + if ( type == null ) { + throw new IllegalArgumentException( "Not a managed type: " + cls ); + } + return (ManagedDomainType) type; + } + + @Override + public EntityDomainType entity(Class cls) { + final EntityType entityType = strictEntityDescriptorMap.get( cls ); + if ( entityType == null ) { + throw new IllegalArgumentException( "Not an entity: " + cls ); + } + return (EntityDomainType) entityType; + } + + @Override + public EmbeddableDomainType embeddable(Class cls) { + final EmbeddableDomainType embeddableType = embeddableDescriptorMap.get( cls ); + if ( embeddableType == null ) { + throw new IllegalArgumentException( "Not an embeddable: " + cls ); + } + return (EmbeddableDomainType) embeddableType; + } + + @Override + public Set> getManagedTypes() { + final int setSize = CollectionHelper.determineProperSizing( + entityDescriptorMap.size() + mappedSuperclassTypeMap.size() + embeddableDescriptors.size() + ); + final Set> managedTypes = new HashSet<>( setSize ); + managedTypes.addAll( entityDescriptorMap.values() ); + managedTypes.addAll( mappedSuperclassTypeMap.values() ); + managedTypes.addAll( embeddableDescriptors ); + return managedTypes; + } + + @Override + public Set> getEntities() { + return new HashSet<>( entityDescriptorMap.values() ); + } + + @Override + public Set> getEmbeddables() { + return new HashSet<>( embeddableDescriptors ); + } + + @Override + public void addNamedEntityGraph(String graphName, RootGraphImplementor entityGraph) { + final EntityGraph old = entityGraphMap.put( + graphName, + entityGraph.makeImmutableCopy( graphName ) + ); + + if ( old != null ) { + log.debugf( "EntityGraph being replaced on EntityManagerFactory for name %s", graphName ); + } + } + + @Override + public RootGraphImplementor findEntityGraphByName(String name) { + return entityGraphMap.get( name ); + } + + @Override + public List> findEntityGraphsByJavaType(Class entityClass) { + final EntityDomainType entityType = entity( entityClass ); + if ( entityType == null ) { + throw new IllegalArgumentException( "Given class is not an entity : " + entityClass.getName() ); + } + + final List> results = new ArrayList<>(); + + for ( EntityGraph entityGraph : entityGraphMap.values() ) { + if ( !RootGraphImplementor.class.isInstance( entityGraph ) ) { + continue; + } + + final RootGraphImplementor egi = (RootGraphImplementor) entityGraph; + if ( egi.appliesTo( entityType ) ) { + results.add( egi ); + } + } + + return results; + } + private String resolveImportedName(String name) { String result = nameToImportNameMap.get( name ); if ( result == null ) { @@ -71,7 +453,7 @@ public class JpaMetamodelImpl implements JpaMetamodel { nameToImportNameMap.put( name, name ); return name; } - catch ( ClassLoadingException cnfe ) { + catch (ClassLoadingException cnfe) { // it is a NOT fully-qualified class name - add a marker entry // so we do not keep trying later nameToImportNameMap.put( name, INVALID_IMPORT ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MapAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MapAttributeImpl.java index 3c07caeaae..4c0169c82c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MapAttributeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MapAttributeImpl.java @@ -59,7 +59,7 @@ class MapAttributeImpl extends AbstractPluralAttribute, V> } @Override - public SimpleDomainType getKeyGraphType() { + public SimpleDomainType getKeyGraphType() { return getKeyType(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MetadataContext.java similarity index 92% rename from hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java rename to hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MetadataContext.java index 921226dab6..2b48885e1a 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MetadataContext.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.metamodel.internal; +package org.hibernate.metamodel.model.domain.internal; import java.lang.reflect.Field; import java.util.ArrayList; @@ -18,6 +18,7 @@ import java.util.Set; import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.IdentifiableType; import javax.persistence.metamodel.MappedSuperclassType; +import javax.persistence.metamodel.Metamodel; import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.Type; @@ -32,20 +33,23 @@ import org.hibernate.mapping.KeyValue; import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; +import org.hibernate.metamodel.internal.JpaMetaModelPopulationSetting; +import org.hibernate.metamodel.internal.JpaStaticMetaModelPopulationSetting; import org.hibernate.metamodel.model.domain.AbstractIdentifiableType; import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.IdentifiableDomainType; +import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.MappedSuperclassDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; import org.hibernate.metamodel.model.domain.SingularPersistentAttribute; -import org.hibernate.metamodel.model.domain.internal.AttributeContainer; -import org.hibernate.metamodel.model.domain.internal.BasicTypeImpl; -import org.hibernate.metamodel.model.domain.internal.EntityTypeImpl; -import org.hibernate.metamodel.model.domain.internal.MappedSuperclassTypeImpl; +import org.hibernate.metamodel.spi.DomainMetamodel; +import org.hibernate.metamodel.spi.MetamodelImplementor; +import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder; import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry; +import org.hibernate.type.spi.TypeConfiguration; /** * Defines a context for storing information during the building of the {@link DomainMetamodelImpl}. @@ -63,9 +67,11 @@ import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry; class MetadataContext { private static final EntityManagerMessageLogger LOG = HEMLogging.messageLogger( MetadataContext.class ); - private final SessionFactoryImplementor sessionFactory; + private final SqmCriteriaNodeBuilder criteriaBuilder; private Set knownMappedSuperclasses; + private TypeConfiguration typeConfiguration; private final boolean ignoreUnsupported; + private final JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting; private final AttributeFactory attributeFactory = new AttributeFactory( this ); private Map, EntityDomainType> entityTypes = new HashMap<>(); @@ -84,18 +90,38 @@ class MetadataContext { * Stack of PersistentClass being process. Last in the list is the highest in the stack. */ private List stackOfPersistentClassesBeingProcessed = new ArrayList<>(); + private DomainMetamodel metamodel; public MetadataContext( - SessionFactoryImplementor sessionFactory, + DomainMetamodel metamodel, + SqmCriteriaNodeBuilder criteriaBuilder, Set mappedSuperclasses, - JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting) { - this.sessionFactory = sessionFactory; + TypeConfiguration typeConfiguration, + JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting, + JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting + ) { + this.metamodel = metamodel; + this.criteriaBuilder = criteriaBuilder; this.knownMappedSuperclasses = mappedSuperclasses; + this.typeConfiguration = typeConfiguration; this.ignoreUnsupported = jpaMetaModelPopulationSetting == JpaMetaModelPopulationSetting.IGNORE_UNSUPPORTED; + this.jpaStaticMetaModelPopulationSetting = jpaStaticMetaModelPopulationSetting; } - /*package*/ SessionFactoryImplementor getSessionFactory() { - return sessionFactory; + public SqmCriteriaNodeBuilder getCriteriaBuilder() { + return criteriaBuilder; + } + + public TypeConfiguration getTypeConfiguration() { + return typeConfiguration; + } + + public JavaTypeDescriptorRegistry getJavaTypeDescriptorRegistry(){ + return typeConfiguration.getJavaTypeDescriptorRegistry(); + } + + DomainMetamodel getMetamodel() { + return metamodel; } /*package*/ boolean isIgnoreUnsupported() { @@ -211,8 +237,7 @@ class MetadataContext { LOG.trace( "Wrapping up metadata context..." ); } - boolean staticMetamodelScanEnabled = JpaStaticMetaModelPopulationSetting - .determineJpaMetaModelPopulationSetting( sessionFactory.getProperties() ) != JpaStaticMetaModelPopulationSetting.DISABLED; + boolean staticMetamodelScanEnabled = this.jpaStaticMetaModelPopulationSetting != JpaStaticMetaModelPopulationSetting.DISABLED; //we need to process types from superclasses to subclasses for ( Object mapping : orderedMappings ) { @@ -561,9 +586,8 @@ class MetadataContext { return (BasicDomainType) basicDomainTypeMap.computeIfAbsent( javaType, jt -> { - final JavaTypeDescriptorRegistry registry = getSessionFactory() - .getMetamodel() - .getTypeConfiguration() + final JavaTypeDescriptorRegistry registry = + getTypeConfiguration() .getJavaTypeDescriptorRegistry(); return new BasicTypeImpl<>( registry.resolveDescriptor( javaType ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/DomainMetamodel.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/DomainMetamodel.java index 348dd774e7..48fda9f45e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/DomainMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/DomainMetamodel.java @@ -9,6 +9,7 @@ package org.hibernate.metamodel.spi; import java.util.List; import java.util.function.Consumer; +import org.hibernate.UnknownEntityTypeException; import org.hibernate.graph.RootGraph; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.JpaMetamodel; @@ -39,7 +40,9 @@ public interface DomainMetamodel { /** * Given a JPA entity domain type, get the associated Hibernate entity descriptor */ - EntityPersister resolveEntityDescriptor(EntityDomainType entityDomainType); + default EntityPersister resolveEntityDescriptor(EntityDomainType entityDomainType){ + return resolveEntityPersister( entityDomainType ); + } /** * Visit all entity mapping descriptors defined in the model diff --git a/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java b/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java index f2679761c2..ddcf96d704 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java +++ b/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java @@ -31,7 +31,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.id.uuid.LocalObjectUuidHelper; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.SessionFactoryRegistry; -import org.hibernate.metamodel.internal.DomainMetamodelImpl; +import org.hibernate.metamodel.model.domain.internal.DomainMetamodelImpl; import org.hibernate.metamodel.spi.MetamodelImplementor; import org.hibernate.query.BinaryArithmeticOperator; import org.hibernate.query.internal.QueryHelper; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java index 969b42747d..911386e149 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java @@ -34,7 +34,7 @@ import org.hibernate.jpa.test.metamodel.Phone; import org.hibernate.jpa.test.metamodel.Product; import org.hibernate.jpa.test.metamodel.ShelfLife; import org.hibernate.jpa.test.metamodel.Spouse; -import org.hibernate.metamodel.internal.DomainMetamodelImpl; +import org.hibernate.metamodel.model.domain.internal.DomainMetamodelImpl; import org.hibernate.query.criteria.internal.CriteriaBuilderImpl; import org.hibernate.query.criteria.internal.predicate.ComparisonPredicate; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/metadata/MetadataTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/metadata/MetadataTest.java index ad7a5a4f34..fa94dbbf26 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/metadata/MetadataTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/metadata/MetadataTest.java @@ -29,7 +29,7 @@ import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.metamodel.internal.JpaMetaModelPopulationSetting; -import org.hibernate.metamodel.internal.DomainMetamodelImpl; +import org.hibernate.metamodel.model.domain.internal.DomainMetamodelImpl; import org.junit.Test;