From 8dca8637a8528803ee84427d31ebf616ef7e67e5 Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Wed, 9 Oct 2024 11:10:00 +0200 Subject: [PATCH] HHH-18683 Change metamodel implementations to comply with JPA spec --- .../metamodel/model/domain/JpaMetamodel.java | 32 ++++++- .../domain/internal/JpaMetamodelImpl.java | 88 +++++++++++++------ .../domain/internal/MappingMetamodelImpl.java | 21 +++++ .../FullyQualifiedReflectivePathTerminal.java | 2 +- .../hql/internal/SemanticQueryBuilder.java | 3 +- .../sqm/sql/BaseSqmToSqlAstConverter.java | 3 +- .../validation/MockSessionFactory.java | 21 ++++- 7 files changed, 134 insertions(+), 36 deletions(-) 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 c4f526a29a..b26dad3559 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 @@ -78,16 +78,40 @@ public interface JpaMetamodel extends Metamodel { EntityDomainType resolveHqlEntityReference(String entityName); /** - * Same as {@link #managedType} except {@code null} is returned rather + * Same as {@link #managedType(Class)} except {@code null} is returned rather * than throwing an exception */ - ManagedDomainType findManagedType(Class cls); + @Nullable ManagedDomainType findManagedType(Class cls); /** - * Same as {@link #entity} except {@code null} is returned rather + * Same as {@link #entity(Class)} except {@code null} is returned rather * than throwing an exception */ - EntityDomainType findEntityType(Class cls); + @Nullable EntityDomainType findEntityType(Class cls); + + /** + * Same as {@link #embeddable(Class)} except {@code null} is returned rather + * than throwing an exception + */ + @Nullable EmbeddableDomainType findEmbeddableType(Class cls); + + /** + * Same as {@link #managedType(String)} except {@code null} is returned rather + * than throwing an exception + */ + @Nullable ManagedDomainType findManagedType(@Nullable String typeName); + + /** + * Same as {@link #entity(String)} except {@code null} is returned rather + * than throwing an exception + */ + @Nullable EntityDomainType findEntityType(@Nullable String entityName); + + /** + * Same as {@link #embeddable(String)} except {@code null} is returned rather + * than throwing an exception + */ + @Nullable EmbeddableDomainType findEmbeddableType(@Nullable String embeddableName); String qualifyImportableName(String queryName); 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 289c11a3c9..12601134a3 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 @@ -134,33 +134,61 @@ public JpaCompliance getJpaCompliance() { } @Override - public ManagedDomainType managedType(String typeName) { + public @Nullable ManagedDomainType findManagedType(@Nullable String typeName) { //noinspection unchecked return typeName == null ? null : (ManagedDomainType) managedTypeByName.get( typeName ); } @Override - public EntityDomainType entity(String entityName) { + public ManagedDomainType managedType(String typeName) { + final ManagedDomainType managedType = findManagedType( typeName ); + if ( managedType == null ) { + throw new IllegalArgumentException("Not a managed type: " + typeName); + } + return managedType; + } + + @Override + @Nullable public EntityDomainType findEntityType(@Nullable String entityName) { if ( entityName == null ) { return null; } final ManagedDomainType managedType = managedTypeByName.get( entityName ); - if ( !( managedType instanceof EntityDomainType ) ) { + if ( !( managedType instanceof EntityDomainType entityDomainType ) ) { return null; } - return (EntityDomainType) managedType; + return entityDomainType; } @Override - public EmbeddableDomainType embeddable(String embeddableName) { + public EntityDomainType entity(String entityName) { + final EntityDomainType entityType = findEntityType( entityName ); + if ( entityType == null ) { + // per JPA + throw new IllegalArgumentException("Not an entity: " + entityName); + } + return entityType; + } + + @Override + @Nullable public EmbeddableDomainType findEmbeddableType(@Nullable String embeddableName) { if ( embeddableName == null ) { return null; } final ManagedDomainType managedType = managedTypeByName.get( embeddableName ); - if ( !( managedType instanceof EmbeddableDomainType ) ) { + if ( !( managedType instanceof EmbeddableDomainType embeddableDomainType) ) { return null; } - return (EmbeddableDomainType) managedType; + return embeddableDomainType; + } + + @Override + public EmbeddableDomainType embeddable(String embeddableName) { + final EmbeddableDomainType embeddableType = findEmbeddableType( embeddableName ); + if ( embeddableType == null ) { + throw new IllegalArgumentException("Not an embeddable: " + embeddableName); + } + return embeddableType; } @Override @@ -172,7 +200,7 @@ public EntityDomainType getHqlEntityReference(String entityName) { entityName = importInfo.importedName; } - final EntityDomainType entityDescriptor = entity( entityName ); + final EntityDomainType entityDescriptor = findEntityType( entityName ); if ( entityDescriptor != null ) { //noinspection unchecked return (EntityDomainType) entityDescriptor; @@ -201,13 +229,23 @@ public EntityDomainType resolveHqlEntityReference(String entityName) { } @Override - public ManagedDomainType findManagedType(Class cls) { + @Nullable public ManagedDomainType findManagedType(Class cls) { //noinspection unchecked return (ManagedDomainType) managedTypeByClass.get( cls ); } @Override - public EntityDomainType findEntityType(Class cls) { + public ManagedDomainType managedType(Class cls) { + final ManagedDomainType type = findManagedType( cls ); + if ( type == null ) { + // per JPA + throw new IllegalArgumentException( "Not a managed type: " + cls ); + } + return type; + } + + @Override + @Nullable public EntityDomainType findEntityType(Class cls) { final ManagedType type = managedTypeByClass.get( cls ); if ( !( type instanceof EntityDomainType ) ) { return null; @@ -217,35 +255,31 @@ public EntityDomainType findEntityType(Class cls) { } @Override - public ManagedDomainType managedType(Class cls) { - final ManagedType type = managedTypeByClass.get( cls ); - if ( type == null ) { - // per JPA - throw new IllegalArgumentException( "Not a managed type: " + cls ); + public EntityDomainType entity(Class cls) { + final EntityDomainType entityType = findEntityType( cls ); + if ( entityType == null ) { + throw new IllegalArgumentException( "Not an entity: " + cls.getName() ); } - - //noinspection unchecked - return (ManagedDomainType) type; + return entityType; } @Override - public EntityDomainType entity(Class cls) { + public @Nullable EmbeddableDomainType findEmbeddableType(Class cls) { final ManagedType type = managedTypeByClass.get( cls ); - if ( !( type instanceof EntityDomainType ) ) { - throw new IllegalArgumentException( "Not an entity: " + cls.getName() ); + if ( !( type instanceof EmbeddableDomainType ) ) { + return null; } //noinspection unchecked - return (EntityDomainType) type; + return (EmbeddableDomainType) type; } @Override public EmbeddableDomainType embeddable(Class cls) { - final ManagedType type = managedTypeByClass.get( cls ); - if ( !( type instanceof EmbeddableDomainType ) ) { + final EmbeddableDomainType embeddableType = findEmbeddableType( cls ); + if ( embeddableType == null ) { throw new IllegalArgumentException( "Not an embeddable: " + cls.getName() ); } - //noinspection unchecked - return (EmbeddableDomainType) type; + return embeddableType; } private Collection> getAllManagedTypes() { @@ -441,7 +475,7 @@ private void applyNamedEntityGraphs(Collection named definition.getEntityName(), definition.getJpaEntityName() ); - final EntityDomainType entityType = entity( definition.getEntityName() ); + final EntityDomainType entityType = findEntityType( definition.getEntityName() ); if ( entityType == null ) { throw new IllegalArgumentException( "Attempted to register named entity graph [" + definition.getRegisteredName() diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappingMetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappingMetamodelImpl.java index afe60f76f8..dc4d46b655 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappingMetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappingMetamodelImpl.java @@ -17,6 +17,7 @@ import java.util.function.Function; import java.util.stream.Stream; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.EntityNameResolver; import org.hibernate.HibernateException; import org.hibernate.MappingException; @@ -459,16 +460,31 @@ public Set> getEmbeddables() { return jpaMetamodel.getEmbeddables(); } + @Override + public @Nullable ManagedDomainType findManagedType(@Nullable String typeName) { + return jpaMetamodel.findManagedType( typeName ); + } + @Override public ManagedDomainType managedType(String typeName) { return jpaMetamodel.managedType( typeName ); } + @Override + public @Nullable EntityDomainType findEntityType(@Nullable String entityName) { + return jpaMetamodel.findEntityType( entityName ); + } + @Override public EntityDomainType entity(String entityName) { return jpaMetamodel.entity( entityName ); } + @Override + public @Nullable EmbeddableDomainType findEmbeddableType(@Nullable String embeddableName) { + return jpaMetamodel.findEmbeddableType( embeddableName ); + } + @Override public EmbeddableDomainType embeddable(String embeddableName) { return jpaMetamodel.embeddable( embeddableName ); @@ -494,6 +510,11 @@ public EntityDomainType findEntityType(Class cls) { return jpaMetamodel.findEntityType( cls ); } + @Override + public @Nullable EmbeddableDomainType findEmbeddableType(Class cls) { + return jpaMetamodel.findEmbeddableType( cls ); + } + @Override public String qualifyImportableName(String queryName) { return jpaMetamodel.qualifyImportableName( queryName ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/FullyQualifiedReflectivePathTerminal.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/FullyQualifiedReflectivePathTerminal.java index 3b3dea9c9e..d2b673c7b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/FullyQualifiedReflectivePathTerminal.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/FullyQualifiedReflectivePathTerminal.java @@ -71,7 +71,7 @@ public FullyQualifiedReflectivePathTerminal copy(SqmCopyContext context) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // See if it is an entity-type literal - final EntityDomainType entityDescriptor = creationContext.getJpaMetamodel().entity( fullPath ); + final EntityDomainType entityDescriptor = creationContext.getJpaMetamodel().findEntityType( fullPath ); if ( entityDescriptor != null ) { return new SqmLiteralEntityType<>( entityDescriptor, creationContext.getNodeBuilder() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java index 6eacb6ea6c..8500c7ffb3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java @@ -1242,11 +1242,12 @@ private SqmFromClause buildInferredFromClause(HqlParser.SelectClauseContext sele private EntityDomainType getResultEntity() { final JpaMetamodel jpaMetamodel = creationContext.getJpaMetamodel(); if ( expectedResultEntity != null ) { - final EntityDomainType entityDescriptor = jpaMetamodel.entity( expectedResultEntity ); + final EntityDomainType entityDescriptor = jpaMetamodel.findEntityType( expectedResultEntity ); if ( entityDescriptor == null ) { throw new SemanticException( "Query has no 'from' clause, and the result type '" + expectedResultEntity + "' is not an entity type", query ); } + //noinspection unchecked return (EntityDomainType) entityDescriptor; } else if ( expectedResultType != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index 1d7965ac2a..6a9163094f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -3114,9 +3114,8 @@ private void registerEntityNameUsage( if ( tableGroup.getModelPart() instanceof EmbeddableValuedModelPart ) { persister = null; final EmbeddableDomainType embeddableDomainType = creationContext.getSessionFactory() - .getRuntimeMetamodels() .getJpaMetamodel() - .embeddable( treatTargetTypeName ); + .findEmbeddableType( treatTargetTypeName ); if ( embeddableDomainType == null || !embeddableDomainType.isPolymorphic() ) { return; } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java index b1c471c6db..23d18b5e19 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockSessionFactory.java @@ -779,6 +779,16 @@ public EntityDomainType entity(String entityName) { : null; } + @Override + public @Nullable EntityDomainType findEntityType(@Nullable String entityName) { + if ( isEntityDefined(entityName) ) { + return new MockEntityDomainType<>(entityName); + } + else { + return null; + } + } + @Override public String qualifyImportableName(String queryName) { if (isClassDefined(queryName)) { @@ -794,9 +804,18 @@ else if (isEntityDefined(queryName)) { @Override public ManagedDomainType managedType(String typeName) { + final ManagedDomainType managedType = findManagedType( typeName ); + if ( managedType == null ) { + throw new IllegalArgumentException("Not a managed type: " + typeName); + } + return managedType; + } + + @Override + public @Nullable ManagedDomainType findManagedType(@Nullable String typeName) { final String entityName = qualifyName( typeName ); //noinspection unchecked - return entityName == null ? null : (ManagedDomainType) entity( entityName ); + return entityName == null ? null : (ManagedDomainType) findEntityType( entityName ); } @Override