From 31335d69b1c0b141ad56cb5536f98e3ac94ae144 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Wed, 1 Jan 2025 18:15:36 +0100 Subject: [PATCH 1/9] "subgraph" and "subtype" are words and do not come with hyphens --- design/working/attributes.adoc | 2 +- .../userguide/chapters/fetching/Fetching.adoc | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/design/working/attributes.adoc b/design/working/attributes.adoc index a4ab2799d972..0ec3f171f3c3 100644 --- a/design/working/attributes.adoc +++ b/design/working/attributes.adoc @@ -24,7 +24,7 @@ class ForeignCustomer extends Customer { ---- The general idea is that the attributes are ordered alphabetically, super attributes first. Subtypes are sorted -depth-first and the attributes are sorted alphabetically within each sub-type. So the order of the attributes +depth-first and the attributes are sorted alphabetically within each subtype. So the order of the attributes depends on where we start. Starting from Customer we have: `[address, name, quota, attr1, attr2, taxId, attr3, attr4, vat]` diff --git a/documentation/src/main/asciidoc/userguide/chapters/fetching/Fetching.adoc b/documentation/src/main/asciidoc/userguide/chapters/fetching/Fetching.adoc index 6fb7bd9c6d5a..3adc7ed1304c 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/fetching/Fetching.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/fetching/Fetching.adoc @@ -233,7 +233,7 @@ An EntityGraph is the root of a "load plan" and must correspond to an EntityType [[fetching-strategies-dynamic-fetching-entity-subgraph]] ==== Jakarta Persistence (key) subgraphs -A sub-graph is used to control the fetching of sub-attributes of the AttributeNode it is applied to. +A subgraph is used to control the fetching of sub-attributes of the AttributeNode it is applied to. It is generally defined via the {jpaJavadocUrlPrefix}NamedSubgraph.html[`@NamedSubgraph`] annotation. If we have a `Project` parent entity which has an `employees` child associations, @@ -264,24 +264,24 @@ include::{extrasdir}/fetching-strategies-dynamic-fetching-entity-subgraph-exampl ---- ==== -Specifying a sub-graph is only valid for an attribute (or its "key") whose type is a ManagedType. So +Specifying a subgraph is only valid for an attribute (or its "key") whose type is a ManagedType. So while an EntityGraph must correspond to an EntityType, a Subgraph is legal for any ManagedType. An attribute's key is defined as either: * For a singular attribute, the attribute's type must be an IdentifiableType and that IdentifiableType must - have a composite identifier. The "key sub-graph" is applied to the identifier type. The - non-key sub-graph applies to the attribute's value, which must be a ManagedType. + have a composite identifier. The "key subgraph" is applied to the identifier type. The + non-key subgraph applies to the attribute's value, which must be a ManagedType. * For a plural attribute, the attribute must be a Map and the Map's key value must be a ManagedType. - The "key sub-graph" is applied to the Map's key type. In this case, the non-key sub-graph applies + The "key subgraph" is applied to the Map's key type. In this case, the non-key subgraph applies to the plural attribute's value/element. [[fetching-strategies-dynamic-fetching-entity-subgraph-subtype]] ==== Jakarta Persistence SubGraph sub-typing -SubGraphs can also be sub-type specific. Given an attribute whose value is an inheritance hierarchy, -we can refer to attributes of a specific sub-type using the forms of sub-graph definition that accept -the sub-type Class. +Subgraphs can also be subtype specific. Given an attribute whose value is an inheritance hierarchy, +we can refer to attributes of a specific subtype using the forms of subgraph definition that accept +the subtype Class. [[fetching-strategies-dynamic-fetching-entity-graph-parsing]] @@ -289,7 +289,7 @@ the sub-type Class. Hibernate allows the creation of Jakarta Persistence fetch/load graphs by parsing a textual representation of the graph. Generally speaking, the textual representation of a graph is a comma-separated -list of attribute names, optionally including any sub-graph specifications. +list of attribute names, optionally including any subgraph specifications. `org.hibernate.graph.GraphParser` is the starting point for such parsing operations. [NOTE] @@ -312,7 +312,7 @@ This example actually functions exactly as < Date: Wed, 1 Jan 2025 18:18:19 +0100 Subject: [PATCH 2/9] "subgraph" and "subtype" are words and do not come with hyphens --- .../boot/model/source/internal/hbm/ModelBinder.java | 2 +- .../boot/model/source/spi/CompositeIdentifierSource.java | 2 +- .../boot/model/source/spi/IdentifiableTypeSource.java | 2 +- .../org/hibernate/metamodel/internal/AttributeFactory.java | 2 +- .../org/hibernate/metamodel/mapping/EntityMappingType.java | 2 +- .../hibernate/persister/entity/EntityPropertyMapping.java | 2 +- .../entity/mutation/UpdateCoordinatorStandard.java | 4 ++-- .../lazy/proxy/LazyGroupWithInheritanceTest.java | 2 +- .../orm/test/entitygraph/parser/EntityGraphParserTest.java | 6 +++--- .../org/hibernate/orm/test/fetching/GraphParsingTest.java | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java index fcdd013d82b6..bd1b81090f22 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java @@ -2655,7 +2655,7 @@ else if ( attributeSource instanceof PluralAttributeSource ) { throw new AssertionFailure( String.format( Locale.ENGLISH, - "Unexpected AttributeSource sub-type [%s] as part of composite [%s]", + "Unexpected AttributeSource subtype [%s] as part of composite [%s]", attributeSource.getClass().getName(), attributeSource.getAttributeRole().getFullPath() ) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/CompositeIdentifierSource.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/CompositeIdentifierSource.java index c5211155d46a..b7407761e49e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/CompositeIdentifierSource.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/CompositeIdentifierSource.java @@ -7,7 +7,7 @@ import org.hibernate.boot.model.IdentifierGeneratorDefinition; /** - * Common contract for composite identifiers. Specific sub-types include aggregated + * Common contract for composite identifiers. Specific subtypes include aggregated * (think {@link jakarta.persistence.EmbeddedId}) and non-aggregated (think * {@link jakarta.persistence.IdClass}). * diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/IdentifiableTypeSource.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/IdentifiableTypeSource.java index 444596d70329..39fca454b982 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/IdentifiableTypeSource.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/IdentifiableTypeSource.java @@ -49,7 +49,7 @@ public interface IdentifiableTypeSource extends AttributeSourceContainer { /** * Access the subtype sources for types extending from this type source, * - * @return Sub-type sources + * @return Subtype sources */ Collection getSubTypes(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java index 7e793eec3f28..343551b135ac 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java @@ -787,7 +787,7 @@ else if ( persistenceType == Type.PersistenceType.MAPPED_SUPERCLASS ) { ); } else { - throw new IllegalArgumentException( "Unexpected sub-type: " + persistenceType ); + throw new IllegalArgumentException( "Unexpected subtype: " + persistenceType ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java index 97d8b5554a21..01696c8a03cd 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java @@ -447,7 +447,7 @@ default void visitAttributeMappings(Consumer action) { } /** - * Walk this type's attributes as well as its sub-type's + * Walk this type's attributes as well as its subtypes */ default void visitSubTypeAttributeMappings(Consumer action) { // by default do nothing diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPropertyMapping.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPropertyMapping.java index e8e12bbb39d2..b36b95866ee2 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPropertyMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPropertyMapping.java @@ -108,7 +108,7 @@ private void logDuplicateRegistration(String path, Type existingType, Type type) private void logIncompatibleRegistration(String path, Type existingType, Type type) { if ( LOG.isTraceEnabled() ) { LOG.tracev( - "Skipped adding attribute [{1}] to base-type [{0}] as more than one sub-type defined the attribute using incompatible types (strictly speaking the attributes are not inherited); existing type = [{2}], incoming type = [{3}]", + "Skipped adding attribute [{1}] to base type [{0}] as more than one subtype defined the attribute using incompatible types (strictly speaking the attributes are not inherited); existing type = [{2}], incoming type = [{3}]", getEntityName(), path, existingType, diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java index 8bcfeabd44cb..1ddd90b3744c 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java @@ -138,7 +138,7 @@ public void forceVersionIncrement( Object nextVersion, SharedSessionContractImplementor session) { if ( versionUpdateGroup == null ) { - throw new HibernateException( "Cannot force version increment relative to sub-type; use the root type" ); + throw new HibernateException( "Cannot force version increment relative to subtype; use the root type" ); } doVersionUpdate( null, id, nextVersion, currentVersion, session ); } @@ -151,7 +151,7 @@ public void forceVersionIncrement( boolean batching, SharedSessionContractImplementor session) { if ( versionUpdateGroup == null ) { - throw new HibernateException( "Cannot force version increment relative to sub-type; use the root type" ); + throw new HibernateException( "Cannot force version increment relative to subtype; use the root type" ); } doVersionUpdate( null, id, nextVersion, currentVersion, batching, session ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java index 6e9f1baded9f..a628c4b10e5e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java @@ -95,7 +95,7 @@ public void queryEntityWithAssociationToAbstract(SessionFactoryScope scope) { // todo (HHH-11147) : this is a regression from 4.x // - the condition is that the association from Order to Customer points to the non-root - // entity (Customer) rather than one of its concrete sub-types (DomesticCustomer, + // entity (Customer) rather than one of its concrete subtypes (DomesticCustomer, // ForeignCustomer). We'd have to read the "other table" to be able to resolve the // concrete type. The same holds true for associations to versioned entities as well. // The only viable solution I see would be to join to the "other side" and read the diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java index af2a0322b885..677e436e808c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java @@ -186,10 +186,10 @@ public void testLinkSubtypeParsing() { assertNullOrEmpty( linkToOneNode.getKeySubgraphs() ); - final SubGraphImplementor subGraph = linkToOneNode.getSubGraphMap().get( GraphParsingTestSubEntity.class ); - assertNotNull( subGraph ); + final SubGraphImplementor subgraph = linkToOneNode.getSubGraphMap().get( GraphParsingTestSubEntity.class ); + assertNotNull( subgraph ); - assertBasicAttributes( subGraph, "sub" ); + assertBasicAttributes( subgraph, "sub" ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/fetching/GraphParsingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/fetching/GraphParsingTest.java index 33ddac2e51a6..d5966df8b7b5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/fetching/GraphParsingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/fetching/GraphParsingTest.java @@ -177,7 +177,7 @@ public void testQueryExample() { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // Some entities for illustrating key sub-graphs + // Some entities for illustrating key subgraphs // // NOTE : for the moment I do not add named (sub)graph annotations because // this is only used for discussing graph parsing From f530548ffb5b43d8d5f6fea0eefa3f631c6f9673 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Wed, 1 Jan 2025 18:19:55 +0100 Subject: [PATCH 3/9] Graphpocalypse: major revision/refactoring of EntityGraph support - fix up a bunch of generic typing issues - deprecate some old / obsolete operations - finally implement addTreatedSubgraph() --- .../org/hibernate/graph/AttributeNode.java | 17 +- .../graph/CannotContainSubGraphException.java | 4 +- .../org/hibernate/graph/EntityGraphs.java | 101 +++--- .../main/java/org/hibernate/graph/Graph.java | 123 +++++-- .../java/org/hibernate/graph/GraphParser.java | 2 +- .../java/org/hibernate/graph/RootGraph.java | 72 +--- .../java/org/hibernate/graph/SubGraph.java | 76 ----- .../graph/internal/AbstractGraph.java | 323 +++++++++++------- .../graph/internal/AttributeNodeImpl.java | 144 ++++---- .../graph/internal/RootGraphImpl.java | 83 ++--- .../graph/internal/SubGraphImpl.java | 56 +-- .../graph/spi/AttributeNodeImplementor.java | 41 +-- .../hibernate/graph/spi/GraphImplementor.java | 102 ++---- .../graph/spi/RootGraphImplementor.java | 9 +- .../graph/spi/SubGraphImplementor.java | 21 +- .../AbstractSharedSessionContract.java | 5 +- .../model/domain/AbstractManagedType.java | 68 ++-- .../model/domain/ManagedDomainType.java | 11 +- .../model/domain/internal/EntityTypeImpl.java | 5 - .../domain/internal/JpaMetamodelImpl.java | 9 +- .../main/java/org/hibernate/query/Query.java | 12 + .../query/sqm/internal/AppliedGraphs.java | 8 +- .../domain/SqmPolymorphicRootDescriptor.java | 50 ++- ...StandardEntityGraphTraversalStateImpl.java | 16 +- ...rtyInSubclassIdInMappedSuperclassTest.java | 10 +- .../orm/test/jpa/graphs/EntityGraphTest.java | 60 +++- .../validation/MockSessionFactory.java | 9 +- 27 files changed, 692 insertions(+), 745 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java index e1767bc1b13d..9b91daaea057 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java @@ -5,7 +5,6 @@ package org.hibernate.graph; import java.util.Map; -import jakarta.persistence.Subgraph; import org.hibernate.metamodel.model.domain.PersistentAttribute; @@ -20,20 +19,8 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr PersistentAttribute getAttributeDescriptor(); - Map, SubGraph> getSubGraphs(); - Map, SubGraph> getKeySubGraphs(); - - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default Map getSubgraphs() { - return (Map) getSubGraphs(); - } - - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default Map getKeySubgraphs() { - return (Map) getKeySubGraphs(); - } + Map, ? extends SubGraph> getSubGraphs(); + Map, ? extends SubGraph> getKeySubGraphs(); void addSubGraph(Class subType, SubGraph subGraph); void addKeySubGraph(Class subType, SubGraph subGraph); diff --git a/hibernate-core/src/main/java/org/hibernate/graph/CannotContainSubGraphException.java b/hibernate-core/src/main/java/org/hibernate/graph/CannotContainSubGraphException.java index 134d40d9990a..aa39e02c3e5c 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/CannotContainSubGraphException.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/CannotContainSubGraphException.java @@ -7,8 +7,8 @@ import org.hibernate.HibernateException; /** - * Indicates an attempt was made to add a (key)? sub-graph to an - * attribute type that does not support (key)? sub-graphs. + * Indicates an attempt was made to add a (key)? subgraph to an + * attribute type that does not support (key)? subgraphs. * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java b/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java index 15e6fe64623b..b1891aee19b3 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java @@ -31,40 +31,38 @@ public final class EntityGraphs { * Merges multiple entity graphs into a single graph that specifies the * fetching/loading of all attributes the input graphs specify. * - * @param Root entity type of the query and graph. + * @param Root entity type of the query and graph. * - * @param em EntityManager to use to create the new merged graph. + * @param entityManager EntityManager to use to create the new merged graph. * @param rootType Root type of the entity for which the graph is being merged. - * @param graphs Graphs to merge. + * @param graphs Graphs to merge. * - * @return The merged graph. + * @return The merged graph. */ - @SuppressWarnings("unchecked") - public static EntityGraph merge(EntityManager em, Class rootType, EntityGraph... graphs) { - return merge( (SessionImplementor) em, rootType, (Object[]) graphs ); + @SafeVarargs + public static EntityGraph merge(EntityManager entityManager, Class rootType, EntityGraph... graphs) { + return mergeInternal( (SessionImplementor) entityManager, rootType, graphs ); } @SafeVarargs public static EntityGraph merge(Session session, Class rootType, Graph... graphs) { - return merge( (SessionImplementor) session, rootType, (Object[]) graphs ); + return mergeInternal( (SessionImplementor) session, rootType, graphs ); } @SafeVarargs public static EntityGraph merge(SessionImplementor session, Class rootType, GraphImplementor... graphs) { - return merge( session, rootType, (Object[]) graphs ); + return mergeInternal( session, rootType, graphs ); } - @SuppressWarnings("unchecked") - private static EntityGraph merge(SessionImplementor session, Class rootType, Object... graphs) { - RootGraphImplementor merged = session.createEntityGraph( rootType ); - + private static EntityGraph mergeInternal( + SessionImplementor session, Class rootType, jakarta.persistence.Graph[] graphs) { + final RootGraphImplementor merged = session.createEntityGraph( rootType ); if ( graphs != null ) { - for ( Object graph : graphs ) { + for ( jakarta.persistence.Graph graph : graphs ) { merged.merge( (GraphImplementor) graph ); } } - return merged; } @@ -75,12 +73,14 @@ private static EntityGraph merge(SessionImplementor session, Class roo * @param query The JPA Query * @param graph The graph to apply * @param semantic The semantic to use when applying the graph + * + * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)} */ - @SuppressWarnings("unchecked") - public static List executeList(Query query, EntityGraph graph, GraphSemantic semantic) { + @Deprecated(since = "7.0") + public static @SuppressWarnings("rawtypes") List executeList(Query query, EntityGraph graph, GraphSemantic semantic) { return query.unwrap( org.hibernate.query.Query.class ) - .applyGraph( (RootGraph) graph, semantic ) - .list(); + .applyGraph( (RootGraph) graph, semantic ) + .getResultList(); } /** @@ -94,10 +94,14 @@ public static List executeList(Query query, EntityGraph graph, GraphSemantic sem * @apiNote This signature assumes that the Query's return is an entity and that * the graph applies to that entity's type. JPA does not necessarily * require that, but it is by far the most common usage. + * + * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)} */ - @SuppressWarnings({"unused", "unchecked"}) + @Deprecated(since = "7.0") public static List executeList(TypedQuery query, EntityGraph graph, GraphSemantic semantic) { - return executeList( (Query) query, graph, semantic ); + @SuppressWarnings("unchecked") + org.hibernate.query.Query unwrapped = query.unwrap( org.hibernate.query.Query.class ); + return unwrapped.setEntityGraph( graph, semantic ).getResultList(); } /** @@ -110,12 +114,12 @@ public static List executeList(TypedQuery query, EntityGraph graph, * @param semanticJpaHintName See {@link GraphSemantic#fromHintName} * * @return The result list + * + * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)} */ - @SuppressWarnings({"unused", "unchecked"}) - public static List executeList(Query query, EntityGraph graph, String semanticJpaHintName) { - return query.unwrap( org.hibernate.query.Query.class ) - .applyGraph( (RootGraph) graph, GraphSemantic.fromHintName( semanticJpaHintName ) ) - .list(); + @Deprecated(since = "7.0") + public static @SuppressWarnings("rawtypes") List executeList(Query query, EntityGraph graph, String semanticJpaHintName) { + return executeList( query, graph, GraphSemantic.fromHintName( semanticJpaHintName ) ); } /** @@ -129,10 +133,12 @@ public static List executeList(Query query, EntityGraph graph, String semanticJp * @apiNote This signature assumes that the Query's return is an entity and that * the graph applies to that entity's type. JPA does not necessarily * require that, but it is by far the most common usage. + * + * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)} */ - @SuppressWarnings({"unused", "unchecked"}) + @Deprecated(since = "7.0") public static List executeList(TypedQuery query, EntityGraph graph, String semanticJpaHintName) { - return executeList( (Query) query, graph, semanticJpaHintName ); + return executeList( query, graph, GraphSemantic.fromHintName( semanticJpaHintName ) ); } /** @@ -146,12 +152,12 @@ public static List executeList(TypedQuery query, EntityGraph graph, * entity graph applied to a query is {@link GraphSemantic#FETCH}. * This is simply knowledge from JPA EG discussions, nothing that * is specifically mentioned or discussed in the spec. + * + * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)} */ - @SuppressWarnings({"unused", "unchecked"}) - public static List executeList(Query query, EntityGraph graph) { - return query.unwrap( org.hibernate.query.Query.class ) - .applyFetchGraph( (RootGraph) graph ) - .list(); + @Deprecated(since = "7.0") + public static @SuppressWarnings("rawtypes") List executeList(Query query, EntityGraph graph) { + return executeList( query, graph, GraphSemantic.FETCH ); } /** @@ -164,16 +170,14 @@ public static List executeList(Query query, EntityGraph graph) { * @apiNote This signature assumes that the Query's return is an entity and that * the graph applies to that entity's type. JPA does not necessarily * require that, but it is by far the most common usage. + * + * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)} */ - @SuppressWarnings("unused") + @Deprecated(since = "7.0") public static List executeList(TypedQuery query, EntityGraph graph) { return executeList( query, graph, GraphSemantic.FETCH ); } - // todo : ? - we could add JPA's other Query execution methods - // but really, I think unwrapping as Hibernate's Query and using our - // "proprietary" methods is better (this class is "proprietary" too). - /** * Compares two entity graphs and returns {@code true} if they are equal, * ignoring attribute order. @@ -191,8 +195,8 @@ public static boolean areEqual(EntityGraph a, EntityGraph b) { return false; } - List> aNodes = a.getAttributeNodes(); - List> bNodes = b.getAttributeNodes(); + final List> aNodes = a.getAttributeNodes(); + final List> bNodes = b.getAttributeNodes(); if ( aNodes.size() != bNodes.size() ) { return false; @@ -226,7 +230,8 @@ public static boolean areEqual(AttributeNode a, AttributeNode b) { return false; } if ( a.getAttributeName().equals( b.getAttributeName() ) ) { - return areEqual( a.getSubgraphs(), b.getSubgraphs() ) && areEqual( a.getKeySubgraphs(), b.getKeySubgraphs() ); + return areEqual( a.getSubgraphs(), b.getSubgraphs() ) + && areEqual( a.getKeySubgraphs(), b.getKeySubgraphs() ); } else { return false; @@ -237,7 +242,9 @@ public static boolean areEqual(AttributeNode a, AttributeNode b) { * Compares two entity subgraph maps and returns {@code true} if they are equal, * ignoring order. */ - public static boolean areEqual(@SuppressWarnings("rawtypes") Map a, @SuppressWarnings("rawtypes") Map b) { + public static boolean areEqual( + @SuppressWarnings("rawtypes") Map a, + @SuppressWarnings("rawtypes") Map b) { if ( a == b ) { return true; } @@ -246,9 +253,9 @@ public static boolean areEqual(@SuppressWarnings("rawtypes") Map aKeys = a.keySet(); + final Set aKeys = a.keySet(); @SuppressWarnings("rawtypes") - Set bKeys = b.keySet(); + final Set bKeys = b.keySet(); if ( aKeys.equals( bKeys ) ) { for ( Class clazz : aKeys ) { @@ -282,16 +289,16 @@ public static boolean areEqual(@SuppressWarnings("rawtypes") Subgraph a, @Suppre } @SuppressWarnings("unchecked") - List> aNodes = a.getAttributeNodes(); + final List> aNodes = a.getAttributeNodes(); @SuppressWarnings("unchecked") - List> bNodes = b.getAttributeNodes(); + final List> bNodes = b.getAttributeNodes(); if ( aNodes.size() != bNodes.size() ) { return false; } for ( AttributeNode aNode : aNodes ) { - String attributeName = aNode.getAttributeName(); + final String attributeName = aNode.getAttributeName(); AttributeNode bNode = null; for ( AttributeNode bCandidate : bNodes ) { if ( attributeName.equals( bCandidate.getAttributeName() ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java index 41f06e1c2a19..57cc15e46bdc 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java @@ -58,14 +58,20 @@ default SubGraph addPluralSubgraph(PluralAttribute at * @param mutable controls whether the resulting {@code Graph} is mutable * * @throws CannotBecomeEntityGraphException If the named attribute is not entity-valued + * + * @deprecated This will be removed */ + @Deprecated(since = "7.0", forRemoval = true) RootGraph makeRootGraph(String name, boolean mutable) throws CannotBecomeEntityGraphException; /** * Create a new (mutable or immutable) {@link SubGraph} rooted at * this {@link Graph}. + * + * @deprecated This will be removed */ + @Deprecated(since = "7.0", forRemoval = true) SubGraph makeSubGraph(boolean mutable); @Override @@ -75,40 +81,64 @@ RootGraph makeRootGraph(String name, boolean mutable) // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AttributeNode handling - /** - * Ultimately only needed for implementing - * {@link jakarta.persistence.EntityGraph#getAttributeNodes()} - * and {@link jakarta.persistence.Subgraph#getAttributeNodes()} - */ - List> getGraphAttributeNodes(); - /** * Find an already existing AttributeNode by attributeName within * this container + * + * @see #getAttributeNode(String) */ AttributeNode findAttributeNode(String attributeName); + @Override + default jakarta.persistence.AttributeNode getAttributeNode(String attributeName) { + return findAttributeNode( attributeName ); + } + /** * Find an already existing AttributeNode by corresponding attribute * reference, within this container. + * + * @see #getAttributeNode(Attribute) */ AttributeNode findAttributeNode(PersistentAttribute attribute); + @Override + default jakarta.persistence.AttributeNode getAttributeNode(Attribute attribute) { + return findAttributeNode( (PersistentAttribute) attribute ); + } + + /** + * Add an {@link AttributeNode} (with no associated {@link SubGraph}) + * to this container by attribute reference. + * + * @see #addAttributeNode(Attribute) + */ + AttributeNode addAttributeNode(PersistentAttribute attribute) + throws CannotContainSubGraphException; + + @Override + default jakarta.persistence.AttributeNode addAttributeNode(Attribute attribute) { + return addAttributeNode( (PersistentAttribute) attribute ); + } + /** * Get a list of all existing AttributeNodes within this container. + * + * @see #getAttributeNodes */ List> getAttributeNodeList(); /** - * Add an {@link AttributeNode} (with no associated {@link SubGraph}) - * to this container by attribute reference. + * @deprecated Use {@link #getAttributeNodeList} */ - AttributeNode addAttributeNode(PersistentAttribute attribute); - + @Deprecated(since = "7.0", forRemoval = true) + default List> getGraphAttributeNodes() { + return getAttributeNodeList(); + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // sub graph nodes + // Subgraph nodes /** * Create and return a new (mutable) {@link SubGraph} associated with @@ -116,11 +146,9 @@ RootGraph makeRootGraph(String name, boolean mutable) * * @apiNote If no such AttributeNode exists yet, it is created. */ - SubGraph addSubGraph(String attributeName) - throws CannotContainSubGraphException; + SubGraph addSubGraph(String attributeName); - SubGraph addSubGraph(String attributeName, Class type) - throws CannotContainSubGraphException; + SubGraph addSubGraph(String attributeName, Class type); /** * Create and return a new (mutable) {@link SubGraph} associated with @@ -128,32 +156,65 @@ SubGraph addSubGraph(String attributeName, Class type) * * @apiNote If no such AttributeNode exists yet, it is created. */ - SubGraph addSubGraph(PersistentAttribute attribute) - throws CannotContainSubGraphException; + SubGraph addSubGraph(PersistentAttribute attribute); - SubGraph addSubGraph(PersistentAttribute attribute, Class type) - throws CannotContainSubGraphException; + SubGraph addSubGraph(PersistentAttribute attribute, Class type); - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // key sub graph nodes + @Override + default SubGraph addTreatedSubgraph(Attribute attribute, Class type) { + return addSubGraph( (PersistentAttribute) attribute, type ); + } - SubGraph addKeySubGraph(String attributeName) - throws CannotContainSubGraphException; - SubGraph addKeySubGraph(String attributeName, Class type) - throws CannotContainSubGraphException; + @Override + default SubGraph addSubgraph(Attribute attribute) { + return addSubGraph( (PersistentAttribute) attribute ); + } - SubGraph addKeySubGraph(PersistentAttribute attribute) - throws CannotContainSubGraphException; - SubGraph addKeySubGraph(PersistentAttribute attribute, Class type) - throws CannotContainSubGraphException; + @Override + default SubGraph addSubgraph(Attribute attribute, Class type) { + return addSubGraph( (PersistentAttribute) attribute, type ); + } + + @Override + default SubGraph addSubgraph(String name) { + return addSubGraph( name ); + } + @Override + default SubGraph addSubgraph(String name, Class type) { + return addSubGraph( name, type ); + } + + SubGraph addKeySubGraph(String attributeName); + SubGraph addKeySubGraph(String attributeName, Class type); + + SubGraph addKeySubGraph(PersistentAttribute attribute); + SubGraph addKeySubGraph(PersistentAttribute attribute, Class type); @Override - SubGraph addTreatedSubgraph(Attribute attribute, Class type); + default SubGraph addKeySubgraph(Attribute attribute) { + return addKeySubGraph( (PersistentAttribute) attribute ); + } + + @Override + default SubGraph addKeySubgraph(Attribute attribute, Class type) { + return addKeySubGraph( (PersistentAttribute) attribute, type ); + } + + @Override + default SubGraph addKeySubgraph(String name) { + return addKeySubGraph( name ); + } + + @Override + default SubGraph addKeySubgraph(String name, Class type) { + return addKeySubGraph( name, type ); + } @Override SubGraph addTreatedElementSubgraph(PluralAttribute attribute, Class type); @Override SubGraph addTreatedMapKeySubgraph(MapAttribute attribute, Class type); + } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/GraphParser.java b/hibernate-core/src/main/java/org/hibernate/graph/GraphParser.java index 21666ee07706..837a43579037 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/GraphParser.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/GraphParser.java @@ -22,7 +22,7 @@ * The {@link #parse} methods all create a root {@link jakarta.persistence.EntityGraph} * based on the passed entity class and parse the graph string into that root graph. *

- * The {@link #parseInto} methods parse the graph string into a passed graph, which may be a sub-graph + * The {@link #parseInto} methods parse the graph string into a passed graph, which may be a subgraph *

* Multiple graphs made for the same entity type can be merged. See {@link EntityGraphs#merge(SessionImplementor, Class, GraphImplementor...)}. * diff --git a/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java index e3047d075cd3..8d7fd652d513 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java @@ -4,13 +4,7 @@ */ package org.hibernate.graph; -import java.util.List; -import jakarta.persistence.AttributeNode; import jakarta.persistence.EntityGraph; -import jakarta.persistence.Subgraph; -import jakarta.persistence.metamodel.Attribute; - -import org.hibernate.metamodel.model.domain.PersistentAttribute; /** * Extends the JPA-defined {@link EntityGraph} with additional operations. @@ -23,65 +17,19 @@ public interface RootGraph extends Graph, EntityGraph { @Override + RootGraph makeCopy(boolean mutable); + + @Override @Deprecated(forRemoval = true) RootGraph makeRootGraph(String name, boolean mutable); + @Override @Deprecated(forRemoval = true) SubGraph makeSubGraph(boolean mutable); - @Override - SubGraph addSubclassSubgraph(Class type); - - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default List> getAttributeNodes() { - return (List) getAttributeNodeList(); - } - - @Override - default void addAttributeNodes(String... names) { - if ( names != null ) { - for ( String name : names ) { - addAttributeNode( name ); - } - } - } - - @Override - default SubGraph addSubgraph(Attribute attribute) { - return addSubGraph( (PersistentAttribute) attribute ); - } - - @Override - default Subgraph addSubgraph(Attribute attribute, Class type) { - return addSubGraph( (PersistentAttribute) attribute, type ); - } - - @Override - default SubGraph addSubgraph(String name) { - return addSubGraph( name ); - } - - @Override - default SubGraph addSubgraph(String name, Class type) { - return addSubGraph( name, type ); - } - - @Override - default SubGraph addKeySubgraph(Attribute attribute) { - return addKeySubGraph( (PersistentAttribute) attribute ); - } - - @Override - default SubGraph addKeySubgraph(Attribute attribute, Class type) { - return addKeySubGraph( (PersistentAttribute) attribute, type ); - } - - @Override - default SubGraph addKeySubgraph(String name) { - return addKeySubGraph( name ); - } - - @Override - default Subgraph addKeySubgraph(String name, Class type) { - return addKeySubGraph( name, type ); + /** + * @deprecated Planned for removal in JPA 4 + */ + @Override @Deprecated(forRemoval = true) + default SubGraph addSubclassSubgraph(Class type) { + throw new UnsupportedOperationException("This operation will be removed in JPA 4"); } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/SubGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/SubGraph.java index ffee6efb75ae..51ae23e706f0 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/SubGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/SubGraph.java @@ -4,12 +4,7 @@ */ package org.hibernate.graph; -import java.util.List; - import jakarta.persistence.Subgraph; -import jakarta.persistence.metamodel.Attribute; - -import org.hibernate.metamodel.model.domain.PersistentAttribute; /** * Extends the JPA-defined {@link Subgraph} with additional operations. @@ -20,77 +15,6 @@ * @see RootGraph */ public interface SubGraph extends Graph, Subgraph { - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default List> getAttributeNodes() { - return (List) getAttributeNodeList(); - } - - @Override - default void addAttributeNodes(String... names) { - if ( names == null ) { - return; - } - - for ( String name : names ) { - addAttributeNode( name ); - } - } - - @Override - default void addAttributeNodes(Attribute... attribute) { - if ( attribute == null ) { - return; - } - - for ( Attribute node : attribute ) { - assert node instanceof PersistentAttribute; - addAttributeNode( node ); - } - } - - @Override - default SubGraph addSubgraph(Attribute attribute) { - return addSubGraph( (PersistentAttribute) attribute ); - } - - @Override - default SubGraph addSubgraph(Attribute attribute, Class type) { - return addSubGraph( (PersistentAttribute) attribute, type ); - } - - - @Override - default SubGraph addSubgraph(String name) { - return addSubGraph( name ); - } - - @Override - default SubGraph addSubgraph(String name, Class type) { - return addSubGraph( name, type ); - } - - - @Override - default SubGraph addKeySubgraph(Attribute attribute) { - return addKeySubGraph( (PersistentAttribute) attribute ); - } - - @Override - default SubGraph addKeySubgraph(Attribute attribute, Class type) { - return addKeySubGraph( (PersistentAttribute) attribute, type ); - } - - @Override - default SubGraph addKeySubgraph(String name) { - return addKeySubGraph( name ); - } - - @Override - default SubGraph addKeySubgraph(String name, Class type) { - return addKeySubGraph( name, type ); - } - @Override default Class getClassType() { return getGraphedType().getJavaType(); diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java index 820fd934ce21..67e6eab64f40 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java @@ -8,17 +8,18 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Consumer; +import jakarta.persistence.metamodel.MapAttribute; +import jakarta.persistence.metamodel.PluralAttribute; +import org.hibernate.AssertionFailure; import org.hibernate.graph.AttributeNode; import org.hibernate.graph.CannotBecomeEntityGraphException; -import org.hibernate.graph.CannotContainSubGraphException; import org.hibernate.graph.RootGraph; import org.hibernate.graph.SubGraph; 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.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; @@ -27,6 +28,8 @@ import jakarta.persistence.metamodel.Attribute; import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.Collections.unmodifiableMap; /** * Base class for {@link RootGraph} and {@link SubGraph} implementations. @@ -35,220 +38,290 @@ */ public abstract class AbstractGraph extends AbstractGraphNode implements GraphImplementor { private final ManagedDomainType managedType; - private Map, AttributeNodeImplementor> attrNodeMap; + private Map, AttributeNodeImplementor> attributeNodes; public AbstractGraph(ManagedDomainType managedType, boolean mutable) { super( mutable ); this.managedType = managedType; } - protected AbstractGraph(GraphImplementor original, boolean mutable) { - this( original.getGraphedType(), mutable ); - this.attrNodeMap = new ConcurrentHashMap<>( original.getAttributeNodeList().size() ); - original.visitAttributeNodes( - node -> attrNodeMap.put( - node.getAttributeDescriptor(), - node.makeCopy( mutable ) - ) - ); + protected AbstractGraph(ManagedDomainType managedType, GraphImplementor graph, boolean mutable) { + this( managedType, mutable ); + attributeNodes = new HashMap<>( graph.getAttributeNodesByAttribute().size() ); + graph.getAttributeNodesByAttribute() + .forEach( (attribute, node) -> attributeNodes.put( attribute, node.makeCopy( mutable ) ) ); + } + + protected AbstractGraph(GraphImplementor graph, boolean mutable) { + this( graph.getGraphedType(), graph, mutable ); } @Override - public ManagedDomainType getGraphedType() { + public final ManagedDomainType getGraphedType() { return managedType; } - @Override + @Override @Deprecated(forRemoval = true) public RootGraphImplementor makeRootGraph(String name, boolean mutable) { if ( getGraphedType() instanceof EntityDomainType ) { return new RootGraphImpl<>( name, this, mutable); } - - throw new CannotBecomeEntityGraphException( - "Cannot transform Graph to RootGraph - " + getGraphedType() + " is not an EntityType" - ); - } - - @Override - @SuppressWarnings("unchecked") - public void merge(GraphImplementor other) { - if ( other == null ) { - return; - } - - for ( AttributeNodeImplementor attributeNode : other.getAttributeNodeImplementors() ) { - final AttributeNodeImplementor localAttributeNode = findAttributeNode( - (PersistentAttribute) attributeNode.getAttributeDescriptor() + else { + throw new CannotBecomeEntityGraphException( + "Cannot transform Graph to RootGraph because '" + getGraphedType() + "' is not an entity type" ); - if ( localAttributeNode != null ) { - // keep the local one, but merge in the incoming one - localAttributeNode.merge( attributeNode ); - } - else { - addAttributeNode( attributeNode.makeCopy( true ) ); - } - } - - } - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // AttributeNode handling - - - @Override - public AttributeNodeImplementor getAttributeNode(String attributeName) { - if ( attrNodeMap == null ) { - return null; } - final PersistentAttribute attribute = managedType.findAttributeInSuperTypes( attributeName ); - //noinspection unchecked - return (AttributeNodeImplementor) attrNodeMap.get( attribute ); } @Override - public AttributeNodeImplementor getAttributeNode(Attribute attribute) { - return null; - } - - @Override - public void visitAttributeNodes(Consumer> consumer) { - if ( attrNodeMap != null ) { - attrNodeMap.forEach( (attribute, nodeImplementor) -> consumer.accept( nodeImplementor ) ); + public void merge(GraphImplementor graph) { + if ( graph != null ) { + verifyMutability(); + graph.getAttributeNodesByAttribute().forEach( (attribute, node) -> { + final AttributeNodeImplementor existingNode = findAttributeNode( attribute ); + if ( existingNode != null ) { + // keep the local one, but merge in the incoming one + mergeNode( node, existingNode ); + } + else { + addAttributeNode( attribute, node.makeCopy( true ) ); + } + } ); } } - @Override - public List> getAttributeNodeList() { - if ( attrNodeMap == null ) { - return emptyList(); + private static void mergeNode(AttributeNodeImplementor node, AttributeNodeImplementor existingNode) { + if ( existingNode.getAttributeDescriptor() == node.getAttributeDescriptor() ) { + @SuppressWarnings("unchecked") // safe, we just checked + final AttributeNodeImplementor castNode = (AttributeNodeImplementor) node; + existingNode.merge( castNode ); } else { - final List> result = new ArrayList<>(); - visitAttributeNodes( result::add ); - return result; + throw new AssertionFailure( "Attributes should have been identical" ); } } - @Override - public AttributeNodeImplementor addAttributeNode(AttributeNodeImplementor incomingAttributeNode) { - verifyMutability(); - - AttributeNodeImplementor attributeNode = null; - if ( attrNodeMap == null ) { - attrNodeMap = new HashMap<>(); - } - else { - attributeNode = attrNodeMap.get( incomingAttributeNode.getAttributeDescriptor() ); - } - + private void addAttributeNode(PersistentAttribute attribute, AttributeNodeImplementor node) { + final AttributeNodeImplementor attributeNode = getNodeForPut( node.getAttributeDescriptor() ); if ( attributeNode == null ) { - attributeNode = incomingAttributeNode; - attrNodeMap.put( incomingAttributeNode.getAttributeDescriptor(), attributeNode ); + attributeNodes.put( attribute, node ); } else { - @SuppressWarnings("rawtypes") - final AttributeNodeImplementor attributeNodeFinal = attributeNode; - incomingAttributeNode.visitSubGraphs( - // we assume the subGraph has been properly copied if needed - (subType, subGraph) -> attributeNodeFinal.addSubGraph( subGraph ) - ); + // we assume the subgraph has been properly copied if needed + node.getSubGraphMap().forEach( (subtype, subgraph) -> attributeNode.addSubGraph( subgraph ) ); } + } - return attributeNode; + @Override + public List> getAttributeNodeList() { + return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() ); } @Override - @SuppressWarnings("unchecked") public AttributeNodeImplementor findAttributeNode(String attributeName) { - PersistentAttribute attribute = managedType.findAttributeInSuperTypes( attributeName ); - if ( attribute instanceof SqmPathSource && ( (SqmPathSource) attribute ).isGeneric() ) { - attribute = managedType.findConcreteGenericAttribute( attributeName ); - } - return attribute == null ? null : findAttributeNode( (PersistentAttribute) attribute ); + final PersistentAttribute attribute = findAttributeInSupertypes( attributeName ); + @SuppressWarnings("unchecked") // The JPA API is unsafe by nature + final PersistentAttribute result = (PersistentAttribute) attribute; + return attribute == null ? null : findAttributeNode( result ); } @Override - @SuppressWarnings("unchecked") public AttributeNodeImplementor findAttributeNode(PersistentAttribute attribute) { - return attrNodeMap == null ? null : (AttributeNodeImplementor) attrNodeMap.get( attribute ); + return attributeNodes == null ? null : getNode( attribute ); } @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - public List> getGraphAttributeNodes() { - return (List) getAttributeNodeImplementors(); + public List> getAttributeNodes() { + return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() ); } @Override public List> getAttributeNodeImplementors() { - return attrNodeMap == null ? emptyList() : new ArrayList<>( attrNodeMap.values() ); + return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() ); } @Override - public AttributeNodeImplementor addAttributeNode(String attributeName) throws CannotContainSubGraphException { + public Map, AttributeNodeImplementor> getAttributeNodesByAttribute() { + return attributeNodes == null ? emptyMap() : unmodifiableMap( attributeNodes ); + } + + @Override + public AttributeNodeImplementor addAttributeNode(String attributeName) { return findOrCreateAttributeNode( attributeName ); } @Override - public AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute) - throws CannotContainSubGraphException { + public AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute) { return findOrCreateAttributeNode( attribute ); } @Override public AttributeNodeImplementor addAttributeNode(Attribute attribute) { - //noinspection unchecked - return (AttributeNodeImplementor) findOrCreateAttributeNode( (PersistentAttribute) attribute ); + return addAttributeNode( (PersistentAttribute) attribute ); } @Override public void addAttributeNodes(String... attributeNames) { - for ( int i = 0; i < attributeNames.length; i++ ) { - addAttributeNode( attributeNames[i] ); + for ( String attributeName : attributeNames ) { + addAttributeNode( attributeName ); } } @Override @SafeVarargs public final void addAttributeNodes(Attribute... attributes) { - for ( int i = 0; i < attributes.length; i++ ) { - addAttributeNode( attributes[i] ); + for ( Attribute attribute : attributes ) { + addAttributeNode( attribute ); } } @Override public void removeAttributeNode(String attributeName) { - final PersistentAttribute attribute = managedType.findAttribute( attributeName ); - attrNodeMap.remove( attribute ); + attributeNodes.remove( managedType.findAttribute( attributeName ) ); } @Override public void removeAttributeNode(Attribute attribute) { - attrNodeMap.remove( (PersistentAttribute) attribute ); + attributeNodes.remove( (PersistentAttribute) attribute ); } @Override - public void removeAttributeNodes(Attribute.PersistentAttributeType nodeTypes) { - attrNodeMap.entrySet().removeIf( entry -> entry.getKey().getPersistentAttributeType() == nodeTypes ); + public void removeAttributeNodes(Attribute.PersistentAttributeType nodeType) { + attributeNodes.keySet().removeIf( entry -> entry.getPersistentAttributeType() == nodeType ); } @Override - @SuppressWarnings("unchecked") public AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute) { verifyMutability(); - - AttributeNodeImplementor attrNode = null; - if ( attrNodeMap == null ) { - attrNodeMap = new HashMap<>(); + final AttributeNodeImplementor node = getNodeForPut( attribute ); + if ( node == null ) { + final AttributeNodeImpl newAttrNode = new AttributeNodeImpl<>( attribute, isMutable() ); + attributeNodes.put( attribute, newAttrNode ); + return newAttrNode; } else { - attrNode = (AttributeNodeImplementor) attrNodeMap.get( attribute ); + return node; } + } + + @Override + public AttributeNodeImplementor findOrCreateAttributeNode(String attributeName) { + final PersistentAttribute attribute = getAttribute( attributeName ); + @SuppressWarnings("unchecked") // The JPA API is unsafe by nature + final PersistentAttribute persistentAttribute = (PersistentAttribute) attribute; + return findOrCreateAttributeNode( persistentAttribute ); + } + + private PersistentAttribute findAttributeInSupertypes(String attributeName) { + final PersistentAttribute attribute = managedType.findAttributeInSuperTypes( attributeName ); + return attribute instanceof SqmPathSource sqmPathSource && sqmPathSource.isGeneric() + ? managedType.findConcreteGenericAttribute( attributeName ) + : attribute; + } + + private PersistentAttribute getAttribute(String attributeName) { + final PersistentAttribute attribute = managedType.getAttribute( attributeName ); + return attribute instanceof SqmPathSource sqmPathSource && sqmPathSource.isGeneric() + ? managedType.findConcreteGenericAttribute( attributeName ) + : attribute; + } - if ( attrNode == null ) { - attrNode = new AttributeNodeImpl<>(attribute, isMutable()); - attrNodeMap.put( attribute, attrNode ); + private AttributeNodeImplementor getNodeForPut(PersistentAttribute attribute) { + if ( attributeNodes == null ) { + attributeNodes = new HashMap<>(); + return null; + } + else { + return getNode( attribute ); } + } + + @SuppressWarnings("unchecked") + private AttributeNodeImplementor getNode(PersistentAttribute attribute) { + return (AttributeNodeImplementor) attributeNodes.get( attribute ); + } + + @Override + @SuppressWarnings("unchecked") // The JPA API is unsafe by nature + public SubGraphImplementor addSubGraph(String attributeName) { + return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeSubGraph(); + } + + @Override + public SubGraphImplementor addSubGraph(String attributeName, Class subType) { + return findOrCreateAttributeNode( attributeName ).makeSubGraph( subType ); + } + + @Override + public SubGraphImplementor addSubGraph(PersistentAttribute attribute) { + return findOrCreateAttributeNode( attribute ).makeSubGraph(); + } + + @Override + public SubGraphImplementor addSubGraph( + PersistentAttribute attribute, Class subType) { + return findOrCreateAttributeNode( attribute ).makeSubGraph( subType ); + } + + @Override + public SubGraphImplementor addTreatedSubgraph(Attribute attribute, Class type) { + // TODO Test this it's probably not right! + final ManagedDomainType managedDomainType = getGraphedType().getMetamodel().managedType( type ); + return new SubGraphImpl<>( managedDomainType,false ); + } + + @Override + @SuppressWarnings("unchecked") // The JPA API is unsafe by nature + public SubGraphImplementor addKeySubGraph(String attributeName) { + return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeKeySubGraph(); + } - return attrNode; + @Override + public SubGraphImplementor addKeySubGraph(String attributeName, Class subtype) { + return findOrCreateAttributeNode( attributeName ).makeKeySubGraph( subtype ); + } + + @Override + public SubGraphImplementor addKeySubGraph(PersistentAttribute attribute) { + return findOrCreateAttributeNode( attribute ).makeKeySubGraph(); + } + + @Override + public SubGraphImplementor addKeySubGraph( + PersistentAttribute attribute, Class subType) { + return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subType ); + } + + ////////////////// TODO ////////////////// + + @Override + public SubGraphImplementor addTreatedElementSubgraph( + PluralAttribute attribute, + Class type) { + throw new UnsupportedOperationException( "Not yet implemented" ); + } + + @Override + public SubGraphImplementor addTreatedMapKeySubgraph(MapAttribute attribute, Class type) { + throw new UnsupportedOperationException( "Not yet implemented" ); + } + + @Override + public SubGraphImplementor addElementSubgraph(PluralAttribute attribute) { + throw new UnsupportedOperationException( "Not yet implemented" ); + } + + @Override + public SubGraphImplementor addElementSubgraph(String attributeName) { + throw new UnsupportedOperationException( "Not yet implemented" ); + } + + @Override + public SubGraphImplementor addElementSubgraph(String attributeName, Class type) { + throw new UnsupportedOperationException( "Not yet implemented" ); + } + + @Override + public SubGraphImplementor addMapKeySubgraph(MapAttribute attribute) { + throw new UnsupportedOperationException( "Not yet implemented" ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java index 37e641e0fd7a..96b825a3b181 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java @@ -12,7 +12,6 @@ import org.hibernate.graph.CannotContainSubGraphException; import org.hibernate.graph.SubGraph; import org.hibernate.graph.spi.AttributeNodeImplementor; -import org.hibernate.graph.spi.GraphImplementor; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType; @@ -35,8 +34,8 @@ public class AttributeNodeImpl implements AttributeNodeImplementor { private final PersistentAttribute attribute; - private Map, SubGraphImplementor> subGraphMap; - private Map, SubGraphImplementor> keySubGraphMap; + private Map, SubGraphImplementor> subgraphMap; + private Map, SubGraphImplementor> keySubgraphMap; public AttributeNodeImpl(PersistentAttribute attribute, boolean mutable) { this(attribute, null, null, mutable); @@ -47,13 +46,13 @@ public AttributeNodeImpl(PersistentAttribute attribute, boolean mutabl */ private AttributeNodeImpl( PersistentAttribute attribute, - Map, SubGraphImplementor> subGraphMap, - Map, SubGraphImplementor> keySubGraphMap, + Map, SubGraphImplementor> subgraphMap, + Map, SubGraphImplementor> keySubgraphMap, boolean mutable) { super( mutable ); this.attribute = attribute; - this.subGraphMap = subGraphMap; - this.keySubGraphMap = keySubGraphMap; + this.subgraphMap = subgraphMap; + this.keySubgraphMap = keySubgraphMap; } @Override @@ -68,12 +67,12 @@ public PersistentAttribute getAttributeDescriptor() { @Override public Map, SubGraphImplementor> getSubGraphMap() { - return subGraphMap == null ? emptyMap() : subGraphMap; + return subgraphMap == null ? emptyMap() : subgraphMap; } @Override public Map, SubGraphImplementor> getKeySubGraphMap() { - return keySubGraphMap == null ? emptyMap() : keySubGraphMap; + return keySubgraphMap == null ? emptyMap() : keySubgraphMap; } @Override @@ -93,7 +92,7 @@ public SubGraphImplementor makeSubGraph(ManagedDomainType su private SubGraphImplementor internalMakeSubgraph(ManagedDomainType type) { assert type != null; - log.debugf( "Making sub-graph : ( (%s) %s )", type.getTypeName(), getAttributeName() ); + log.debugf( "Making subgraph : ( (%s) %s )", type.getTypeName(), getAttributeName() ); final SubGraphImplementor subGraph = DomainModelHelper.makeSubGraph( type, type.getBindableJavaType() ); internalAddSubGraph( subGraph ); return subGraph; @@ -109,7 +108,7 @@ private ManagedDomainType valueGraphTypeAsManaged() { throw new CannotContainSubGraphException( String.format( Locale.ROOT, - "Attribute [%s] (%s) cannot contain value sub-graphs", + "Attribute [%s] (%s) cannot contain value subgraphs", getAttributeName(), getAttributeDescriptor().getPersistentAttributeType().name() ) @@ -126,13 +125,13 @@ private SubGraphImplementor internalMakeSubgraph(Class subTy } protected void internalAddSubGraph(SubGraphImplementor subGraph) { - log.tracef( "Adding sub-graph : ( (%s) %s )", subGraph.getGraphedType().getTypeName(), getAttributeName() ); - if ( subGraphMap == null ) { - subGraphMap = new HashMap<>(); + log.tracef( "Adding subgraph : ( (%s) %s )", subGraph.getGraphedType().getTypeName(), getAttributeName() ); + if ( subgraphMap == null ) { + subgraphMap = new HashMap<>(); } - final SubGraphImplementor previous = subGraphMap.put( subGraph.getClassType(), subGraph ); + final SubGraphImplementor previous = subgraphMap.put( subGraph.getClassType(), subGraph ); if ( previous != null ) { - log.debugf( "Adding sub-graph [%s] over-wrote existing [%s]", subGraph, previous ); + log.debugf( "Adding subgraph [%s] over-wrote existing [%s]", subGraph, previous ); } } @@ -144,8 +143,8 @@ public void addSubGraph(Class subType, SubGraph subGraph) { } @Override - public void addSubGraph(SubGraphImplementor subGraph) { - internalAddSubGraph( subGraph ); + public void addSubGraph(SubGraphImplementor subgraph) { + internalAddSubGraph( subgraph ); } @Override @@ -165,7 +164,7 @@ public SubGraphImplementor makeKeySubGraph(ManagedDomainType private SubGraphImplementor internalMakeKeySubgraph(ManagedDomainType type) { assert type != null; - log.debugf( "Making key sub-graph : ( (%s) %s )", type.getTypeName(), getAttributeName() ); + log.debugf( "Making key subgraph : ( (%s) %s )", type.getTypeName(), getAttributeName() ); final SubGraphImplementor subGraph = DomainModelHelper.makeSubGraph( type, type.getBindableJavaType() ); internalAddKeySubGraph( subGraph ); return subGraph; @@ -178,14 +177,14 @@ private SubGraphImplementor internalMakeKeySubgraph(Class ty } protected void internalAddKeySubGraph(SubGraph subGraph) { - log.tracef( "Adding key sub-graph : ( (%s) %s )", subGraph.getClassType().getName(), getAttributeName() ); - if ( keySubGraphMap == null ) { - keySubGraphMap = new HashMap<>(); + log.tracef( "Adding key subgraph : ( (%s) %s )", subGraph.getClassType().getName(), getAttributeName() ); + if ( keySubgraphMap == null ) { + keySubgraphMap = new HashMap<>(); } final SubGraphImplementor previous = - keySubGraphMap.put( subGraph.getClassType(), (SubGraphImplementor) subGraph ); + keySubgraphMap.put( subGraph.getClassType(), (SubGraphImplementor) subGraph ); if ( previous != null ) { - log.debugf( "Adding key sub-graph [%s] over-wrote existing [%]", subGraph, previous ); + log.debugf( "Adding key subgraph [%s] overwrote existing [%]", subGraph, previous ); } } @@ -199,7 +198,7 @@ private ManagedDomainType keyGraphTypeAsManaged() { throw new CannotContainSubGraphException( String.format( Locale.ROOT, - "Attribute [%s#%s] (%s) cannot contain key sub-graphs - %s", + "Attribute [%s#%s] (%s) cannot contain key subgraphs - %s", getAttributeDescriptor().getDeclaringType().getTypeName(), getAttributeName(), getAttributeDescriptor().getPersistentAttributeType().name(), @@ -218,7 +217,7 @@ public void addKeySubGraph(Class subType, SubGraph subGraph) @Override public AttributeNodeImplementor makeCopy(boolean mutable) { return new AttributeNodeImpl<>( - this.attribute, makeMapCopy( mutable, subGraphMap ), makeMapCopy( mutable, keySubGraphMap ), mutable + this.attribute, makeMapCopy( mutable, subgraphMap ), makeMapCopy( mutable, keySubgraphMap ), mutable ); } @@ -236,45 +235,60 @@ private Map, SubGraphImplementor> makeMapCopy( } @Override - public void merge(AttributeNodeImplementor attributeNode) { - attributeNode.visitSubGraphs( - (incomingSubType, incomingGraph) -> { - SubGraphImplementor existing; - if ( subGraphMap == null ) { - subGraphMap = new HashMap<>(); - existing = null; - } - else { - existing = subGraphMap.get( incomingSubType ); - } - - if ( existing != null ) { - existing.merge( (GraphImplementor) incomingGraph ); - } - else { - internalAddSubGraph( (SubGraphImplementor) incomingGraph.makeCopy( true ) ); - } - } - ); + public void merge(AttributeNodeImplementor other) { + other.getSubGraphMap().values().forEach( this::mergeToSubgraph ); + other.getKeySubGraphMap().values().forEach( this::mergeToKeySubgraph ); + } - attributeNode.visitKeySubGraphs( - (incomingSubType, incomingGraph) -> { - SubGraphImplementor existing; - if ( keySubGraphMap == null ) { - keySubGraphMap = new HashMap<>(); - existing = null; - } - else { - existing = keySubGraphMap.get( incomingSubType ); - } - - if ( existing != null ) { - existing.merge( (GraphImplementor) incomingGraph ); - } - else { - internalAddKeySubGraph( (SubGraphImplementor) incomingGraph.makeCopy( true ) ); - } - } - ); + private void mergeToKeySubgraph(SubGraphImplementor subgraph) { + final SubGraphImplementor existing = getKeySubgraphForPut( subgraph ); + if ( existing != null ) { + existing.merge( subgraph ); + } + else { + internalAddKeySubGraph( subgraph.makeCopy( true ) ); + } + } + + private void mergeToSubgraph(SubGraphImplementor subgraph) { + final SubGraphImplementor existing = getSubgraphForPut( subgraph ); + if ( existing != null ) { + existing.merge( subgraph ); + } + else { + internalAddSubGraph( subgraph.makeCopy( true ) ); + } + } + + private SubGraphImplementor getSubgraphForPut(SubGraphImplementor subgraph) { + final SubGraphImplementor existing; + if ( subgraphMap == null ) { + subgraphMap = new HashMap<>(); + existing = null; + } + else { + existing = getSubgraph( subgraph.getClassType() ); + } + return existing; + } + + private SubGraphImplementor getKeySubgraphForPut(SubGraphImplementor subgraph) { + if ( keySubgraphMap == null ) { + keySubgraphMap = new HashMap<>(); + return null; + } + else { + return getKeySubgraph( subgraph.getClassType() ); + } + } + + @SuppressWarnings("unchecked") + private SubGraphImplementor getSubgraph(Class incomingSubtype) { + return (SubGraphImplementor) subgraphMap.get( incomingSubtype ); + } + + @SuppressWarnings("unchecked") + private SubGraphImplementor getKeySubgraph(Class incomingSubtype) { + return (SubGraphImplementor) keySubgraphMap.get( incomingSubtype ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java index fa586080f8e7..521fe9c49bd3 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java @@ -4,15 +4,17 @@ */ package org.hibernate.graph.internal; +import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.graph.spi.GraphHelper; import org.hibernate.graph.spi.GraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.model.domain.EntityDomainType; -import jakarta.persistence.metamodel.Attribute; -import jakarta.persistence.metamodel.MapAttribute; -import jakarta.persistence.metamodel.PluralAttribute; +import org.hibernate.metamodel.model.domain.ManagedDomainType; + +import java.util.ArrayList; +import java.util.List; /** * Implementation of the JPA-defined {@link jakarta.persistence.EntityGraph} interface. @@ -22,6 +24,7 @@ public class RootGraphImpl extends AbstractGraph implements RootGraphImplementor { private final String name; + private List> subgraphs; public RootGraphImpl(String name, EntityDomainType entityType, boolean mutable) { super( entityType, mutable ); @@ -33,7 +36,7 @@ public RootGraphImpl(String name, EntityDomainType entityType) { } public RootGraphImpl(String name, GraphImplementor original, boolean mutable) { - super(original, mutable); + super( original, mutable ); this.name = name; } @@ -49,65 +52,49 @@ public boolean appliesTo(EntityDomainType entityType) { @Override public RootGraphImplementor makeCopy(boolean mutable) { - return new RootGraphImpl<>( null, this, mutable); + return new RootGraphImpl<>( null, this, mutable ); } - @Override + @Override @Deprecated(forRemoval = true) public SubGraphImplementor makeSubGraph(boolean mutable) { - return new SubGraphImpl<>(this, mutable); + return new SubGraphImpl<>( this, mutable ); } - @Override + @Override @Deprecated(forRemoval = true) public RootGraphImplementor makeRootGraph(String name, boolean mutable) { return !mutable && !isMutable() ? this : super.makeRootGraph( name, mutable ); } @Override - public SubGraphImplementor addTreatedSubgraph(Class type) { - //noinspection unchecked,rawtypes - return new SubGraphImpl(this, false ); - } - - @Override - public SubGraphImplementor addTreatedSubgraph(Attribute attribute, Class type) { - //noinspection unchecked - return (SubGraphImplementor) super.makeRootGraph( name, false ); - } - - @Override - public SubGraphImplementor addTreatedElementSubgraph( - PluralAttribute attribute, - Class type) { - throw new UnsupportedOperationException( "Not yet implemented" ); + public RootGraphImplementor makeImmutableCopy(String name) { + return makeRootGraph( name, false ); } @Override - public SubGraphImplementor addTreatedMapKeySubgraph(MapAttribute attribute, Class type) { - throw new UnsupportedOperationException( "Not yet implemented" ); - } - - @Override - public SubGraphImplementor addSubclassSubgraph(Class type) { - throw new UnsupportedOperationException(); - } - - @Override - public SubGraphImplementor addElementSubgraph(PluralAttribute attribute) { - throw new UnsupportedOperationException( "Not yet implemented" ); - } - - @Override - public SubGraphImplementor addElementSubgraph(String attributeName) { - throw new UnsupportedOperationException( "Not yet implemented" ); - } - - @Override - public SubGraphImplementor addElementSubgraph(String attributeName, Class type) { - throw new UnsupportedOperationException( "Not yet implemented" ); + public SubGraphImplementor addTreatedSubgraph(Class type) { + final ManagedDomainType managedDomainType = getGraphedType().getMetamodel().managedType( type ); + final SubGraphImpl subgraph = new SubGraphImpl<>( managedDomainType, this, true ); + if ( subgraphs == null ) { + subgraphs = new ArrayList<>( 1 ); + } + subgraphs.add( subgraph ); + return subgraph; } @Override - public SubGraphImplementor addMapKeySubgraph(MapAttribute attribute) { - throw new UnsupportedOperationException( "Not yet implemented" ); + public AttributeNodeImplementor findAttributeNode(String attributeName) { + final AttributeNodeImplementor node = super.findAttributeNode( attributeName ); + if ( node == null && subgraphs != null ) { + for ( SubGraphImpl subgraph : subgraphs ) { + final AttributeNodeImplementor subgraphNode = subgraph.findAttributeNode( attributeName ); + if ( subgraphNode != null ) { + return subgraphNode; + } + } + return null; + } + else { + return node; + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java index 1a3b53c4a0f2..85eae4725a82 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java @@ -7,10 +7,6 @@ import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.model.domain.ManagedDomainType; -import jakarta.persistence.metamodel.Attribute; -import jakarta.persistence.metamodel.MapAttribute; -import jakarta.persistence.metamodel.PluralAttribute; - /** * Implementation of the JPA-defined {@link jakarta.persistence.Subgraph} interface. * @@ -23,58 +19,20 @@ public SubGraphImpl(ManagedDomainType managedType, boolean mutable) { } public SubGraphImpl(AbstractGraph original, boolean mutable) { - super(original, mutable); + super( original, mutable ); + } + + public SubGraphImpl(ManagedDomainType managedDomainType, AbstractGraph original, boolean mutable) { + super( managedDomainType, original, mutable ); } @Override public SubGraphImplementor makeCopy(boolean mutable) { - return new SubGraphImpl<>(this, mutable); + return new SubGraphImpl<>( this, mutable ); } - @Override + @Override @Deprecated(forRemoval = true) public SubGraphImplementor makeSubGraph(boolean mutable) { return !mutable && !isMutable() ? this : makeCopy( true ); } - - @Override - public SubGraphImplementor addKeySubGraph(String attributeName) { - return super.addKeySubGraph( attributeName ); - } - - @Override - public SubGraphImplementor addTreatedSubgraph(Attribute attribute, Class type) { - return null; - } - - @Override - public SubGraphImplementor addTreatedElementSubgraph( - PluralAttribute attribute, - Class type) { - return null; - } - - @Override - public SubGraphImplementor addTreatedMapKeySubgraph(MapAttribute attribute, Class type) { - throw new UnsupportedOperationException( "Not yet implemented" ); - } - - @Override - public SubGraphImplementor addElementSubgraph(PluralAttribute attribute) { - throw new UnsupportedOperationException( "Not yet implemented" ); - } - - @Override - public SubGraphImplementor addElementSubgraph(String attributeName) { - throw new UnsupportedOperationException( "Not yet implemented" ); - } - - @Override - public SubGraphImplementor addElementSubgraph(String attributeName, Class type) { - throw new UnsupportedOperationException( "Not yet implemented" ); - } - - @Override - public SubGraphImplementor addMapKeySubgraph(MapAttribute attribute) { - throw new UnsupportedOperationException( "Not yet implemented" ); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java index 449d7a000718..e9ed20a8a026 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java @@ -5,13 +5,15 @@ package org.hibernate.graph.spi; import java.util.Map; -import java.util.function.BiConsumer; + import jakarta.persistence.Subgraph; import org.hibernate.graph.AttributeNode; import org.hibernate.graph.SubGraph; import org.hibernate.metamodel.model.domain.ManagedDomainType; +import static java.util.Collections.unmodifiableMap; + /** * Integration version of the {@link AttributeNode} contract * @@ -19,39 +21,28 @@ * @author Steve Ebersole */ public interface AttributeNodeImplementor extends AttributeNode, GraphNodeImplementor { + Map, SubGraphImplementor> getSubGraphMap(); Map, SubGraphImplementor> getKeySubGraphMap(); - default void visitSubGraphs(BiConsumer, SubGraphImplementor> consumer) { - getSubGraphMap().forEach( consumer ); - } - - default void visitKeySubGraphs(BiConsumer, SubGraphImplementor> consumer) { - getKeySubGraphMap().forEach( consumer ); - } - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default Map, SubGraph> getSubGraphs() { - return (Map) getSubGraphMap(); + default Map, ? extends SubGraph> getSubGraphs() { + return unmodifiableMap( getSubGraphMap() ); } @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default Map, SubGraph> getKeySubGraphs() { - return (Map) getKeySubGraphMap(); + default Map, ? extends SubGraph> getKeySubGraphs() { + return unmodifiableMap( getKeySubGraphMap() ); } - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default Map getSubgraphs() { - return (Map) getSubGraphMap(); + @Override // JPA API uses raw types + default @SuppressWarnings("rawtypes") Map getSubgraphs() { + return unmodifiableMap( getSubGraphMap() ); } - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default Map getKeySubgraphs() { - return (Map) getKeySubGraphMap(); + @Override // JPA API uses raw types + default @SuppressWarnings("rawtypes") Map getKeySubgraphs() { + return unmodifiableMap( getKeySubGraphMap() ); } @Override @@ -73,7 +64,7 @@ default Map getKeySubgraphs() { SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype); - void merge(AttributeNodeImplementor attributeNode); + void merge(AttributeNodeImplementor other); - void addSubGraph(SubGraphImplementor subGraph); + void addSubGraph(SubGraphImplementor subgraph); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java index 6d5d8b4b48f9..e81f691fc6b1 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java @@ -5,14 +5,11 @@ package org.hibernate.graph.spi; import java.util.List; -import java.util.function.Consumer; +import java.util.Map; -import org.hibernate.graph.AttributeNode; import org.hibernate.graph.CannotBecomeEntityGraphException; -import org.hibernate.graph.CannotContainSubGraphException; import org.hibernate.graph.Graph; import org.hibernate.metamodel.model.domain.PersistentAttribute; -import org.hibernate.query.sqm.SqmPathSource; import jakarta.persistence.metamodel.Attribute; @@ -25,30 +22,18 @@ */ public interface GraphImplementor extends Graph, GraphNodeImplementor { - void merge(GraphImplementor other); + void merge(GraphImplementor other); - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // Covariant returns - - @Override + @Override @Deprecated(forRemoval = true) RootGraphImplementor makeRootGraph(String name, boolean mutable) throws CannotBecomeEntityGraphException; - @Override + @Override @Deprecated(forRemoval = true) SubGraphImplementor makeSubGraph(boolean mutable); @Override GraphImplementor makeCopy(boolean mutable); - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // AttributeNode access - - default void visitAttributeNodes(Consumer> consumer) { - getAttributeNodeImplementors().forEach( consumer ); - } - @Override default boolean hasAttributeNode(String attributeName) { return getAttributeNode( attributeName ) != null; @@ -59,15 +44,9 @@ default boolean hasAttributeNode(Attribute attribute) { return getAttributeNode( attribute ) != null; } - AttributeNodeImplementor addAttributeNode(AttributeNodeImplementor makeCopy); - List> getAttributeNodeImplementors(); - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default List> getAttributeNodeList() { - return (List) getAttributeNodeImplementors(); - } + Map, AttributeNodeImplementor> getAttributeNodesByAttribute(); @Override AttributeNodeImplementor findAttributeNode(String attributeName); @@ -75,83 +54,40 @@ default List> getAttributeNodeList() { @Override AttributeNodeImplementor findAttributeNode(PersistentAttribute attribute); + AttributeNodeImplementor findOrCreateAttributeNode(String name); + + AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute); + @Override - AttributeNodeImplementor addAttributeNode(String attributeName) throws CannotContainSubGraphException; + AttributeNodeImplementor addAttributeNode(String attributeName); @Override AttributeNodeImplementor addAttributeNode(Attribute attribute); @Override - AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute) - throws CannotContainSubGraphException; - - @SuppressWarnings("unchecked") - default AttributeNodeImplementor findOrCreateAttributeNode(String name) { - PersistentAttribute attribute = getGraphedType().getAttribute( name ); - if ( attribute instanceof SqmPathSource && ( (SqmPathSource) attribute ).isGeneric() ) { - attribute = getGraphedType().findConcreteGenericAttribute( name ); - } - - return findOrCreateAttributeNode( (PersistentAttribute) attribute ); - } - - AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute); - - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // sub graph nodes + AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute); @Override - @SuppressWarnings("unchecked") - default SubGraphImplementor addSubGraph(String attributeName) - throws CannotContainSubGraphException { - return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeSubGraph(); - } + SubGraphImplementor addSubGraph(String attributeName); @Override - default SubGraphImplementor addSubGraph(String attributeName, Class subType) - throws CannotContainSubGraphException { - return findOrCreateAttributeNode( attributeName ).makeSubGraph( subType ); - } + SubGraphImplementor addSubGraph(String attributeName, Class subType); @Override - default SubGraphImplementor addSubGraph(PersistentAttribute attribute) - throws CannotContainSubGraphException { - return findOrCreateAttributeNode( attribute ).makeSubGraph(); - } + SubGraphImplementor addSubGraph(PersistentAttribute attribute); @Override - default SubGraphImplementor addSubGraph( - PersistentAttribute attribute, - Class subType) throws CannotContainSubGraphException { - return findOrCreateAttributeNode( attribute ).makeSubGraph( subType ); - } - - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // key sub graph nodes + SubGraphImplementor addSubGraph(PersistentAttribute attribute, Class subtype); @Override - @SuppressWarnings("unchecked") - default SubGraphImplementor addKeySubGraph(String attributeName) { - return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeKeySubGraph(); - } + SubGraphImplementor addKeySubGraph(String attributeName); @Override - default SubGraphImplementor addKeySubGraph(String attributeName, Class subtype) { - return findOrCreateAttributeNode( attributeName ).makeKeySubGraph( subtype ); - } + SubGraphImplementor addKeySubGraph(String attributeName, Class subtype); @Override - default SubGraphImplementor addKeySubGraph(PersistentAttribute attribute) { - return findOrCreateAttributeNode( attribute ).makeKeySubGraph(); - } + SubGraphImplementor addKeySubGraph(PersistentAttribute attribute); @Override - default SubGraphImplementor addKeySubGraph( - PersistentAttribute attribute, - Class subType) - throws CannotContainSubGraphException { - return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subType ); - } + SubGraphImplementor addKeySubGraph(PersistentAttribute attribute, Class subtype); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/RootGraphImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/RootGraphImplementor.java index b4542e8e9cdc..b5bec2d89b63 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/RootGraphImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/RootGraphImplementor.java @@ -19,9 +19,12 @@ public interface RootGraphImplementor extends RootGraph, GraphImplementor< boolean appliesTo(EntityDomainType entityType); @Override + RootGraphImplementor makeCopy(boolean mutable); + + @Override @Deprecated(forRemoval = true) RootGraphImplementor makeRootGraph(String name, boolean mutable); - @Override + @Override @Deprecated(forRemoval = true) SubGraphImplementor makeSubGraph(boolean mutable); /** @@ -31,7 +34,5 @@ public interface RootGraphImplementor extends RootGraph, GraphImplementor< * * @return The immutable copy */ - default RootGraphImplementor makeImmutableCopy(String name) { - return makeRootGraph( name, false ); - } + RootGraphImplementor makeImmutableCopy(String name); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/SubGraphImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/SubGraphImplementor.java index a90a9285612d..9f7fe8ab844c 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/SubGraphImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/SubGraphImplementor.java @@ -5,9 +5,7 @@ package org.hibernate.graph.spi; import org.hibernate.graph.CannotBecomeEntityGraphException; -import org.hibernate.graph.CannotContainSubGraphException; import org.hibernate.graph.SubGraph; -import org.hibernate.metamodel.model.domain.PersistentAttribute; /** * Integration version of the {@link SubGraph} contract. @@ -21,24 +19,11 @@ public interface SubGraphImplementor extends SubGraph, GraphImplementor @Override SubGraphImplementor makeCopy(boolean mutable); - @Override - default SubGraphImplementor makeSubGraph(boolean mutable) { - return !mutable && !isMutable() ? this : makeCopy( mutable ); - } + @Override @Deprecated(forRemoval = true) + SubGraphImplementor makeSubGraph(boolean mutable); - @Override + @Override @Deprecated(forRemoval = true) RootGraphImplementor makeRootGraph(String name, boolean mutable) throws CannotBecomeEntityGraphException; - @Override - SubGraphImplementor addKeySubGraph(String attributeName); - - @Override - AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute); - - @Override - default SubGraphImplementor addKeySubGraph(PersistentAttribute attribute, Class subType) - throws CannotContainSubGraphException { - return null; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index 621ad1f1a242..2b9ff0e9abcc 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -1527,10 +1527,7 @@ public RootGraph createEntityGraph(Class rootType, String graphName) { public RootGraphImplementor createEntityGraph(String graphName) { checkOpen(); final RootGraphImplementor named = getFactory().findEntityGraphByName( graphName ); - if ( named == null ) { - return null; - } - return named.makeRootGraph( graphName, true ); + return named == null ? null : named.makeCopy( true ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java index db23cf66969c..313f4f194b40 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java @@ -43,7 +43,7 @@ public abstract class AbstractManagedType extends AbstractDomainType implements ManagedDomainType, AttributeContainer, Serializable { private final String hibernateTypeName; - private final ManagedDomainType superType; + private final ManagedDomainType supertype; private final RepresentationMode representationMode; private final JpaMetamodelImplementor metamodel; @@ -51,19 +51,19 @@ public abstract class AbstractManagedType private volatile Map> declaredPluralAttributes ; private volatile Map> declaredConcreteGenericAttributes; - private final List> subTypes = new ArrayList<>(); + private final List> subtypes = new ArrayList<>(); protected AbstractManagedType( String hibernateTypeName, JavaType javaType, - ManagedDomainType superType, + ManagedDomainType supertype, JpaMetamodelImplementor metamodel) { super( javaType ); this.hibernateTypeName = hibernateTypeName; - this.superType = superType; + this.supertype = supertype; this.metamodel = metamodel; - if ( superType != null ) { - superType.addSubType( this ); + if ( supertype != null ) { + supertype.addSubType( this ); } // todo (6.0) : need to handle RepresentationMode#MAP as well @@ -76,19 +76,23 @@ protected InFlightAccess createInFlightAccess() { return new InFlightAccessImpl(); } + public JpaMetamodelImplementor getMetamodel() { + return metamodel; + } + @Override public ManagedDomainType getSuperType() { - return superType; + return supertype; } @Override public Collection> getSubTypes() { - return subTypes; + return subtypes; } @Override public void addSubType(ManagedDomainType subType){ - subTypes.add( subType ); + subtypes.add( subType ); } @Override @@ -150,49 +154,41 @@ public PersistentAttribute getAttribute(String name) { @Override public PersistentAttribute findAttribute(String name) { - // first look at declared attributes final PersistentAttribute attribute = findDeclaredAttribute( name ); if ( attribute != null ) { return attribute; } - - if ( getSuperType() != null ) { - return getSuperType().findAttributeInSuperTypes( name ); + else { + return supertype != null ? supertype.findAttribute( name ) : null; } - - return null; } @Override - public PersistentAttribute findAttributeInSuperTypes(String name) { - final PersistentAttribute local = findDeclaredAttribute( name ); - if ( local != null ) { - return local; + public final PersistentAttribute findAttributeInSuperTypes(String name) { + final PersistentAttribute attribute = findDeclaredAttribute( name ); + if ( attribute != null ) { + return attribute; } - - if ( superType != null ) { - return superType.findAttributeInSuperTypes( name ); + else { + return supertype != null ? supertype.findAttributeInSuperTypes( name ) : null; } - - return null; } @Override public PersistentAttribute findSubTypesAttribute(String name) { - // first look at declared attributes final PersistentAttribute attribute = findDeclaredAttribute( name ); if ( attribute != null ) { return attribute; } - - for ( ManagedDomainType subType : subTypes ) { - final PersistentAttribute subTypeAttribute = subType.findSubTypesAttribute( name ); - if ( subTypeAttribute != null ) { - return subTypeAttribute; + else { + for ( ManagedDomainType subtype : subtypes ) { + final PersistentAttribute subTypeAttribute = subtype.findSubTypesAttribute( name ); + if ( subTypeAttribute != null ) { + return subTypeAttribute; + } } + return null; } - - return null; } @Override @@ -202,13 +198,13 @@ public PersistentAttribute findDeclaredAttribute(String name) { if ( attribute != null ) { return attribute; } - // next plural - if ( declaredPluralAttributes != null ) { + else if ( declaredPluralAttributes != null ) { return declaredPluralAttributes.get( name ); } - - return null; + else { + return null; + } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java index adde14df3ea0..714e8726c299 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java @@ -31,6 +31,8 @@ public interface ManagedDomainType extends SqmExpressible, DomainType, */ String getTypeName(); + JpaMetamodel getMetamodel(); + RepresentationMode getRepresentationMode(); /** @@ -54,7 +56,14 @@ public interface ManagedDomainType extends SqmExpressible, DomainType, PersistentAttribute findAttribute(String name); PersistentAttribute findSubTypesAttribute(String name); - PersistentAttribute findAttributeInSuperTypes(String name); + + /** + * @deprecated Use {@link #findAttribute(String)} + */ + @Deprecated(since = "7.0", forRemoval = true) + default PersistentAttribute findAttributeInSuperTypes(String name) { + return findAttribute( name ); + } SingularPersistentAttribute findSingularAttribute(String name); PluralPersistentAttribute findPluralAttribute(String name); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java index 4265fa5d6dfb..3a20448e9622 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java @@ -227,11 +227,6 @@ public PersistenceType getPersistenceType() { return PersistenceType.ENTITY; } - @Override - public IdentifiableDomainType getSuperType() { - return super.getSuperType(); - } - @Override public Collection> getSubTypes() { //noinspection unchecked 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 367fa0ed0dc9..76bcef67f6fa 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 @@ -378,11 +378,7 @@ private Field getJavaField(String className, String fieldName) throws NoSuchFiel @Override public void addNamedEntityGraph(String graphName, RootGraphImplementor entityGraph) { - final EntityGraph old = entityGraphMap.put( - graphName, - entityGraph.makeImmutableCopy( graphName ) - ); - + final EntityGraph old = entityGraphMap.put( graphName, entityGraph.makeImmutableCopy( graphName ) ); if ( old != null ) { log.debugf( "EntityGraph being replaced on EntityManagerFactory for name %s", graphName ); } @@ -623,7 +619,8 @@ public EntityDomainType resolveEntityReference(Class javaType) { if ( !matchingDescriptors.isEmpty() ) { final SqmPolymorphicRootDescriptor descriptor = new SqmPolymorphicRootDescriptor<>( typeConfiguration.getJavaTypeRegistry().resolveDescriptor( javaType ), - matchingDescriptors + matchingDescriptors, + this ); polymorphicEntityReferenceMap.putIfAbsent( javaType, descriptor ); return descriptor; diff --git a/hibernate-core/src/main/java/org/hibernate/query/Query.java b/hibernate-core/src/main/java/org/hibernate/query/Query.java index cf4c9228be9e..df9d60f9fa2e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/Query.java +++ b/hibernate-core/src/main/java/org/hibernate/query/Query.java @@ -270,7 +270,11 @@ default Stream stream() { * * @param graph The graph to apply. * @param semantic The semantic to use when applying the graph + * + * @deprecated Use {@link #setEntityGraph(EntityGraph, GraphSemantic)} + * which is more type safe */ + @Deprecated(since = "7.0") Query applyGraph(@SuppressWarnings("rawtypes") RootGraph graph, GraphSemantic semantic); /** @@ -278,7 +282,11 @@ default Stream stream() { * * @apiNote This method calls {@link #applyGraph(RootGraph, GraphSemantic)} * using {@link GraphSemantic#FETCH} as the semantic. + * + * @deprecated Use {@link #setEntityGraph(EntityGraph, GraphSemantic)} + * which is more type safe */ + @Deprecated(since = "7.0") default Query applyFetchGraph(@SuppressWarnings("rawtypes") RootGraph graph) { return applyGraph( graph, GraphSemantic.FETCH ); } @@ -288,7 +296,11 @@ default Query applyFetchGraph(@SuppressWarnings("rawtypes") RootGraph graph) * * @apiNote This method calls {@link #applyGraph(RootGraph, GraphSemantic)} * using {@link GraphSemantic#LOAD} as the semantic. + * + * @deprecated Use {@link #setEntityGraph(EntityGraph, GraphSemantic)} + * which is more type safe */ + @Deprecated(since = "7.0") default Query applyLoadGraph(@SuppressWarnings("rawtypes") RootGraph graph) { return applyGraph( graph, GraphSemantic.LOAD ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java index 9cda89f18ce4..0515b7e0b305 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java @@ -26,12 +26,12 @@ public static boolean containsCollectionFetches(QueryOptions queryOptions) { } private static boolean containsCollectionFetches(GraphImplementor graph) { - for ( AttributeNodeImplementor attributeNodeImplementor : graph.getAttributeNodeImplementors() ) { - if ( attributeNodeImplementor.getAttributeDescriptor().isCollection() ) { + for ( AttributeNodeImplementor node : graph.getAttributeNodeImplementors() ) { + if ( node.getAttributeDescriptor().isCollection() ) { return true; } - for ( SubGraphImplementor subGraph : attributeNodeImplementor.getSubGraphMap().values() ) { - if ( containsCollectionFetches(subGraph) ) { + for ( SubGraphImplementor subgraph : node.getSubGraphMap().values() ) { + if ( containsCollectionFetches( subgraph ) ) { return true; } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java index 765689d70c74..a0e7570b7801 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java @@ -4,16 +4,39 @@ */ package org.hibernate.query.sqm.tree.domain; -import jakarta.persistence.metamodel.*; +import jakarta.persistence.metamodel.Attribute; +import jakarta.persistence.metamodel.CollectionAttribute; +import jakarta.persistence.metamodel.ListAttribute; +import jakarta.persistence.metamodel.MapAttribute; +import jakarta.persistence.metamodel.PluralAttribute; +import jakarta.persistence.metamodel.SetAttribute; +import jakarta.persistence.metamodel.SingularAttribute; import org.hibernate.metamodel.RepresentationMode; -import org.hibernate.metamodel.model.domain.*; +import org.hibernate.metamodel.model.domain.DomainType; +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.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.query.sqm.SqmPathSource; import org.hibernate.type.descriptor.java.JavaType; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.function.Consumer; import static java.util.Collections.unmodifiableMap; +import static java.util.Comparator.comparing; /** * Acts as the {@link EntityDomainType} for a "polymorphic query" grouping. @@ -25,17 +48,24 @@ public class SqmPolymorphicRootDescriptor implements EntityDomainType { private final Map> commonAttributes; private final JavaType polymorphicJavaType; + private final JpaMetamodel jpaMetamodel; public SqmPolymorphicRootDescriptor( JavaType polymorphicJavaType, - Set> implementors) { + Set> implementors, + JpaMetamodel jpaMetamodel) { this.polymorphicJavaType = polymorphicJavaType; - TreeSet> treeSet = new TreeSet<>( Comparator.comparing(EntityDomainType::getTypeName) ); - treeSet.addAll( implementors ); - this.implementors = treeSet; + this.jpaMetamodel = jpaMetamodel; + this.implementors = new TreeSet<>( comparing(EntityDomainType::getTypeName) ); + this.implementors.addAll( implementors ); this.commonAttributes = unmodifiableMap( inferCommonAttributes( implementors ) ); } + @Override + public JpaMetamodel getMetamodel() { + return jpaMetamodel; + } + /** * The attributes of a "polymorphic" root are the attributes which are * common to all subtypes of the root type. @@ -157,12 +187,6 @@ public JavaType getExpressibleJavaType() { return commonAttributes.get( name ); } - @Override - public PersistentAttribute findAttributeInSuperTypes(String name) { - // there are effectively no super-types - return null; - } - @Override public void visitAttributes(Consumer> action) { commonAttributes.values().forEach( action ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java index f3f1492440e0..312a84a8ac3f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java @@ -65,8 +65,7 @@ public TraversalResult traverse(FetchParent fetchParent, Fetchable fetchable, bo fetchStrategy = new FetchStrategy( FetchTiming.IMMEDIATE, true ); final Map, ? extends SubGraphImplementor> subgraphMap; final Class subgraphMapKey; - if ( fetchable instanceof PluralAttributeMapping ) { - final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) fetchable; + if ( fetchable instanceof PluralAttributeMapping pluralAttributeMapping ) { if ( exploreKeySubgraph ) { subgraphMap = attributeNode.getKeySubGraphMap(); subgraphMapKey = getEntityCollectionPartJavaClass( pluralAttributeMapping.getIndexDescriptor() ); @@ -95,17 +94,14 @@ else if ( graphSemantic == GraphSemantic.FETCH ) { } private Class getEntityCollectionPartJavaClass(CollectionPart collectionPart) { - if ( collectionPart instanceof EntityCollectionPart ) { - EntityCollectionPart entityCollectionPart = (EntityCollectionPart) collectionPart; - return entityCollectionPart.getEntityMappingType().getJavaType().getJavaTypeClass(); - } - else { - return null; - } + return collectionPart instanceof EntityCollectionPart entityCollectionPart + ? entityCollectionPart.getEntityMappingType().getJavaType().getJavaTypeClass() + : null; } private boolean appliesTo(FetchParent fetchParent) { - return currentGraphContext != null && fetchParent.appliesTo( currentGraphContext, metamodel ); + return currentGraphContext != null + && fetchParent.appliesTo( currentGraphContext, metamodel ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/idprops/IdPropertyInSubclassIdInMappedSuperclassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/idprops/IdPropertyInSubclassIdInMappedSuperclassTest.java index 96d7e8005590..a5ebe084c142 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/idprops/IdPropertyInSubclassIdInMappedSuperclassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/idprops/IdPropertyInSubclassIdInMappedSuperclassTest.java @@ -75,7 +75,7 @@ public void testHql(SessionFactoryScope scope) { assertEquals( 2, - session.createQuery( "from Human h where h.id = :id", Human.class ) + session.createQuery( "from Genius g where g.id = :id", Human.class ) .setParameter( "id", 1L ) .list() .size() @@ -83,6 +83,14 @@ public void testHql(SessionFactoryScope scope) { assertEquals( 1, + session.createQuery( "from Human h where h.id = :id", Human.class ) + .setParameter( "id", 1L ) + .list() + .size() + ); + + assertEquals( + 0, session.createQuery( "from Human h where h.id is null", Human.class ) .list() .size() diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/graphs/EntityGraphTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/graphs/EntityGraphTest.java index 54dda167d0df..d99cb6529575 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/graphs/EntityGraphTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/graphs/EntityGraphTest.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -37,7 +38,6 @@ import org.hibernate.testing.util.uuid.SafeRandomUUIDGenerator; import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; -import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.JiraKey; import org.junit.Test; @@ -55,7 +55,8 @@ public class EntityGraphTest extends BaseEntityManagerFunctionalTestCase { protected Class[] getAnnotatedClasses() { return new Class[] { Foo.class, Bar.class, Baz.class, Author.class, Book.class, Prize.class, Company.class, - Employee.class, Manager.class, Location.class, AnimalOwner.class, Animal.class, Dog.class, Cat.class + Employee.class, Manager.class, Location.class, AnimalOwner.class, Animal.class, Dog.class, Cat.class, + Kennel.class }; } @@ -216,7 +217,7 @@ public void inheritanceTest() { assertTrue( Hibernate.isInitialized( result ) ); assertTrue( Hibernate.isInitialized( result.employees ) ); - assertEquals( result.employees.size(), 2 ); + assertEquals( 2, result.employees.size() ); for (Employee resultEmployee : result.employees) { assertTrue( Hibernate.isInitialized( resultEmployee.managers ) ); assertTrue( Hibernate.isInitialized( resultEmployee.friends ) ); @@ -256,9 +257,9 @@ public void attributeNodeInheritanceTest() { assertTrue( Hibernate.isInitialized( result ) ); assertTrue( Hibernate.isInitialized( result.friends ) ); - assertEquals( result.friends.size(), 1 ); + assertEquals( 1, result.friends.size() ); assertTrue( Hibernate.isInitialized( result.managers) ); - assertEquals( result.managers.size(), 1 ); + assertEquals( 1, result.managers.size() ); em.getTransaction().commit(); em.close(); @@ -266,7 +267,7 @@ public void attributeNodeInheritanceTest() { @Test @JiraKey(value = "HHH-9735") - public void loadIsMemeberQueriedCollection() { + public void loadIsMemberQueriedCollection() { EntityManager em = getOrCreateEntityManager(); em.getTransaction().begin(); @@ -484,6 +485,40 @@ public void joinedInheritanceWithSubEntityAttributeFiltering() { em.close(); } + @Test + public void testTreatedSubgraph() { + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Kennel kennel = new Kennel(); + em.persist( kennel ); + Dog dog = new Dog(); + dog.kennel = kennel; + em.persist( dog ); + em.flush(); + em.clear(); + + EntityGraph graph = em.createEntityGraph( Dog.class ); + graph.addAttributeNode( "kennel" ); + Dog doggie = em.find( graph, dog.id ); + assertTrue( Hibernate.isInitialized( doggie.kennel ) ); + + em.clear(); + + EntityGraph withKennel = em.createEntityGraph( Animal.class ); + withKennel.addTreatedSubgraph( Dog.class ).addAttributeNode( "kennel" ); + Animal animal = em.find( withKennel, doggie.id ); + assertTrue( Hibernate.isInitialized( ( (Dog) animal ).kennel ) ); + + em.clear(); + + EntityGraph withoutKennel = em.createEntityGraph( Animal.class ); + animal = em.find( withoutKennel, doggie.id ); + assertFalse( Hibernate.isInitialized( ( (Dog) animal ).kennel ) ); + + em.getTransaction().rollback(); + em.close(); + } + @Entity(name = "Foo") @Table(name = "foo") public static class Foo { @@ -508,7 +543,7 @@ public static class Bar { public Integer id; @OneToMany(mappedBy = "bar") - public Set foos = new HashSet(); + public Set foos = new HashSet<>(); public Set getFoos() { return foos; @@ -524,7 +559,7 @@ public static class Baz { public Integer id; @OneToMany(mappedBy = "baz") - public Set foos = new HashSet(); + public Set foos = new HashSet<>(); public Set getFoos() { return foos; @@ -620,6 +655,9 @@ public static class Dog extends Animal { public Integer numberOfLegs; + @ManyToOne(fetch = FetchType.LAZY) + Kennel kennel; + public Dog() { dtype = "DOG"; } @@ -635,4 +673,10 @@ public Cat() { dtype = "CAT"; } } + + @Entity(name = "Kennel") + public static class Kennel { + @Id @GeneratedValue + UUID uuid; + } } 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 773ef2c325a1..486293a5c0a8 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 @@ -1024,13 +1024,10 @@ && isSubtype(entityPersister.getEntityName(), getHibernateEntityName())) { if (attribute != null) { return attribute; } - final String supertype = MockSessionFactory.this.getSupertype(getHibernateEntityName()); - final PersistentAttribute superattribute - = new MockMappedDomainType<>(supertype).findAttribute(name); - if (superattribute != null) { - return superattribute; + else { + final String supertype = MockSessionFactory.this.getSupertype( getHibernateEntityName() ); + return new MockMappedDomainType<>( supertype ).findAttribute( name ); } - return null; } @Override From eb45abe6866027e4dc8c66f1c1b22d5a9b5f2d42 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Wed, 1 Jan 2025 22:05:43 +0100 Subject: [PATCH 4/9] Graphpocalypse: major revision/refactoring of EntityGraph support - fix up typing issues with key/value subgraphs --- .../org/hibernate/graph/AttributeNode.java | 18 +- .../main/java/org/hibernate/graph/Graph.java | 11 +- .../java/org/hibernate/graph/RootGraph.java | 5 +- .../graph/internal/AbstractGraph.java | 23 +-- .../graph/internal/AttributeNodeImpl.java | 195 ++++++------------ .../internal/parse/PathQualifierType.java | 53 ++--- .../graph/spi/AttributeNodeImplementor.java | 26 ++- .../hibernate/graph/spi/GraphImplementor.java | 6 - .../domain/internal/DomainModelHelper.java | 73 ------- .../domain/internal/JpaMetamodelImpl.java | 22 +- .../graph/EntityGraphTraversalState.java | 11 +- .../entitygraph/parser/EntityGraphsTest.java | 5 +- 12 files changed, 140 insertions(+), 308 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java index 9b91daaea057..7029e0802787 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java @@ -6,6 +6,7 @@ import java.util.Map; +import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; /** @@ -19,15 +20,16 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr PersistentAttribute getAttributeDescriptor(); - Map, ? extends SubGraph> getSubGraphs(); - Map, ? extends SubGraph> getKeySubGraphs(); + Map, ? extends SubGraph> getSubGraphs(); + Map, ? extends SubGraph> getKeySubGraphs(); - void addSubGraph(Class subType, SubGraph subGraph); - void addKeySubGraph(Class subType, SubGraph subGraph); + SubGraph makeSubGraph(); + SubGraph makeKeySubGraph(); - SubGraph makeSubGraph(); - SubGraph makeKeySubGraph(); + SubGraph makeSubGraph(Class type); + SubGraph makeKeySubGraph(Class type); + + SubGraph makeSubGraph(ManagedDomainType subtype); + SubGraph makeKeySubGraph(ManagedDomainType subtype); - SubGraph makeSubGraph(Class subtype); - SubGraph makeKeySubGraph(Class subtype); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java index 57cc15e46bdc..d3d5c8762ba4 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java @@ -188,17 +188,14 @@ default SubGraph addSubgraph(String name, Class type) { SubGraph addKeySubGraph(String attributeName); SubGraph addKeySubGraph(String attributeName, Class type); - SubGraph addKeySubGraph(PersistentAttribute attribute); - SubGraph addKeySubGraph(PersistentAttribute attribute, Class type); - - @Override + @Override @Deprecated(forRemoval = true) default SubGraph addKeySubgraph(Attribute attribute) { - return addKeySubGraph( (PersistentAttribute) attribute ); + throw new UnsupportedOperationException("This operation will be removed in JPA 4"); } - @Override + @Override @Deprecated(forRemoval = true) default SubGraph addKeySubgraph(Attribute attribute, Class type) { - return addKeySubGraph( (PersistentAttribute) attribute, type ); + throw new UnsupportedOperationException("This operation will be removed in JPA 4"); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java index 8d7fd652d513..0685ce7d620f 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java @@ -29,7 +29,8 @@ public interface RootGraph extends Graph, EntityGraph { * @deprecated Planned for removal in JPA 4 */ @Override @Deprecated(forRemoval = true) - default SubGraph addSubclassSubgraph(Class type) { - throw new UnsupportedOperationException("This operation will be removed in JPA 4"); + @SuppressWarnings("unchecked") // The JPA method was defined with an incorrect generic signature + default SubGraph addSubclassSubgraph(Class type) { + return (SubGraph) addTreatedSubgraph( (Class) type ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java index 67e6eab64f40..be913dc42989 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java @@ -37,6 +37,7 @@ * @author Steve Ebersole */ public abstract class AbstractGraph extends AbstractGraphNode implements GraphImplementor { + private final ManagedDomainType managedType; private Map, AttributeNodeImplementor> attributeNodes; @@ -109,6 +110,7 @@ private void addAttributeNode(PersistentAttribute attribute, A else { // we assume the subgraph has been properly copied if needed node.getSubGraphMap().forEach( (subtype, subgraph) -> attributeNode.addSubGraph( subgraph ) ); + node.getKeySubGraphMap().forEach( (subtype, subgraph) -> attributeNode.addKeySubGraph( subgraph ) ); } } @@ -247,19 +249,19 @@ public SubGraphImplementor addSubGraph(String attributeName) { } @Override - public SubGraphImplementor addSubGraph(String attributeName, Class subType) { - return findOrCreateAttributeNode( attributeName ).makeSubGraph( subType ); + public SubGraphImplementor addSubGraph(String attributeName, Class subtype) { + return findOrCreateAttributeNode( attributeName ).makeSubGraph( subtype ); } @Override public SubGraphImplementor addSubGraph(PersistentAttribute attribute) { - return findOrCreateAttributeNode( attribute ).makeSubGraph(); + return findOrCreateAttributeNode( attribute ).makeSubGraph( attribute.getJavaType() ); } @Override public SubGraphImplementor addSubGraph( - PersistentAttribute attribute, Class subType) { - return findOrCreateAttributeNode( attribute ).makeSubGraph( subType ); + PersistentAttribute attribute, Class subtype) { + return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype ); } @Override @@ -280,17 +282,6 @@ public SubGraphImplementor addKeySubGraph(String attributeName, Class SubGraphImplementor addKeySubGraph(PersistentAttribute attribute) { - return findOrCreateAttributeNode( attribute ).makeKeySubGraph(); - } - - @Override - public SubGraphImplementor addKeySubGraph( - PersistentAttribute attribute, Class subType) { - return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subType ); - } - ////////////////// TODO ////////////////// @Override diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java index 96b825a3b181..30a59fd32adc 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java @@ -5,24 +5,15 @@ package org.hibernate.graph.internal; import java.util.HashMap; -import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; -import org.hibernate.graph.CannotContainSubGraphException; -import org.hibernate.graph.SubGraph; import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.graph.spi.SubGraphImplementor; -import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; -import org.hibernate.metamodel.model.domain.SimpleDomainType; - -import org.hibernate.metamodel.model.domain.internal.DomainModelHelper; -import org.jboss.logging.Logger; import static java.util.Collections.emptyMap; -import static org.hibernate.metamodel.model.domain.internal.DomainModelHelper.findSubType; /** * Implementation of {@link jakarta.persistence.AttributeNode}. @@ -34,8 +25,8 @@ public class AttributeNodeImpl implements AttributeNodeImplementor { private final PersistentAttribute attribute; - private Map, SubGraphImplementor> subgraphMap; - private Map, SubGraphImplementor> keySubgraphMap; + private Map, SubGraphImplementor> subgraphMap; + private Map, SubGraphImplementor> keySubgraphMap; public AttributeNodeImpl(PersistentAttribute attribute, boolean mutable) { this(attribute, null, null, mutable); @@ -46,8 +37,8 @@ public AttributeNodeImpl(PersistentAttribute attribute, boolean mutabl */ private AttributeNodeImpl( PersistentAttribute attribute, - Map, SubGraphImplementor> subgraphMap, - Map, SubGraphImplementor> keySubgraphMap, + Map, SubGraphImplementor> subgraphMap, + Map, SubGraphImplementor> keySubgraphMap, boolean mutable) { super( mutable ); this.attribute = attribute; @@ -66,164 +57,106 @@ public PersistentAttribute getAttributeDescriptor() { } @Override - public Map, SubGraphImplementor> getSubGraphMap() { + public Map, SubGraphImplementor> getSubGraphMap() { return subgraphMap == null ? emptyMap() : subgraphMap; } @Override - public Map, SubGraphImplementor> getKeySubGraphMap() { + public Map, SubGraphImplementor> getKeySubGraphMap() { return keySubgraphMap == null ? emptyMap() : keySubgraphMap; } @Override - public SubGraphImplementor makeSubGraph() { - return internalMakeSubgraph( (Class) null ); + public SubGraphImplementor makeSubGraph() { + return makeSubGraph( (ManagedDomainType) attribute.getValueGraphType() ); } @Override - public SubGraphImplementor makeSubGraph(Class subtype) { - return internalMakeSubgraph( subtype ); + public SubGraphImplementor makeSubGraph(Class type) { + return makeSubGraph( attribute.getDeclaringType().getMetamodel().managedType( type ) ); } @Override - public SubGraphImplementor makeSubGraph(ManagedDomainType subtype) { - return internalMakeSubgraph( subtype ); - } - - private SubGraphImplementor internalMakeSubgraph(ManagedDomainType type) { - assert type != null; - log.debugf( "Making subgraph : ( (%s) %s )", type.getTypeName(), getAttributeName() ); - final SubGraphImplementor subGraph = DomainModelHelper.makeSubGraph( type, type.getBindableJavaType() ); - internalAddSubGraph( subGraph ); - return subGraph; - } - - @SuppressWarnings("unchecked") - private ManagedDomainType valueGraphTypeAsManaged() { - final DomainType valueGraphType = getAttributeDescriptor().getValueGraphType(); - if ( valueGraphType instanceof ManagedDomainType ) { - return (ManagedDomainType) valueGraphType; - } - else { - throw new CannotContainSubGraphException( - String.format( - Locale.ROOT, - "Attribute [%s] (%s) cannot contain value subgraphs", - getAttributeName(), - getAttributeDescriptor().getPersistentAttributeType().name() - ) - ); - } - } - - private static final Logger log = Logger.getLogger( AttributeNodeImpl.class ); - - private SubGraphImplementor internalMakeSubgraph(Class subType) { + public SubGraphImplementor makeSubGraph(ManagedDomainType subtype) { verifyMutability(); - final ManagedDomainType managedType = valueGraphTypeAsManaged(); - return internalMakeSubgraph( findSubType( managedType, subType == null ? managedType.getJavaType() : subType ) ); + assert subtype != null; + if ( !attribute.getValueGraphType().getBindableJavaType().isAssignableFrom( subtype.getJavaType() ) ) { + throw new IllegalArgumentException( "Not a subtype: " + subtype.getJavaType() ); + } + final SubGraphImplementor subGraph = new SubGraphImpl<>( subtype, true ); + addSubGraph( subGraph ); + return subGraph; } - protected void internalAddSubGraph(SubGraphImplementor subGraph) { - log.tracef( "Adding subgraph : ( (%s) %s )", subGraph.getGraphedType().getTypeName(), getAttributeName() ); + @Override + public void addSubGraph(SubGraphImplementor subgraph) { if ( subgraphMap == null ) { subgraphMap = new HashMap<>(); + subgraphMap.put( subgraph.getClassType(), subgraph ); } - final SubGraphImplementor previous = subgraphMap.put( subGraph.getClassType(), subGraph ); - if ( previous != null ) { - log.debugf( "Adding subgraph [%s] over-wrote existing [%s]", subGraph, previous ); + else { + final SubGraphImplementor existing = subgraphMap.get( subgraph.getClassType() ); + if ( existing == null ) { + subgraphMap.put( subgraph.getClassType(), subgraph ); + } + else { + existing.merge( (SubGraphImplementor) subgraph ); + } } } @Override - public void addSubGraph(Class subType, SubGraph subGraph) { - verifyMutability(); - assert subGraph.getClassType() == subType; - internalAddSubGraph( (SubGraphImplementor) subGraph ); - } - - @Override - public void addSubGraph(SubGraphImplementor subgraph) { - internalAddSubGraph( subgraph ); + public void addKeySubGraph(SubGraphImplementor subgraph) { + if ( keySubgraphMap == null ) { + keySubgraphMap = new HashMap<>(); + keySubgraphMap.put( subgraph.getClassType(), subgraph ); + } + else { + final SubGraphImplementor existing = keySubgraphMap.get( subgraph.getClassType() ); + if ( existing == null ) { + keySubgraphMap.put( subgraph.getClassType(), subgraph ); + } + else { + existing.merge( (SubGraphImplementor) subgraph ); + } + } } @Override - public SubGraphImplementor makeKeySubGraph() { - return internalMakeKeySubgraph( (Class) null ); + public SubGraphImplementor makeKeySubGraph() { + return makeKeySubGraph( (ManagedDomainType) attribute.getKeyGraphType() ); } @Override - public SubGraphImplementor makeKeySubGraph(Class subtype) { - return internalMakeKeySubgraph( subtype ); + public SubGraphImplementor makeKeySubGraph(Class type) { + return makeKeySubGraph( attribute.getDeclaringType().getMetamodel().managedType( type ) ); } @Override - public SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype) { - return internalMakeKeySubgraph( subtype ); - } - - private SubGraphImplementor internalMakeKeySubgraph(ManagedDomainType type) { - assert type != null; - log.debugf( "Making key subgraph : ( (%s) %s )", type.getTypeName(), getAttributeName() ); - final SubGraphImplementor subGraph = DomainModelHelper.makeSubGraph( type, type.getBindableJavaType() ); - internalAddKeySubGraph( subGraph ); - return subGraph; - } - - private SubGraphImplementor internalMakeKeySubgraph(Class type) { + public SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype) { verifyMutability(); - final ManagedDomainType managedType = keyGraphTypeAsManaged(); - return internalMakeKeySubgraph( type == null ? managedType : findSubType( managedType, type ) ); - } - - protected void internalAddKeySubGraph(SubGraph subGraph) { - log.tracef( "Adding key subgraph : ( (%s) %s )", subGraph.getClassType().getName(), getAttributeName() ); - if ( keySubgraphMap == null ) { - keySubgraphMap = new HashMap<>(); - } - final SubGraphImplementor previous = - keySubgraphMap.put( subGraph.getClassType(), (SubGraphImplementor) subGraph ); - if ( previous != null ) { - log.debugf( "Adding key subgraph [%s] overwrote existing [%]", subGraph, previous ); - } - } - - @SuppressWarnings("unchecked") - private ManagedDomainType keyGraphTypeAsManaged() { - final SimpleDomainType keyGraphType = getAttributeDescriptor().getKeyGraphType(); - if ( keyGraphType instanceof ManagedDomainType ) { - return (ManagedDomainType) keyGraphType; + assert subtype != null; + if ( !attribute.getKeyGraphType().getBindableJavaType().isAssignableFrom( subtype.getJavaType() ) ) { + throw new IllegalArgumentException( "Not a key subtype: " + subtype.getJavaType() ); } - else { - throw new CannotContainSubGraphException( - String.format( - Locale.ROOT, - "Attribute [%s#%s] (%s) cannot contain key subgraphs - %s", - getAttributeDescriptor().getDeclaringType().getTypeName(), - getAttributeName(), - getAttributeDescriptor().getPersistentAttributeType().name(), - keyGraphType - ) - ); - } - } - - @Override - public void addKeySubGraph(Class subType, SubGraph subGraph) { - assert subGraph.getClassType() == subType; - internalAddKeySubGraph( subGraph ); + final SubGraphImplementor subgraph = new SubGraphImpl<>( subtype, true ); + addKeySubGraph( subgraph ); + return subgraph; } @Override public AttributeNodeImplementor makeCopy(boolean mutable) { return new AttributeNodeImpl<>( - this.attribute, makeMapCopy( mutable, subgraphMap ), makeMapCopy( mutable, keySubgraphMap ), mutable + this.attribute, + makeMapCopy( mutable, subgraphMap ), + makeMapCopy( mutable, keySubgraphMap ), + mutable ); } - private Map, SubGraphImplementor> makeMapCopy( + private Map, SubGraphImplementor> makeMapCopy( boolean mutable, - Map, SubGraphImplementor> nodeMap) { + Map, SubGraphImplementor> nodeMap) { if ( nodeMap == null ) { return null; } @@ -240,23 +173,23 @@ public void merge(AttributeNodeImplementor other) { other.getKeySubGraphMap().values().forEach( this::mergeToKeySubgraph ); } - private void mergeToKeySubgraph(SubGraphImplementor subgraph) { + private void mergeToKeySubgraph(SubGraphImplementor subgraph) { final SubGraphImplementor existing = getKeySubgraphForPut( subgraph ); if ( existing != null ) { existing.merge( subgraph ); } else { - internalAddKeySubGraph( subgraph.makeCopy( true ) ); + addKeySubGraph( subgraph.makeCopy( true ) ); } } - private void mergeToSubgraph(SubGraphImplementor subgraph) { + private void mergeToSubgraph(SubGraphImplementor subgraph) { final SubGraphImplementor existing = getSubgraphForPut( subgraph ); if ( existing != null ) { existing.merge( subgraph ); } else { - internalAddSubGraph( subgraph.makeCopy( true ) ); + addSubGraph( subgraph.makeCopy( true ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/PathQualifierType.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/PathQualifierType.java index a3b1468a89f4..5d2f7e12ad5b 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/PathQualifierType.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/PathQualifierType.java @@ -4,57 +4,42 @@ */ package org.hibernate.graph.internal.parse; -import org.hibernate.graph.CannotContainSubGraphException; -import org.hibernate.metamodel.model.domain.DomainType; + +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.ManagedDomainType; -import static org.hibernate.metamodel.model.domain.internal.DomainModelHelper.resolveSubType; - /** * @author Steve Ebersole */ -@SuppressWarnings("unchecked") public enum PathQualifierType { - KEY( - (attributeNode, subTypeName, sessionFactory) -> - attributeNode.makeKeySubGraph( - resolveSubTypeManagedType( - attributeNode.getAttributeDescriptor().getKeyGraphType(), - subTypeName, - sessionFactory.getJpaMetamodel() - ) - ) + + KEY( (attributeNode, subtypeName, sessionFactory) -> subtypeName == null + ? attributeNode.makeKeySubGraph() + : attributeNode.makeKeySubGraph( getSubtype( subtypeName, sessionFactory ) ) ), - VALUE( - (attributeNode, subTypeName, sessionFactory) -> - attributeNode.makeSubGraph( - resolveSubTypeManagedType( - attributeNode.getAttributeDescriptor().getValueGraphType(), - subTypeName, - sessionFactory.getJpaMetamodel() - ) - ) + + VALUE( (attributeNode, subtypeName, sessionFactory) -> subtypeName == null + ? attributeNode.makeSubGraph() + : attributeNode.makeSubGraph( getSubtype( subtypeName, sessionFactory ) ) ); - private static ManagedDomainType resolveSubTypeManagedType( - DomainType graphType, - String subTypeName, - JpaMetamodel metamodel) { - if ( !( graphType instanceof ManagedDomainType managedType ) ) { - throw new CannotContainSubGraphException( "The given type [" + graphType + "] is not a ManagedType" ); + private static ManagedDomainType getSubtype(String subtypeName, SessionFactoryImplementor sessionFactory) { + final JpaMetamodel metamodel = sessionFactory.getJpaMetamodel(); + ManagedDomainType managedType = metamodel.findManagedType( subtypeName ); + if ( managedType == null ) { + managedType = metamodel.getHqlEntityReference( subtypeName ); } - - if ( subTypeName != null ) { - managedType = resolveSubType( managedType, subTypeName, metamodel ); + if ( managedType == null ) { + throw new IllegalArgumentException( "Unknown type " + subtypeName ); } return managedType; } private final SubGraphGenerator subGraphCreator; - PathQualifierType(SubGraphGenerator subGraphCreator) { - this.subGraphCreator = subGraphCreator; + PathQualifierType(SubGraphGenerator subgraphCreator) { + this.subGraphCreator = subgraphCreator; } public SubGraphGenerator getSubGraphCreator() { diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java index e9ed20a8a026..e9bf2b2f0385 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java @@ -22,16 +22,16 @@ */ public interface AttributeNodeImplementor extends AttributeNode, GraphNodeImplementor { - Map, SubGraphImplementor> getSubGraphMap(); - Map, SubGraphImplementor> getKeySubGraphMap(); + Map, SubGraphImplementor> getSubGraphMap(); + Map, SubGraphImplementor> getKeySubGraphMap(); @Override - default Map, ? extends SubGraph> getSubGraphs() { + default Map, ? extends SubGraph> getSubGraphs() { return unmodifiableMap( getSubGraphMap() ); } @Override - default Map, ? extends SubGraph> getKeySubGraphs() { + default Map, ? extends SubGraph> getKeySubGraphs() { return unmodifiableMap( getKeySubGraphMap() ); } @@ -49,22 +49,26 @@ public interface AttributeNodeImplementor extends AttributeNode, GraphNode AttributeNodeImplementor makeCopy(boolean mutable); @Override - SubGraphImplementor makeSubGraph(); + SubGraphImplementor makeSubGraph(); @Override - SubGraphImplementor makeKeySubGraph(); + SubGraphImplementor makeKeySubGraph(); @Override - SubGraphImplementor makeSubGraph(Class subtype); + SubGraphImplementor makeSubGraph(Class type); @Override - SubGraphImplementor makeKeySubGraph(Class subtype); + SubGraphImplementor makeKeySubGraph(Class type); - SubGraphImplementor makeSubGraph(ManagedDomainType subtype); + @Override + SubGraphImplementor makeSubGraph(ManagedDomainType subtype); - SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype); + @Override + SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype); void merge(AttributeNodeImplementor other); - void addSubGraph(SubGraphImplementor subgraph); + void addSubGraph(SubGraphImplementor subgraph); + + void addKeySubGraph(SubGraphImplementor subgraph); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java index e81f691fc6b1..d6d21e7e1931 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java @@ -84,10 +84,4 @@ default boolean hasAttributeNode(Attribute attribute) { @Override SubGraphImplementor addKeySubGraph(String attributeName, Class subtype); - - @Override - SubGraphImplementor addKeySubGraph(PersistentAttribute attribute); - - @Override - SubGraphImplementor addKeySubGraph(PersistentAttribute attribute, Class subtype); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainModelHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainModelHelper.java index e9bc9296a5ed..5d5c87510205 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainModelHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainModelHelper.java @@ -4,15 +4,10 @@ */ package org.hibernate.metamodel.model.domain.internal; -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; -import org.hibernate.graph.internal.SubGraphImpl; -import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.MappingMetamodel; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ModelPart; -import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; -import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; @@ -25,35 +20,6 @@ */ public class DomainModelHelper { - @SuppressWarnings("unchecked") - public static ManagedDomainType resolveSubType( - ManagedDomainType baseType, - String subTypeName, - JpaMetamodel jpaMetamodel) { - if ( baseType instanceof EmbeddableDomainType ) { - // todo : at least validate the string is a valid subtype of the embeddable class? - return (ManagedDomainType) baseType; - } - - // first, try to find it by name directly - final ManagedDomainType subManagedType = jpaMetamodel.resolveHqlEntityReference( subTypeName ); - if ( subManagedType != null ) { - return subManagedType; - } - - // it could still be a mapped-superclass - try { - final Class javaType = - jpaMetamodel.getServiceRegistry().requireService( ClassLoaderService.class ) - .classForName( subTypeName ); - return (ManagedDomainType) jpaMetamodel.managedType( javaType ); - } - catch (Exception ignore) { - } - - throw new IllegalArgumentException( "Unknown subtype name (" + baseType.getTypeName() + ") : " + subTypeName ); - } - static boolean isCompatible( PersistentAttribute attribute1, PersistentAttribute attribute2, @@ -94,43 +60,4 @@ static ModelPart getEntityAttributeModelPart( return candidate; } } - - public static ManagedDomainType findSubType(ManagedDomainType type, Class subtype) { - if ( type.getBindableJavaType() == subtype ) { - @SuppressWarnings("unchecked") - final ManagedDomainType result = (ManagedDomainType) type; - return result; - } - for ( ManagedDomainType candidate : type.getSubTypes() ) { - if ( candidate.getBindableJavaType() == subtype ) { - @SuppressWarnings("unchecked") - final ManagedDomainType result = (ManagedDomainType) candidate; - return result; - } - } - for ( ManagedDomainType candidate : type.getSubTypes() ) { - final ManagedDomainType candidateSubtype = findSubType( candidate, subtype ); - if ( candidateSubtype != null) { - return candidateSubtype; - } - } - throw new IllegalArgumentException( "The class '" + subtype.getName() - + "' is not a mapped subtype of '" + type.getTypeName() + "'" ); -// return metamodel.managedType( subtype ); - } - - public static SubGraphImplementor makeSubGraph(ManagedDomainType type, Class subtype) { - if ( type.getBindableJavaType().isAssignableFrom( subtype ) ) { - return new SubGraphImpl( type, true ); - } - else { - throw new IllegalArgumentException( - String.format( - "Type '%s' cannot be treated as subtype '%s'", - type.getTypeName(), - subtype.getName() - ) - ); - } - } } 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 76bcef67f6fa..bf26e3d616af 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 @@ -320,16 +320,20 @@ public EnumJavaType getEnumType(String className) { if ( enumJavaType != null ) { return enumJavaType; } - final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); - try { - final Class clazz = classLoaderService.classForName( className ); - if ( clazz == null || !clazz.isEnum() ) { - return null; + else { + final ClassLoaderService classLoaderService = + serviceRegistry.requireService( ClassLoaderService.class ); + try { + final Class clazz = classLoaderService.classForName( className ); + if ( clazz == null || !clazz.isEnum() ) { + return null; + } + //noinspection rawtypes,unchecked + return new EnumJavaType( clazz ); + } + catch (ClassLoadingException e) { + throw new RuntimeException( e ); } - return new EnumJavaType( clazz ); - } - catch (ClassLoadingException e) { - throw new RuntimeException( e ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/EntityGraphTraversalState.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/EntityGraphTraversalState.java index d405e3e61ff4..4a335b924b68 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/EntityGraphTraversalState.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/EntityGraphTraversalState.java @@ -6,7 +6,6 @@ import org.hibernate.Incubating; import org.hibernate.engine.FetchTiming; -import org.hibernate.graph.AttributeNode; import org.hibernate.graph.spi.GraphImplementor; /** @@ -59,14 +58,8 @@ public boolean isJoined() { } /** - * Traverses to the next part of the Jakarta Persistence entity graph relating to the - * given fetchable. - *

- * - * The {@link AttributeNode} corresponding to the given `fetchable` is resolved. - * - * Depending on `exploreKeySubgraph`, either {@link AttributeNode#getSubGraphs()} - * or {@link AttributeNode#getKeySubGraphs()} will be used + * Traverses to the next part of the Jakarta Persistence entity graph relating to + * the given {@link Fetchable}. */ TraversalResult traverse(FetchParent parent, Fetchable fetchable, boolean exploreKeySubgraph); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphsTest.java index 8a4dcfeb6683..75a7c38af602 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphsTest.java @@ -14,14 +14,15 @@ public class EntityGraphsTest extends AbstractEntityGraphTest { - private final void checkMerge(Class rootType, EntityGraph expected, @SuppressWarnings("unchecked") EntityGraph... graphs) { + @SafeVarargs + private void checkMerge(Class rootType, EntityGraph expected, EntityGraph... graphs) { EntityManager entityManager = getOrCreateEntityManager(); EntityGraph actual = EntityGraphs.merge( entityManager, rootType, graphs ); Assert.assertTrue( EntityGraphs.areEqual( expected, actual ) ); } @SafeVarargs - private final void checkMerge(EntityGraph expected, EntityGraph... graphs) { + private void checkMerge(EntityGraph expected, EntityGraph... graphs) { checkMerge( GraphParsingTestEntity.class, expected, graphs ); } From cced71703f805125a0833ef80de8569697f31938 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Wed, 1 Jan 2025 22:40:22 +0100 Subject: [PATCH 5/9] minor change, for possibly better performance --- .../hibernate/graph/internal/AttributeNodeImpl.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java index 30a59fd32adc..e71caeee3ce0 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java @@ -6,7 +6,6 @@ import java.util.HashMap; import java.util.Map; -import java.util.stream.Collectors; import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.graph.spi.SubGraphImplementor; @@ -161,9 +160,9 @@ private Map, SubGraphImplementor> makeMapC return null; } else { - return nodeMap.entrySet().stream() - .map(entry -> Map.entry( entry.getKey(), entry.getValue().makeCopy( mutable ) )) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + final HashMap, SubGraphImplementor> map = new HashMap<>( nodeMap.size() ); + nodeMap.forEach( (attribute, subgraph) -> map.put( attribute, subgraph.makeCopy( mutable ) ) ); + return map; } } @@ -194,15 +193,13 @@ private void mergeToSubgraph(SubGraphImplementor subgraph) { } private SubGraphImplementor getSubgraphForPut(SubGraphImplementor subgraph) { - final SubGraphImplementor existing; if ( subgraphMap == null ) { subgraphMap = new HashMap<>(); - existing = null; + return null; } else { - existing = getSubgraph( subgraph.getClassType() ); + return getSubgraph( subgraph.getClassType() ); } - return existing; } private SubGraphImplementor getKeySubgraphForPut(SubGraphImplementor subgraph) { From 35fba779be63c71fd51ef4ca2d862e31cc3f9c49 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Thu, 2 Jan 2025 00:19:24 +0100 Subject: [PATCH 6/9] Graphpocalypse: major revision/refactoring of EntityGraph support - attempt to fill in unimplemented operations from JPA 3.2 - organize operations on Graph/GraphImplementor --- .../main/java/org/hibernate/graph/Graph.java | 105 ++++++++------- .../java/org/hibernate/graph/RootGraph.java | 5 + .../graph/internal/AbstractGraph.java | 86 +++++++----- .../graph/internal/AttributeNodeImpl.java | 50 +++++-- .../graph/internal/RootGraphImpl.java | 34 ----- .../hibernate/graph/spi/GraphImplementor.java | 29 ++-- .../query/sqm/internal/AppliedGraphs.java | 2 +- .../parser/EntityGraphParserTest.java | 2 +- .../orm/test/jpa/graphs/EntityGraphTest.java | 127 ++++++++++++++++++ 9 files changed, 291 insertions(+), 149 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java index d3d5c8762ba4..d41953ca8b1e 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java @@ -7,9 +7,9 @@ import java.util.List; import jakarta.persistence.metamodel.Attribute; -import jakarta.persistence.metamodel.MapAttribute; import jakarta.persistence.metamodel.PluralAttribute; import org.hibernate.metamodel.model.domain.ManagedDomainType; +import org.hibernate.metamodel.model.domain.MapPersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute; /** @@ -32,18 +32,11 @@ public interface Graph extends GraphNode, jakarta.persistence.Graph { /** - * Add a subgraph rooted at a plural attribute, allowing further - * nodes to be added to the subgraph. - * - * @apiNote This method is missing in JPA, and nodes cannot be - * added in a typesafe way to subgraphs representing - * fetched collections + * Get a list of all existing AttributeNodes within this container. * - * @since 6.3 + * @see #getAttributeNodes */ - default SubGraph addPluralSubgraph(PluralAttribute attribute) { - return addSubGraph( attribute.getName() ); - } + List> getAttributeNodeList(); /** * Graphs apply only to {@link jakarta.persistence.metamodel.ManagedType}s. @@ -89,11 +82,6 @@ RootGraph makeRootGraph(String name, boolean mutable) */ AttributeNode findAttributeNode(String attributeName); - @Override - default jakarta.persistence.AttributeNode getAttributeNode(String attributeName) { - return findAttributeNode( attributeName ); - } - /** * Find an already existing AttributeNode by corresponding attribute * reference, within this container. @@ -103,10 +91,25 @@ default jakarta.persistence.AttributeNode getAttributeNode(String attribu AttributeNode findAttributeNode(PersistentAttribute attribute); @Override - default jakarta.persistence.AttributeNode getAttributeNode(Attribute attribute) { + default AttributeNode getAttributeNode(String attributeName) { + return findAttributeNode( attributeName ); + } + + @Override + default AttributeNode getAttributeNode(Attribute attribute) { return findAttributeNode( (PersistentAttribute) attribute ); } + @Override + default boolean hasAttributeNode(String attributeName) { + return getAttributeNode( attributeName ) != null; + } + + @Override + default boolean hasAttributeNode(Attribute attribute) { + return getAttributeNode( attribute ) != null; + } + /** * Add an {@link AttributeNode} (with no associated {@link SubGraph}) * to this container by attribute reference. @@ -117,35 +120,23 @@ AttributeNode addAttributeNode(PersistentAttribute attrib throws CannotContainSubGraphException; @Override - default jakarta.persistence.AttributeNode addAttributeNode(Attribute attribute) { + default AttributeNode addAttributeNode(Attribute attribute) { return addAttributeNode( (PersistentAttribute) attribute ); } - /** - * Get a list of all existing AttributeNodes within this container. - * - * @see #getAttributeNodes - */ - List> getAttributeNodeList(); - - /** - * @deprecated Use {@link #getAttributeNodeList} - */ - @Deprecated(since = "7.0", forRemoval = true) - default List> getGraphAttributeNodes() { - return getAttributeNodeList(); - } - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Subgraph nodes + SubGraph addTreatedSubGraph(Class type); + /** * Create and return a new (mutable) {@link SubGraph} associated with * the named {@link AttributeNode}. * * @apiNote If no such AttributeNode exists yet, it is created. */ + @Deprecated SubGraph addSubGraph(String attributeName); SubGraph addSubGraph(String attributeName, Class type); @@ -160,6 +151,15 @@ default List> getGraphAttributeNodes() { SubGraph addSubGraph(PersistentAttribute attribute, Class type); + SubGraph addSubGraph(MapPersistentAttribute attribute, ManagedDomainType type); + + @Deprecated + SubGraph addKeySubGraph(String attributeName); + + SubGraph addKeySubGraph(String attributeName, Class type); + + SubGraph addKeySubGraph(PersistentAttribute attribute, ManagedDomainType type); + @Override default SubGraph addTreatedSubgraph(Attribute attribute, Class type) { return addSubGraph( (PersistentAttribute) attribute, type ); @@ -185,19 +185,6 @@ default SubGraph addSubgraph(String name, Class type) { return addSubGraph( name, type ); } - SubGraph addKeySubGraph(String attributeName); - SubGraph addKeySubGraph(String attributeName, Class type); - - @Override @Deprecated(forRemoval = true) - default SubGraph addKeySubgraph(Attribute attribute) { - throw new UnsupportedOperationException("This operation will be removed in JPA 4"); - } - - @Override @Deprecated(forRemoval = true) - default SubGraph addKeySubgraph(Attribute attribute, Class type) { - throw new UnsupportedOperationException("This operation will be removed in JPA 4"); - } - @Override default SubGraph addKeySubgraph(String name) { return addKeySubGraph( name ); @@ -208,10 +195,28 @@ default SubGraph addKeySubgraph(String name, Class type) { return addKeySubGraph( name, type ); } - @Override - SubGraph addTreatedElementSubgraph(PluralAttribute attribute, Class type); + /** + * Add a subgraph rooted at a plural attribute, allowing further nodes + * to be added to the subgraph. + * + * @apiNote {@link #addElementSubgraph(PluralAttribute)} was added + * in JPA 3.2, and so this method is no longer really needed + * + * @since 6.3 + * + * @see #addElementSubgraph(PluralAttribute) + */ + default SubGraph addPluralSubgraph(PluralAttribute attribute) { + return addSubGraph( attribute.getName(), attribute.getBindableJavaType() ); + } - @Override - SubGraph addTreatedMapKeySubgraph(MapAttribute attribute, Class type); + @Override @Deprecated(forRemoval = true) + default SubGraph addKeySubgraph(Attribute attribute) { + throw new UnsupportedOperationException("This operation will be removed in JPA 4"); + } + @Override @Deprecated(forRemoval = true) + default SubGraph addKeySubgraph(Attribute attribute, Class type) { + throw new UnsupportedOperationException("This operation will be removed in JPA 4"); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java index 0685ce7d620f..5a6c250cbaa7 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java @@ -33,4 +33,9 @@ public interface RootGraph extends Graph, EntityGraph { default SubGraph addSubclassSubgraph(Class type) { return (SubGraph) addTreatedSubgraph( (Class) type ); } + + @Override + default SubGraph addTreatedSubgraph(Class type) { + return addTreatedSubGraph( type ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java index be913dc42989..b89414221ea8 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java @@ -12,7 +12,6 @@ import jakarta.persistence.metamodel.MapAttribute; import jakarta.persistence.metamodel.PluralAttribute; import org.hibernate.AssertionFailure; -import org.hibernate.graph.AttributeNode; import org.hibernate.graph.CannotBecomeEntityGraphException; import org.hibernate.graph.RootGraph; import org.hibernate.graph.SubGraph; @@ -22,6 +21,7 @@ import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType; +import org.hibernate.metamodel.model.domain.MapPersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute; import org.hibernate.query.sqm.SqmPathSource; @@ -40,6 +40,7 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G private final ManagedDomainType managedType; private Map, AttributeNodeImplementor> attributeNodes; + private List> subgraphs; public AbstractGraph(ManagedDomainType managedType, boolean mutable) { super( mutable ); @@ -115,7 +116,7 @@ private void addAttributeNode(PersistentAttribute attribute, A } @Override - public List> getAttributeNodeList() { + public List> getAttributeNodeList() { return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() ); } @@ -123,8 +124,20 @@ public List> getAttributeNodeList() { public AttributeNodeImplementor findAttributeNode(String attributeName) { final PersistentAttribute attribute = findAttributeInSupertypes( attributeName ); @SuppressWarnings("unchecked") // The JPA API is unsafe by nature - final PersistentAttribute result = (PersistentAttribute) attribute; - return attribute == null ? null : findAttributeNode( result ); + final PersistentAttribute persistentAttribute = (PersistentAttribute) attribute; + final AttributeNodeImplementor node = attribute == null ? null : findAttributeNode( persistentAttribute ); + if ( node == null && subgraphs != null ) { + for ( SubGraphImplementor subgraph : subgraphs ) { + final AttributeNodeImplementor subgraphNode = subgraph.findAttributeNode( attributeName ); + if ( subgraphNode != null ) { + return subgraphNode; + } + } + return null; + } + else { + return node; + } } @Override @@ -137,11 +150,6 @@ public List> getAttributeNodes() { return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() ); } - @Override - public List> getAttributeNodeImplementors() { - return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() ); - } - @Override public Map, AttributeNodeImplementor> getAttributeNodesByAttribute() { return attributeNodes == null ? emptyMap() : unmodifiableMap( attributeNodes ); @@ -243,7 +251,7 @@ private AttributeNodeImplementor getNode(PersistentAttribute SubGraphImplementor addSubGraph(String attributeName) { return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeSubGraph(); } @@ -259,20 +267,22 @@ public SubGraphImplementor addSubGraph(PersistentAttribute SubGraphImplementor addSubGraph( - PersistentAttribute attribute, Class subtype) { + public SubGraphImplementor addSubGraph(PersistentAttribute attribute, Class subtype) { + return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype ); + } + + @Override + public SubGraphImplementor addSubGraph(MapPersistentAttribute attribute, ManagedDomainType subtype) { return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype ); } @Override - public SubGraphImplementor addTreatedSubgraph(Attribute attribute, Class type) { - // TODO Test this it's probably not right! - final ManagedDomainType managedDomainType = getGraphedType().getMetamodel().managedType( type ); - return new SubGraphImpl<>( managedDomainType,false ); + public SubGraphImplementor addKeySubGraph(PersistentAttribute attribute, ManagedDomainType subtype) { + return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subtype ); } @Override - @SuppressWarnings("unchecked") // The JPA API is unsafe by nature + @SuppressWarnings("unchecked") // The API is unsafe by nature public SubGraphImplementor addKeySubGraph(String attributeName) { return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeKeySubGraph(); } @@ -282,37 +292,49 @@ public SubGraphImplementor addKeySubGraph(String attributeName, Class SubGraphImplementor addTreatedElementSubgraph( - PluralAttribute attribute, - Class type) { - throw new UnsupportedOperationException( "Not yet implemented" ); + public SubGraphImplementor addMapKeySubgraph(MapAttribute attribute) { + return findOrCreateAttributeNode( attribute.getName() ).makeKeySubGraph( attribute.getKeyJavaType() ); } @Override - public SubGraphImplementor addTreatedMapKeySubgraph(MapAttribute attribute, Class type) { - throw new UnsupportedOperationException( "Not yet implemented" ); + public SubGraphImplementor addTreatedMapKeySubgraph( + MapAttribute attribute, + Class type) { + return addMapKeySubgraph( attribute ).addTreatedSubGraph( type ); + } + + @Override @SuppressWarnings("unchecked") // The JPA API is unsafe by nature + public SubGraphImplementor addElementSubgraph(String attributeName) { + return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeSubGraph(); } @Override public SubGraphImplementor addElementSubgraph(PluralAttribute attribute) { - throw new UnsupportedOperationException( "Not yet implemented" ); + return findOrCreateAttributeNode( attribute.getName() ) + .makeSubGraph( (ManagedDomainType) attribute.getElementType() ); } @Override - public SubGraphImplementor addElementSubgraph(String attributeName) { - throw new UnsupportedOperationException( "Not yet implemented" ); + public SubGraphImplementor addElementSubgraph(String attributeName, Class type) { + return findOrCreateAttributeNode( attributeName ).makeSubGraph( type); } @Override - public SubGraphImplementor addElementSubgraph(String attributeName, Class type) { - throw new UnsupportedOperationException( "Not yet implemented" ); + public SubGraphImplementor addTreatedElementSubgraph( + PluralAttribute attribute, + Class type) { + return addElementSubgraph( attribute ).addTreatedSubGraph( type ); } @Override - public SubGraphImplementor addMapKeySubgraph(MapAttribute attribute) { - throw new UnsupportedOperationException( "Not yet implemented" ); + public SubGraphImplementor addTreatedSubGraph(Class type) { + final ManagedDomainType managedDomainType = getGraphedType().getMetamodel().managedType( type ); + final SubGraphImpl subgraph = new SubGraphImpl<>( managedDomainType, this, true ); + if ( subgraphs == null ) { + subgraphs = new ArrayList<>( 1 ); + } + subgraphs.add( subgraph ); + return subgraph; } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java index e71caeee3ce0..400ac0690d19 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java @@ -79,44 +79,59 @@ public SubGraphImplementor makeSubGraph(Class type) { public SubGraphImplementor makeSubGraph(ManagedDomainType subtype) { verifyMutability(); assert subtype != null; - if ( !attribute.getValueGraphType().getBindableJavaType().isAssignableFrom( subtype.getJavaType() ) ) { - throw new IllegalArgumentException( "Not a subtype: " + subtype.getJavaType() ); + final Class javaType = subtype.getJavaType(); + if ( !attribute.getValueGraphType().getBindableJavaType().isAssignableFrom( javaType ) ) { + throw new IllegalArgumentException( "Not a subtype: " + javaType.getName() ); + } + final SubGraphImplementor existing = subgraphMap == null ? null : getSubgraph( javaType ); + if ( existing != null ) { + return existing; + } + else { + final SubGraphImplementor subGraph = new SubGraphImpl<>( subtype, true ); + addSubGraph( subGraph ); + return subGraph; } - final SubGraphImplementor subGraph = new SubGraphImpl<>( subtype, true ); - addSubGraph( subGraph ); - return subGraph; } @Override public void addSubGraph(SubGraphImplementor subgraph) { + addSubgraph( subgraph ); + } + + private void addSubgraph(SubGraphImplementor subgraph) { if ( subgraphMap == null ) { subgraphMap = new HashMap<>(); subgraphMap.put( subgraph.getClassType(), subgraph ); } else { - final SubGraphImplementor existing = subgraphMap.get( subgraph.getClassType() ); + final SubGraphImplementor existing = getSubgraph( subgraph.getClassType() ); if ( existing == null ) { subgraphMap.put( subgraph.getClassType(), subgraph ); } else { - existing.merge( (SubGraphImplementor) subgraph ); + existing.merge( subgraph ); } } } @Override public void addKeySubGraph(SubGraphImplementor subgraph) { + addKeySubgraph( subgraph ); + } + + private void addKeySubgraph(SubGraphImplementor subgraph) { if ( keySubgraphMap == null ) { keySubgraphMap = new HashMap<>(); keySubgraphMap.put( subgraph.getClassType(), subgraph ); } else { - final SubGraphImplementor existing = keySubgraphMap.get( subgraph.getClassType() ); + final SubGraphImplementor existing = getKeySubgraph( subgraph.getClassType() ); if ( existing == null ) { keySubgraphMap.put( subgraph.getClassType(), subgraph ); } else { - existing.merge( (SubGraphImplementor) subgraph ); + existing.merge( subgraph ); } } } @@ -135,12 +150,19 @@ public SubGraphImplementor makeKeySubGraph(Class type) { public SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype) { verifyMutability(); assert subtype != null; - if ( !attribute.getKeyGraphType().getBindableJavaType().isAssignableFrom( subtype.getJavaType() ) ) { - throw new IllegalArgumentException( "Not a key subtype: " + subtype.getJavaType() ); + final Class javaType = subtype.getJavaType(); + if ( !attribute.getKeyGraphType().getBindableJavaType().isAssignableFrom( javaType ) ) { + throw new IllegalArgumentException( "Not a key subtype: " + javaType.getName() ); + } + final SubGraphImplementor existing = keySubgraphMap == null ? null : getKeySubgraph( javaType ); + if ( existing != null ) { + return existing; + } + else { + final SubGraphImplementor subgraph = new SubGraphImpl<>( subtype, true ); + addKeySubGraph( subgraph ); + return subgraph; } - final SubGraphImplementor subgraph = new SubGraphImpl<>( subtype, true ); - addKeySubGraph( subgraph ); - return subgraph; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java index 521fe9c49bd3..2e8965910bfb 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java @@ -4,17 +4,12 @@ */ package org.hibernate.graph.internal; -import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.graph.spi.GraphHelper; import org.hibernate.graph.spi.GraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.model.domain.EntityDomainType; -import org.hibernate.metamodel.model.domain.ManagedDomainType; - -import java.util.ArrayList; -import java.util.List; /** * Implementation of the JPA-defined {@link jakarta.persistence.EntityGraph} interface. @@ -24,7 +19,6 @@ public class RootGraphImpl extends AbstractGraph implements RootGraphImplementor { private final String name; - private List> subgraphs; public RootGraphImpl(String name, EntityDomainType entityType, boolean mutable) { super( entityType, mutable ); @@ -69,32 +63,4 @@ public RootGraphImplementor makeRootGraph(String name, boolean mutable) { public RootGraphImplementor makeImmutableCopy(String name) { return makeRootGraph( name, false ); } - - @Override - public SubGraphImplementor addTreatedSubgraph(Class type) { - final ManagedDomainType managedDomainType = getGraphedType().getMetamodel().managedType( type ); - final SubGraphImpl subgraph = new SubGraphImpl<>( managedDomainType, this, true ); - if ( subgraphs == null ) { - subgraphs = new ArrayList<>( 1 ); - } - subgraphs.add( subgraph ); - return subgraph; - } - - @Override - public AttributeNodeImplementor findAttributeNode(String attributeName) { - final AttributeNodeImplementor node = super.findAttributeNode( attributeName ); - if ( node == null && subgraphs != null ) { - for ( SubGraphImpl subgraph : subgraphs ) { - final AttributeNodeImplementor subgraphNode = subgraph.findAttributeNode( attributeName ); - if ( subgraphNode != null ) { - return subgraphNode; - } - } - return null; - } - else { - return node; - } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java index d6d21e7e1931..989536f121b2 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java @@ -9,9 +9,10 @@ import org.hibernate.graph.CannotBecomeEntityGraphException; import org.hibernate.graph.Graph; +import org.hibernate.metamodel.model.domain.ManagedDomainType; +import org.hibernate.metamodel.model.domain.MapPersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute; -import jakarta.persistence.metamodel.Attribute; /** * Integration version of the {@link Graph} contract @@ -35,16 +36,7 @@ RootGraphImplementor makeRootGraph(String name, boolean mutable) GraphImplementor makeCopy(boolean mutable); @Override - default boolean hasAttributeNode(String attributeName) { - return getAttributeNode( attributeName ) != null; - } - - @Override - default boolean hasAttributeNode(Attribute attribute) { - return getAttributeNode( attribute ) != null; - } - - List> getAttributeNodeImplementors(); + List> getAttributeNodeList(); Map, AttributeNodeImplementor> getAttributeNodesByAttribute(); @@ -58,12 +50,6 @@ default boolean hasAttributeNode(Attribute attribute) { AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute); - @Override - AttributeNodeImplementor addAttributeNode(String attributeName); - - @Override - AttributeNodeImplementor addAttributeNode(Attribute attribute); - @Override AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute); @@ -84,4 +70,13 @@ default boolean hasAttributeNode(Attribute attribute) { @Override SubGraphImplementor addKeySubGraph(String attributeName, Class subtype); + + @Override + SubGraphImplementor addSubGraph(MapPersistentAttribute attribute, ManagedDomainType subtype); + + @Override + SubGraphImplementor addKeySubGraph(PersistentAttribute attribute, ManagedDomainType subtype); + + @Override + SubGraphImplementor addTreatedSubGraph(Class type); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java index 0515b7e0b305..ba35ceecfbd9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java @@ -26,7 +26,7 @@ public static boolean containsCollectionFetches(QueryOptions queryOptions) { } private static boolean containsCollectionFetches(GraphImplementor graph) { - for ( AttributeNodeImplementor node : graph.getAttributeNodeImplementors() ) { + for ( AttributeNodeImplementor node : graph.getAttributeNodeList() ) { if ( node.getAttributeDescriptor().isCollection() ) { return true; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java index 677e436e808c..7758b090ece2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java @@ -176,7 +176,7 @@ public void testLinkSubtypeParsing() { RootGraphImplementor graph = parseGraph( "linkToOne(name, description), linkToOne(GraphParsingTestSubEntity: sub)" ); assertNotNull( graph ); - List> attrs = graph.getAttributeNodeImplementors(); + List> attrs = graph.getAttributeNodeList(); assertNotNull( attrs ); assertEquals( 1, attrs.size() ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/graphs/EntityGraphTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/graphs/EntityGraphTest.java index d99cb6529575..168f3dcc9175 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/graphs/EntityGraphTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/graphs/EntityGraphTest.java @@ -4,6 +4,7 @@ */ package org.hibernate.orm.test.jpa.graphs; +import jakarta.persistence.ManyToMany; import jakarta.persistence.MapKey; import java.util.HashMap; import java.util.HashSet; @@ -34,6 +35,8 @@ import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Root; +import jakarta.persistence.metamodel.Attribute; +import jakarta.persistence.metamodel.PluralAttribute; import org.hibernate.Hibernate; import org.hibernate.testing.util.uuid.SafeRandomUUIDGenerator; import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; @@ -519,6 +522,127 @@ public void testTreatedSubgraph() { em.close(); } + @Test + public void testElementSubgraph() { + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Bar bar = new Bar(); + Foo foo = new Foo(); + Baz baz = new Baz(); + foo.baz = baz; + foo.bar = bar; + bar.foos.add( foo ); + baz.foos.add( foo ); + em.persist( bar ); + em.persist( baz ); + em.persist( foo ); + em.flush(); + em.clear(); + + EntityGraph graph = em.createEntityGraph( Bar.class ); + Subgraph subgraph = graph.addElementSubgraph( "foos", Foo.class ); + subgraph.addAttributeNode( "baz" ); + Bar b = em.find( graph, bar.id ); + assertTrue( Hibernate.isInitialized( b.foos ) ); + assertTrue( Hibernate.isInitialized( b.foos.iterator().next().baz ) ); + + em.getTransaction().rollback(); + em.close(); + } + + @Test + public void testTreatedElementSubgraph() { + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + AnimalOwner animalOwner = new AnimalOwner(); + Dog dog = new Dog(); + Cat cat = new Cat(); + Kennel kennel = new Kennel(); + dog.kennel = kennel; + animalOwner.animals.add( dog ); + animalOwner.animals.add( cat ); + em.persist( animalOwner ); + em.persist( kennel ); + em.persist( dog ); + em.persist( cat ); + em.flush(); + em.clear(); + + PluralAttribute animalsAttribute = + (PluralAttribute) + em.getEntityManagerFactory().getMetamodel() + .entity( AnimalOwner.class ) + .getAttribute( "animals" ); + + EntityGraph graph = em.createEntityGraph( AnimalOwner.class ); + Subgraph subgraph = graph.addElementSubgraph( animalsAttribute ); + AnimalOwner owner = em.find( graph, animalOwner.id ); + assertTrue( Hibernate.isInitialized( owner.animals ) ); + assertEquals( 2, owner.animals.size() ); + owner.animals.forEach( animal -> { + if (animal instanceof Dog d ) { + assertFalse( Hibernate.isInitialized( d.kennel ) ); + } + } ); + + em.clear(); + + graph = em.createEntityGraph( AnimalOwner.class ); + subgraph = graph.addElementSubgraph( animalsAttribute ); + Subgraph treated = graph.addTreatedElementSubgraph( animalsAttribute, Dog.class ); + treated.addAttributeNode( "kennel" ); + owner = em.find( graph, animalOwner.id ); + assertTrue( Hibernate.isInitialized( owner.animals ) ); + assertEquals( 2, owner.animals.size() ); + owner.animals.forEach( animal -> { + if (animal instanceof Dog d ) { + assertTrue( Hibernate.isInitialized( d.kennel ) ); + } + } ); + + em.getTransaction().rollback(); + em.close(); + } + + @Test + public void testTreatedElementSubgraph2() { + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + AnimalOwner animalOwner = new AnimalOwner(); + Dog dog = new Dog(); + Cat cat = new Cat(); + Kennel kennel = new Kennel(); + dog.kennel = kennel; + animalOwner.animals.add( dog ); + animalOwner.animals.add( cat ); + em.persist( animalOwner ); + em.persist( kennel ); + em.persist( dog ); + em.persist( cat ); + em.flush(); + em.clear(); + + Attribute kennelAttribute = + (Attribute) + em.getEntityManagerFactory().getMetamodel() + .entity( Dog.class ) + .getAttribute( "kennel" ); + + EntityGraph graph = em.createEntityGraph( Animal.class ); + Animal animal = em.find( graph, dog.id ); + assertFalse( Hibernate.isInitialized( ((Dog) animal).kennel ) ); + + em.clear(); + + graph = em.createEntityGraph( Animal.class ); + graph.addTreatedSubgraph( Dog.class ).addAttributeNode( kennelAttribute ); + animal = em.find( graph, dog.id ); + assertTrue( Hibernate.isInitialized( ((Dog) animal).kennel ) ); + + em.getTransaction().rollback(); + em.close(); + } + @Entity(name = "Foo") @Table(name = "foo") public static class Foo { @@ -637,6 +761,9 @@ public static class AnimalOwner { @ManyToOne(fetch = FetchType.LAZY) public Animal animal; + + @ManyToMany + public Set animals = new HashSet<>(); } @Entity(name = "Animal") From dfd4205321dd6b2ea4bb34bcd78ae78a414ca2e2 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Thu, 2 Jan 2025 05:34:44 +0100 Subject: [PATCH 7/9] Graphpocalypse: major revision/refactoring of EntityGraph support - important simplification --- .../org/hibernate/graph/AttributeNode.java | 7 +- .../org/hibernate/graph/EntityGraphs.java | 1 - .../main/java/org/hibernate/graph/Graph.java | 19 +- .../graph/internal/AbstractGraph.java | 120 ++++++-- .../graph/internal/AttributeNodeImpl.java | 263 +++++++++--------- .../graph/internal/SubGraphImpl.java | 4 - .../graph/spi/AttributeNodeImplementor.java | 53 ++-- .../hibernate/graph/spi/GraphImplementor.java | 17 +- .../orm/test/graph/EntityGraphsTest.java | 2 +- 9 files changed, 280 insertions(+), 206 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java index 7029e0802787..da3daa569ce2 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java @@ -4,11 +4,12 @@ */ package org.hibernate.graph; -import java.util.Map; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; +import java.util.Map; + /** * Extends the JPA-defined {@link AttributeNode} with additional operations. * @@ -26,8 +27,8 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr SubGraph makeSubGraph(); SubGraph makeKeySubGraph(); - SubGraph makeSubGraph(Class type); - SubGraph makeKeySubGraph(Class type); + SubGraph makeSubGraph(Class subtype); + SubGraph makeKeySubGraph(Class subtype); SubGraph makeSubGraph(ManagedDomainType subtype); SubGraph makeKeySubGraph(ManagedDomainType subtype); diff --git a/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java b/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java index b1891aee19b3..021b2d5a5a89 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java @@ -61,7 +61,6 @@ private static EntityGraph mergeInternal( for ( jakarta.persistence.Graph graph : graphs ) { merged.merge( (GraphImplementor) graph ); } - } return merged; } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java index d41953ca8b1e..f0bc73fa67e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java @@ -11,6 +11,7 @@ import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.MapPersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute; +import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; /** * A container for {@link AttributeNode} references. @@ -130,6 +131,8 @@ default AttributeNode addAttributeNode(Attribute attribute) SubGraph addTreatedSubGraph(Class type); + SubGraph addTreatedSubGraph(ManagedDomainType type); + /** * Create and return a new (mutable) {@link SubGraph} associated with * the named {@link AttributeNode}. @@ -151,18 +154,22 @@ default AttributeNode addAttributeNode(Attribute attribute) SubGraph addSubGraph(PersistentAttribute attribute, Class type); - SubGraph addSubGraph(MapPersistentAttribute attribute, ManagedDomainType type); + SubGraph addSubGraph(PersistentAttribute attribute, ManagedDomainType type); + + SubGraph addElementSubGraph(PluralPersistentAttribute attribute, Class type); + + SubGraph addElementSubGraph(PluralPersistentAttribute attribute, ManagedDomainType type); @Deprecated SubGraph addKeySubGraph(String attributeName); SubGraph addKeySubGraph(String attributeName, Class type); - SubGraph addKeySubGraph(PersistentAttribute attribute, ManagedDomainType type); + SubGraph addKeySubGraph(MapPersistentAttribute attribute, ManagedDomainType type); @Override default SubGraph addTreatedSubgraph(Attribute attribute, Class type) { - return addSubGraph( (PersistentAttribute) attribute, type ); + return addSubGraph( (PersistentAttribute) attribute ).addTreatedSubGraph( type ); } @Override @@ -172,7 +179,7 @@ default SubGraph addSubgraph(Attribute attribute) { @Override default SubGraph addSubgraph(Attribute attribute, Class type) { - return addSubGraph( (PersistentAttribute) attribute, type ); + return addSubGraph( (PersistentAttribute) attribute ).addTreatedSubGraph( type ); } @Override @@ -182,7 +189,7 @@ default SubGraph addSubgraph(String name) { @Override default SubGraph addSubgraph(String name, Class type) { - return addSubGraph( name, type ); + return addSubGraph( name ).addTreatedSubGraph( type ); } @Override @@ -192,7 +199,7 @@ default SubGraph addKeySubgraph(String name) { @Override default SubGraph addKeySubgraph(String name, Class type) { - return addKeySubGraph( name, type ); + return addKeySubGraph( name ).addTreatedSubGraph( type ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java index b89414221ea8..9bf8dc55134e 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java @@ -23,6 +23,7 @@ import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.MapPersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute; +import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; import org.hibernate.query.sqm.SqmPathSource; import jakarta.persistence.metamodel.Attribute; @@ -39,8 +40,8 @@ public abstract class AbstractGraph extends AbstractGraphNode implements GraphImplementor { private final ManagedDomainType managedType; + private final Map, SubGraphImplementor> subgraphs = new HashMap<>(1); private Map, AttributeNodeImplementor> attributeNodes; - private List> subgraphs; public AbstractGraph(ManagedDomainType managedType, boolean mutable) { super( mutable ); @@ -50,8 +51,7 @@ public AbstractGraph(ManagedDomainType managedType, boolean mutable) { protected AbstractGraph(ManagedDomainType managedType, GraphImplementor graph, boolean mutable) { this( managedType, mutable ); attributeNodes = new HashMap<>( graph.getAttributeNodesByAttribute().size() ); - graph.getAttributeNodesByAttribute() - .forEach( (attribute, node) -> attributeNodes.put( attribute, node.makeCopy( mutable ) ) ); + mergeInternal( graph, mutable ); } protected AbstractGraph(GraphImplementor graph, boolean mutable) { @@ -76,42 +76,61 @@ public RootGraphImplementor makeRootGraph(String name, boolean mutable) { } @Override - public void merge(GraphImplementor graph) { + public void merge(GraphImplementor graph) { + merge( graph, true ); + } + + @Override + public void merge(GraphImplementor graph, boolean mutable) { if ( graph != null ) { verifyMutability(); - graph.getAttributeNodesByAttribute().forEach( (attribute, node) -> { - final AttributeNodeImplementor existingNode = findAttributeNode( attribute ); - if ( existingNode != null ) { - // keep the local one, but merge in the incoming one - mergeNode( node, existingNode ); - } - else { - addAttributeNode( attribute, node.makeCopy( true ) ); - } - } ); + mergeInternal( graph, mutable ); } } - private static void mergeNode(AttributeNodeImplementor node, AttributeNodeImplementor existingNode) { + private void mergeInternal(GraphImplementor graph, boolean mutable) { + graph.getAttributeNodesByAttribute().forEach( (attribute, node) -> { + final AttributeNodeImplementor existingNode = findAttributeNode( attribute ); + if ( existingNode != null ) { + // keep the local one, but merge in the incoming one + mergeNode( node, existingNode, mutable ); + } + else { + addAttributeNode( attribute, node.makeCopy( mutable ), mutable ); + } + } ); + graph.getSubGraphMap().forEach( (type, subgraph) -> { + final SubGraphImplementor existing = subgraphs.get( type ); + if ( existing != null ) { + existing.merge( (SubGraphImplementor) subgraph, mutable ); + } + else { + subgraphs.put( type, subgraph.makeCopy( mutable ) ); + } + } ); + } + + private static void mergeNode( + AttributeNodeImplementor node, AttributeNodeImplementor existingNode, boolean mutable) { if ( existingNode.getAttributeDescriptor() == node.getAttributeDescriptor() ) { @SuppressWarnings("unchecked") // safe, we just checked final AttributeNodeImplementor castNode = (AttributeNodeImplementor) node; - existingNode.merge( castNode ); + existingNode.merge( castNode, mutable ); } else { throw new AssertionFailure( "Attributes should have been identical" ); } } - private void addAttributeNode(PersistentAttribute attribute, AttributeNodeImplementor node) { + private void addAttributeNode( + PersistentAttribute attribute, AttributeNodeImplementor node, boolean mutable) { final AttributeNodeImplementor attributeNode = getNodeForPut( node.getAttributeDescriptor() ); if ( attributeNode == null ) { attributeNodes.put( attribute, node ); } else { // we assume the subgraph has been properly copied if needed - node.getSubGraphMap().forEach( (subtype, subgraph) -> attributeNode.addSubGraph( subgraph ) ); - node.getKeySubGraphMap().forEach( (subtype, subgraph) -> attributeNode.addKeySubGraph( subgraph ) ); + node.merge( attributeNode, mutable ); } } @@ -126,8 +145,8 @@ public AttributeNodeImplementor findAttributeNode(String attributeName) @SuppressWarnings("unchecked") // The JPA API is unsafe by nature final PersistentAttribute persistentAttribute = (PersistentAttribute) attribute; final AttributeNodeImplementor node = attribute == null ? null : findAttributeNode( persistentAttribute ); - if ( node == null && subgraphs != null ) { - for ( SubGraphImplementor subgraph : subgraphs ) { + if ( node == null ) { + for ( SubGraphImplementor subgraph : subgraphs.values() ) { final AttributeNodeImplementor subgraphNode = subgraph.findAttributeNode( attributeName ); if ( subgraphNode != null ) { return subgraphNode; @@ -272,12 +291,22 @@ public SubGraphImplementor addSubGraph(PersistentAttribute SubGraphImplementor addSubGraph(MapPersistentAttribute attribute, ManagedDomainType subtype) { + public SubGraphImplementor addSubGraph(PersistentAttribute attribute, ManagedDomainType subtype) { return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype ); } @Override - public SubGraphImplementor addKeySubGraph(PersistentAttribute attribute, ManagedDomainType subtype) { + public SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, Class type) { + return findOrCreateAttributeNode( attribute ).makeSubGraph( type ); + } + + @Override + public SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, ManagedDomainType type) { + return findOrCreateAttributeNode( attribute ).makeSubGraph( type ); + } + + @Override + public SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, ManagedDomainType subtype) { return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subtype ); } @@ -328,13 +357,44 @@ public SubGraphImplementor addTreatedElementSubgraph( } @Override - public SubGraphImplementor addTreatedSubGraph(Class type) { - final ManagedDomainType managedDomainType = getGraphedType().getMetamodel().managedType( type ); - final SubGraphImpl subgraph = new SubGraphImpl<>( managedDomainType, this, true ); - if ( subgraphs == null ) { - subgraphs = new ArrayList<>( 1 ); + public SubGraphImplementor addTreatedSubGraph(ManagedDomainType type) { + if ( getGraphedType().equals( type ) ) { + //noinspection unchecked + return (SubGraphImplementor) this; + } + else { + final Class javaType = type.getJavaType(); + final SubGraphImplementor castSubgraph = subgraph( javaType ); + if ( castSubgraph == null ) { + final SubGraphImpl subgraph = new SubGraphImpl<>( type, true ); + subgraphs.put( javaType, subgraph ); + return subgraph; + } + else { + return castSubgraph; + } + } + } + + private SubGraphImplementor subgraph(Class javaType) { + final SubGraphImplementor existing = subgraphs.get( javaType ); + if ( existing != null ) { + @SuppressWarnings("unchecked") + final SubGraphImplementor castSubgraph = (SubGraphImplementor) existing; + return castSubgraph; + } + else { + return null; } - subgraphs.add( subgraph ); - return subgraph; + } + + @Override + public SubGraphImplementor addTreatedSubGraph(Class type) { + return addTreatedSubGraph( getGraphedType().getMetamodel().managedType( type ) ); + } + + @Override + public Map, SubGraphImplementor> getSubGraphMap() { + return subgraphs; } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java index 400ac0690d19..6784c30cc8b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java @@ -4,16 +4,19 @@ */ package org.hibernate.graph.internal; -import java.util.HashMap; -import java.util.Map; - +import jakarta.persistence.Subgraph; import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.graph.spi.SubGraphImplementor; +import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; +import java.util.HashMap; +import java.util.Map; + import static java.util.Collections.emptyMap; + /** * Implementation of {@link jakarta.persistence.AttributeNode}. * @@ -24,25 +27,23 @@ public class AttributeNodeImpl implements AttributeNodeImplementor { private final PersistentAttribute attribute; - private Map, SubGraphImplementor> subgraphMap; - private Map, SubGraphImplementor> keySubgraphMap; + private SubGraphImplementor subgraph; + private SubGraphImplementor keySubgraph; public AttributeNodeImpl(PersistentAttribute attribute, boolean mutable) { - this(attribute, null, null, mutable); + this(attribute, mutable, null, null); } /** * Intended only for use from making a copy */ private AttributeNodeImpl( - PersistentAttribute attribute, - Map, SubGraphImplementor> subgraphMap, - Map, SubGraphImplementor> keySubgraphMap, - boolean mutable) { + PersistentAttribute attribute, boolean mutable, + SubGraphImplementor subgraph, SubGraphImplementor keySubgraph) { super( mutable ); this.attribute = attribute; - this.subgraphMap = subgraphMap; - this.keySubgraphMap = keySubgraphMap; + this.subgraph = subgraph; + this.keySubgraph = keySubgraph; } @Override @@ -56,191 +57,203 @@ public PersistentAttribute getAttributeDescriptor() { } @Override - public Map, SubGraphImplementor> getSubGraphMap() { - return subgraphMap == null ? emptyMap() : subgraphMap; + public SubGraphImplementor getSubGraph() { + return subgraph; } @Override - public Map, SubGraphImplementor> getKeySubGraphMap() { - return keySubgraphMap == null ? emptyMap() : keySubgraphMap; + public SubGraphImplementor getKeySubGraph() { + return keySubgraph; } - @Override - public SubGraphImplementor makeSubGraph() { - return makeSubGraph( (ManagedDomainType) attribute.getValueGraphType() ); + private SubGraphImplementor subgraph(ManagedDomainType valueType) { + if ( subgraph == null ) { + final SubGraphImplementor graph = new SubGraphImpl<>( valueType, true ); + subgraph = graph; + return graph; + } + else { + //noinspection unchecked + return (SubGraphImplementor) subgraph; + } } @Override - public SubGraphImplementor makeSubGraph(Class type) { - return makeSubGraph( attribute.getDeclaringType().getMetamodel().managedType( type ) ); + public SubGraphImplementor makeSubGraph() { + verifyMutability(); + return subgraph( (ManagedDomainType) attribute.getValueGraphType() ); } @Override - public SubGraphImplementor makeSubGraph(ManagedDomainType subtype) { + public SubGraphImplementor makeSubGraph(Class subtype) { verifyMutability(); - assert subtype != null; - final Class javaType = subtype.getJavaType(); - if ( !attribute.getValueGraphType().getBindableJavaType().isAssignableFrom( javaType ) ) { - throw new IllegalArgumentException( "Not a subtype: " + javaType.getName() ); + final DomainType type = attribute.getValueGraphType(); + if ( !type.getBindableJavaType().isAssignableFrom( subtype ) ) { + throw new IllegalArgumentException( "Not a subtype: " + subtype.getName() ); } - final SubGraphImplementor existing = subgraphMap == null ? null : getSubgraph( javaType ); - if ( existing != null ) { - return existing; + @SuppressWarnings("unchecked") + final ManagedDomainType valueType = (ManagedDomainType) type; + SubGraphImplementor subgraph = subgraph( valueType ); + if ( type.getBindableJavaType() == subtype ) { + //noinspection unchecked + return (SubGraphImplementor) subgraph; } else { - final SubGraphImplementor subGraph = new SubGraphImpl<>( subtype, true ); - addSubGraph( subGraph ); - return subGraph; + return subgraph.addTreatedSubGraph( subtype ); } } @Override - public void addSubGraph(SubGraphImplementor subgraph) { - addSubgraph( subgraph ); - } - - private void addSubgraph(SubGraphImplementor subgraph) { - if ( subgraphMap == null ) { - subgraphMap = new HashMap<>(); - subgraphMap.put( subgraph.getClassType(), subgraph ); + public SubGraphImplementor makeSubGraph(ManagedDomainType subtype) { + verifyMutability(); + final DomainType type = attribute.getValueGraphType(); + final Class javaType = subtype.getBindableJavaType(); + if ( !type.getBindableJavaType().isAssignableFrom( javaType ) ) { + throw new IllegalArgumentException( "Not a subtype: " + javaType.getName() ); + } + @SuppressWarnings("unchecked") + final ManagedDomainType valueType = (ManagedDomainType) type; + SubGraphImplementor subgraph = subgraph( valueType ); + if ( type.getBindableJavaType() == javaType ) { + //noinspection unchecked + return (SubGraphImplementor) subgraph; } else { - final SubGraphImplementor existing = getSubgraph( subgraph.getClassType() ); - if ( existing == null ) { - subgraphMap.put( subgraph.getClassType(), subgraph ); - } - else { - existing.merge( subgraph ); - } + return subgraph.addTreatedSubGraph( subtype ); } } - @Override - public void addKeySubGraph(SubGraphImplementor subgraph) { - addKeySubgraph( subgraph ); - } - - private void addKeySubgraph(SubGraphImplementor subgraph) { - if ( keySubgraphMap == null ) { - keySubgraphMap = new HashMap<>(); - keySubgraphMap.put( subgraph.getClassType(), subgraph ); + private SubGraphImplementor keySubgraph(ManagedDomainType keyType) { + if ( keySubgraph == null ) { + final SubGraphImplementor graph = new SubGraphImpl<>( keyType, true ); + keySubgraph = graph; + return graph; } else { - final SubGraphImplementor existing = getKeySubgraph( subgraph.getClassType() ); - if ( existing == null ) { - keySubgraphMap.put( subgraph.getClassType(), subgraph ); - } - else { - existing.merge( subgraph ); - } + //noinspection unchecked + return (SubGraphImplementor) keySubgraph; } } @Override public SubGraphImplementor makeKeySubGraph() { - return makeKeySubGraph( (ManagedDomainType) attribute.getKeyGraphType() ); + verifyMutability(); + return keySubgraph( (ManagedDomainType) attribute.getKeyGraphType() ); } @Override - public SubGraphImplementor makeKeySubGraph(Class type) { - return makeKeySubGraph( attribute.getDeclaringType().getMetamodel().managedType( type ) ); + public SubGraphImplementor makeKeySubGraph(Class subtype) { + verifyMutability(); + final DomainType type = attribute.getKeyGraphType(); + if ( !type.getBindableJavaType().isAssignableFrom( subtype ) ) { + throw new IllegalArgumentException( "Not a key subtype: " + subtype.getName() ); + } + @SuppressWarnings("unchecked") + final ManagedDomainType keyType = (ManagedDomainType) type; + final SubGraphImplementor keySubgraph = keySubgraph( keyType ); + if ( type.getBindableJavaType() == subtype ) { + //noinspection unchecked + return (SubGraphImplementor) keySubgraph; + } + else { + return keySubgraph.addTreatedSubGraph( subtype ); + } } @Override public SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype) { verifyMutability(); - assert subtype != null; - final Class javaType = subtype.getJavaType(); - if ( !attribute.getKeyGraphType().getBindableJavaType().isAssignableFrom( javaType ) ) { + final DomainType type = attribute.getKeyGraphType(); + final Class javaType = subtype.getBindableJavaType(); + if ( !type.getBindableJavaType().isAssignableFrom( javaType ) ) { throw new IllegalArgumentException( "Not a key subtype: " + javaType.getName() ); } - final SubGraphImplementor existing = keySubgraphMap == null ? null : getKeySubgraph( javaType ); - if ( existing != null ) { - return existing; + @SuppressWarnings("unchecked") + final ManagedDomainType keyType = (ManagedDomainType) type; + final SubGraphImplementor keySubgraph = keySubgraph( keyType ); + if ( type.getBindableJavaType() == javaType ) { + //noinspection unchecked + return (SubGraphImplementor) keySubgraph; } else { - final SubGraphImplementor subgraph = new SubGraphImpl<>( subtype, true ); - addKeySubGraph( subgraph ); - return subgraph; + return keySubgraph.addTreatedSubGraph( subtype ); } } @Override public AttributeNodeImplementor makeCopy(boolean mutable) { - return new AttributeNodeImpl<>( - this.attribute, - makeMapCopy( mutable, subgraphMap ), - makeMapCopy( mutable, keySubgraphMap ), - mutable - ); + return new AttributeNodeImpl<>( this.attribute, mutable, + subgraph == null ? null : subgraph.makeCopy( mutable ), + keySubgraph == null ? null : keySubgraph.makeCopy( mutable ) ); } - private Map, SubGraphImplementor> makeMapCopy( - boolean mutable, - Map, SubGraphImplementor> nodeMap) { - if ( nodeMap == null ) { - return null; + @Override + public void merge(AttributeNodeImplementor other, boolean mutable) { + final SubGraphImplementor otherSubgraph = other.getSubGraph(); + if ( otherSubgraph != null ) { + if ( subgraph == null ) { + subgraph = otherSubgraph.makeCopy( mutable ); + } + else { + subgraph.merge( (SubGraphImplementor) otherSubgraph, mutable ); + } } - else { - final HashMap, SubGraphImplementor> map = new HashMap<>( nodeMap.size() ); - nodeMap.forEach( (attribute, subgraph) -> map.put( attribute, subgraph.makeCopy( mutable ) ) ); - return map; + final SubGraphImplementor otherKeySubgraph = other.getKeySubGraph(); + if ( otherKeySubgraph != null ) { + if ( keySubgraph == null ) { + keySubgraph = otherKeySubgraph.makeCopy( mutable ); + } + else { + keySubgraph.merge( (SubGraphImplementor) otherKeySubgraph, mutable ); + } } } @Override - public void merge(AttributeNodeImplementor other) { - other.getSubGraphMap().values().forEach( this::mergeToSubgraph ); - other.getKeySubGraphMap().values().forEach( this::mergeToKeySubgraph ); - } - - private void mergeToKeySubgraph(SubGraphImplementor subgraph) { - final SubGraphImplementor existing = getKeySubgraphForPut( subgraph ); - if ( existing != null ) { - existing.merge( subgraph ); + public Map, SubGraphImplementor> getSubGraphMap() { + if ( subgraph == null ) { + return emptyMap(); } else { - addKeySubGraph( subgraph.makeCopy( true ) ); + final HashMap, SubGraphImplementor> map = new HashMap<>( subgraph.getSubGraphMap() ); + map.put( attribute.getValueGraphType().getBindableJavaType(), subgraph ); + return map; } } - private void mergeToSubgraph(SubGraphImplementor subgraph) { - final SubGraphImplementor existing = getSubgraphForPut( subgraph ); - if ( existing != null ) { - existing.merge( subgraph ); + @Override + public Map, SubGraphImplementor> getKeySubGraphMap() { + if ( keySubgraph == null ) { + return emptyMap(); } else { - addSubGraph( subgraph.makeCopy( true ) ); + final HashMap, SubGraphImplementor> map = new HashMap<>( keySubgraph.getSubGraphMap() ); + map.put( attribute.getKeyGraphType().getJavaType(), keySubgraph ); + return map; } } - private SubGraphImplementor getSubgraphForPut(SubGraphImplementor subgraph) { - if ( subgraphMap == null ) { - subgraphMap = new HashMap<>(); - return null; + @Override + public @SuppressWarnings("rawtypes") Map getSubgraphs() { + if ( subgraph == null ) { + return emptyMap(); } else { - return getSubgraph( subgraph.getClassType() ); + final HashMap map = new HashMap<>( subgraph.getSubGraphMap() ); + map.put( attribute.getValueGraphType().getBindableJavaType(), subgraph ); + return map; } } - private SubGraphImplementor getKeySubgraphForPut(SubGraphImplementor subgraph) { - if ( keySubgraphMap == null ) { - keySubgraphMap = new HashMap<>(); - return null; + @Override + public @SuppressWarnings("rawtypes") Map getKeySubgraphs() { + if ( keySubgraph == null ) { + return emptyMap(); } else { - return getKeySubgraph( subgraph.getClassType() ); + final HashMap map = new HashMap<>( keySubgraph.getSubGraphMap() ); + map.put( attribute.getKeyGraphType().getJavaType(), keySubgraph ); + return map; } } - - @SuppressWarnings("unchecked") - private SubGraphImplementor getSubgraph(Class incomingSubtype) { - return (SubGraphImplementor) subgraphMap.get( incomingSubtype ); - } - - @SuppressWarnings("unchecked") - private SubGraphImplementor getKeySubgraph(Class incomingSubtype) { - return (SubGraphImplementor) keySubgraphMap.get( incomingSubtype ); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java index 85eae4725a82..1e2f24537bbc 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java @@ -22,10 +22,6 @@ public SubGraphImpl(AbstractGraph original, boolean mutable) { super( original, mutable ); } - public SubGraphImpl(ManagedDomainType managedDomainType, AbstractGraph original, boolean mutable) { - super( managedDomainType, original, mutable ); - } - @Override public SubGraphImplementor makeCopy(boolean mutable) { return new SubGraphImpl<>( this, mutable ); diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java index e9bf2b2f0385..1a1d66b7285a 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java @@ -4,15 +4,11 @@ */ package org.hibernate.graph.spi; -import java.util.Map; - -import jakarta.persistence.Subgraph; - import org.hibernate.graph.AttributeNode; import org.hibernate.graph.SubGraph; import org.hibernate.metamodel.model.domain.ManagedDomainType; -import static java.util.Collections.unmodifiableMap; +import java.util.Map; /** * Integration version of the {@link AttributeNode} contract @@ -22,29 +18,6 @@ */ public interface AttributeNodeImplementor extends AttributeNode, GraphNodeImplementor { - Map, SubGraphImplementor> getSubGraphMap(); - Map, SubGraphImplementor> getKeySubGraphMap(); - - @Override - default Map, ? extends SubGraph> getSubGraphs() { - return unmodifiableMap( getSubGraphMap() ); - } - - @Override - default Map, ? extends SubGraph> getKeySubGraphs() { - return unmodifiableMap( getKeySubGraphMap() ); - } - - @Override // JPA API uses raw types - default @SuppressWarnings("rawtypes") Map getSubgraphs() { - return unmodifiableMap( getSubGraphMap() ); - } - - @Override // JPA API uses raw types - default @SuppressWarnings("rawtypes") Map getKeySubgraphs() { - return unmodifiableMap( getKeySubGraphMap() ); - } - @Override AttributeNodeImplementor makeCopy(boolean mutable); @@ -55,10 +28,10 @@ public interface AttributeNodeImplementor extends AttributeNode, GraphNode SubGraphImplementor makeKeySubGraph(); @Override - SubGraphImplementor makeSubGraph(Class type); + SubGraphImplementor makeSubGraph(Class subtype); @Override - SubGraphImplementor makeKeySubGraph(Class type); + SubGraphImplementor makeKeySubGraph(Class subtype); @Override SubGraphImplementor makeSubGraph(ManagedDomainType subtype); @@ -66,9 +39,23 @@ public interface AttributeNodeImplementor extends AttributeNode, GraphNode @Override SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype); - void merge(AttributeNodeImplementor other); + void merge(AttributeNodeImplementor other, boolean mutable); + + SubGraphImplementor getSubGraph(); - void addSubGraph(SubGraphImplementor subgraph); + SubGraphImplementor getKeySubGraph(); + + Map, SubGraphImplementor> getSubGraphMap(); + + Map, SubGraphImplementor> getKeySubGraphMap(); - void addKeySubGraph(SubGraphImplementor subgraph); + @Override + default Map, ? extends SubGraph> getSubGraphs() { + return getSubGraphMap(); + } + + @Override + default Map, ? extends SubGraph> getKeySubGraphs() { + return getKeySubGraphMap(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java index 989536f121b2..81afe4cf5860 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java @@ -12,6 +12,7 @@ import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.MapPersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute; +import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; /** @@ -23,7 +24,9 @@ */ public interface GraphImplementor extends Graph, GraphNodeImplementor { - void merge(GraphImplementor other); + void merge(GraphImplementor other); + + void merge(GraphImplementor other, boolean mutable); @Override @Deprecated(forRemoval = true) RootGraphImplementor makeRootGraph(String name, boolean mutable) @@ -72,11 +75,19 @@ RootGraphImplementor makeRootGraph(String name, boolean mutable) SubGraphImplementor addKeySubGraph(String attributeName, Class subtype); @Override - SubGraphImplementor addSubGraph(MapPersistentAttribute attribute, ManagedDomainType subtype); + SubGraphImplementor addSubGraph(PersistentAttribute attribute, ManagedDomainType subtype); + + SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, Class type); + + SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, ManagedDomainType type); @Override - SubGraphImplementor addKeySubGraph(PersistentAttribute attribute, ManagedDomainType subtype); + SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, ManagedDomainType subtype); @Override SubGraphImplementor addTreatedSubGraph(Class type); + + SubGraphImplementor addTreatedSubGraph(ManagedDomainType type); + + Map, SubGraphImplementor> getSubGraphMap(); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/graph/EntityGraphsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/graph/EntityGraphsTest.java index 7e73ad0720fc..db1bbd8b8e16 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/graph/EntityGraphsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/graph/EntityGraphsTest.java @@ -25,7 +25,7 @@ private void checkMerge(Class rootType, EntityGraph expected, EntityGr } @SafeVarargs - private final void checkMerge(EntityGraph expected, EntityGraph... graphs) { + private void checkMerge(EntityGraph expected, EntityGraph... graphs) { checkMerge( GraphParsingTestEntity.class, expected, graphs ); } From 128221cd9d37a33fe0ade5dfe7f97fadd55a1a5b Mon Sep 17 00:00:00 2001 From: Gavin King Date: Thu, 2 Jan 2025 12:03:01 +0100 Subject: [PATCH 8/9] Graphpocalypse: major revision/refactoring of EntityGraph support - sort out handling of mutability - try to minimize diff --- .../org/hibernate/graph/AttributeNode.java | 13 ++ .../main/java/org/hibernate/graph/Graph.java | 37 ++-- .../graph/internal/AbstractGraph.java | 179 ++++++++------- .../graph/internal/AttributeNodeImpl.java | 204 +++++++----------- .../graph/internal/SubGraphImpl.java | 4 +- .../graph/spi/AttributeNodeImplementor.java | 16 +- .../hibernate/graph/spi/GraphImplementor.java | 10 +- .../graph/spi/SubGraphImplementor.java | 1 - .../query/sqm/internal/AppliedGraphs.java | 4 +- ...StandardEntityGraphTraversalStateImpl.java | 6 +- .../parser/EntityGraphParserTest.java | 2 +- .../orm/test/graph/EntityGraphsTest.java | 1 - 12 files changed, 230 insertions(+), 247 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java index da3daa569ce2..3f8582ef87e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java @@ -5,11 +5,14 @@ package org.hibernate.graph; +import jakarta.persistence.Subgraph; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; import java.util.Map; +import static java.util.Collections.unmodifiableMap; + /** * Extends the JPA-defined {@link AttributeNode} with additional operations. * @@ -24,6 +27,16 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr Map, ? extends SubGraph> getSubGraphs(); Map, ? extends SubGraph> getKeySubGraphs(); + @Override + default @SuppressWarnings("rawtypes") Map getSubgraphs() { + return unmodifiableMap( getSubGraphs() ); + } + + @Override + default @SuppressWarnings("rawtypes") Map getKeySubgraphs() { + return unmodifiableMap( getKeySubGraphs() ); + } + SubGraph makeSubGraph(); SubGraph makeKeySubGraph(); diff --git a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java index f0bc73fa67e4..fc34e1c7686d 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java @@ -117,8 +117,7 @@ default boolean hasAttributeNode(Attribute attribute) { * * @see #addAttributeNode(Attribute) */ - AttributeNode addAttributeNode(PersistentAttribute attribute) - throws CannotContainSubGraphException; + AttributeNode addAttributeNode(PersistentAttribute attribute); @Override default AttributeNode addAttributeNode(Attribute attribute) { @@ -140,9 +139,11 @@ default AttributeNode addAttributeNode(Attribute attribute) * @apiNote If no such AttributeNode exists yet, it is created. */ @Deprecated - SubGraph addSubGraph(String attributeName); + SubGraph addSubGraph(String attributeName) + throws CannotContainSubGraphException; - SubGraph addSubGraph(String attributeName, Class type); + SubGraph addSubGraph(String attributeName, Class type) + throws CannotContainSubGraphException; /** * Create and return a new (mutable) {@link SubGraph} associated with @@ -150,22 +151,30 @@ default AttributeNode addAttributeNode(Attribute attribute) * * @apiNote If no such AttributeNode exists yet, it is created. */ - SubGraph addSubGraph(PersistentAttribute attribute); + SubGraph addSubGraph(PersistentAttribute attribute) + throws CannotContainSubGraphException; - SubGraph addSubGraph(PersistentAttribute attribute, Class type); + SubGraph addSubGraph(PersistentAttribute attribute, Class type) + throws CannotContainSubGraphException; - SubGraph addSubGraph(PersistentAttribute attribute, ManagedDomainType type); + SubGraph addSubGraph(PersistentAttribute attribute, ManagedDomainType type) + throws CannotContainSubGraphException; - SubGraph addElementSubGraph(PluralPersistentAttribute attribute, Class type); + SubGraph addElementSubGraph(PluralPersistentAttribute attribute, Class type) + throws CannotContainSubGraphException; - SubGraph addElementSubGraph(PluralPersistentAttribute attribute, ManagedDomainType type); + SubGraph addElementSubGraph(PluralPersistentAttribute attribute, ManagedDomainType type) + throws CannotContainSubGraphException; @Deprecated - SubGraph addKeySubGraph(String attributeName); + SubGraph addKeySubGraph(String attributeName) + throws CannotContainSubGraphException; - SubGraph addKeySubGraph(String attributeName, Class type); + SubGraph addKeySubGraph(String attributeName, Class type) + throws CannotContainSubGraphException; - SubGraph addKeySubGraph(MapPersistentAttribute attribute, ManagedDomainType type); + SubGraph addKeySubGraph(MapPersistentAttribute attribute, ManagedDomainType type) + throws CannotContainSubGraphException; @Override default SubGraph addTreatedSubgraph(Attribute attribute, Class type) { @@ -219,11 +228,11 @@ default SubGraph addPluralSubgraph(PluralAttribute at @Override @Deprecated(forRemoval = true) default SubGraph addKeySubgraph(Attribute attribute) { - throw new UnsupportedOperationException("This operation will be removed in JPA 4"); + throw new UnsupportedOperationException( "This operation will be removed in JPA 4" ); } @Override @Deprecated(forRemoval = true) default SubGraph addKeySubgraph(Attribute attribute, Class type) { - throw new UnsupportedOperationException("This operation will be removed in JPA 4"); + throw new UnsupportedOperationException( "This operation will be removed in JPA 4" ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java index 9bf8dc55134e..9f27b280896d 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java @@ -11,8 +11,10 @@ import jakarta.persistence.metamodel.MapAttribute; import jakarta.persistence.metamodel.PluralAttribute; +import jakarta.persistence.metamodel.Type; import org.hibernate.AssertionFailure; import org.hibernate.graph.CannotBecomeEntityGraphException; +import org.hibernate.graph.CannotContainSubGraphException; import org.hibernate.graph.RootGraph; import org.hibernate.graph.SubGraph; import org.hibernate.graph.spi.AttributeNodeImplementor; @@ -40,7 +42,7 @@ public abstract class AbstractGraph extends AbstractGraphNode implements GraphImplementor { private final ManagedDomainType managedType; - private final Map, SubGraphImplementor> subgraphs = new HashMap<>(1); + private Map, SubGraphImplementor> treatedSubgraphs; private Map, AttributeNodeImplementor> attributeNodes; public AbstractGraph(ManagedDomainType managedType, boolean mutable) { @@ -48,10 +50,14 @@ public AbstractGraph(ManagedDomainType managedType, boolean mutable) { this.managedType = managedType; } - protected AbstractGraph(ManagedDomainType managedType, GraphImplementor graph, boolean mutable) { - this( managedType, mutable ); - attributeNodes = new HashMap<>( graph.getAttributeNodesByAttribute().size() ); - mergeInternal( graph, mutable ); + protected AbstractGraph(ManagedDomainType managedType, GraphImplementor graph, boolean mutable) { + super( mutable ); + this.managedType = managedType; + var attributeNodesByAttribute = graph.getNodes(); + var subGraphMap = graph.getSubGraphs(); + attributeNodes = attributeNodesByAttribute.isEmpty() ? null : new HashMap<>( attributeNodesByAttribute.size() ); + treatedSubgraphs = subGraphMap.isEmpty() ? null : new HashMap<>( subGraphMap.size() ); + mergeInternal( graph ); } protected AbstractGraph(GraphImplementor graph, boolean mutable) { @@ -63,6 +69,36 @@ public final ManagedDomainType getGraphedType() { return managedType; } + @SuppressWarnings("unchecked") + private SubGraphImplementor getTreatedSubgraph(Class javaType) { + return treatedSubgraphs == null ? null : (SubGraphImplementor) treatedSubgraphs.get( javaType ); + } + + @SuppressWarnings("unchecked") + private AttributeNodeImplementor getNode(PersistentAttribute attribute) { + return attributeNodes == null ? null : (AttributeNodeImplementor) attributeNodes.get( attribute ); + } + + private SubGraphImplementor getTreatedSubgraphForPut(Class javaType) { + if ( treatedSubgraphs == null ) { + treatedSubgraphs = new HashMap<>(1); + return null; + } + else { + return getTreatedSubgraph( javaType ); + } + } + + private AttributeNodeImplementor getNodeForPut(PersistentAttribute attribute) { + if ( attributeNodes == null ) { + attributeNodes = new HashMap<>(); + return null; + } + else { + return getNode( attribute ); + } + } + @Override @Deprecated(forRemoval = true) public RootGraphImplementor makeRootGraph(String name, boolean mutable) { if ( getGraphedType() instanceof EntityDomainType ) { @@ -76,64 +112,55 @@ public RootGraphImplementor makeRootGraph(String name, boolean mutable) { } @Override - public void merge(GraphImplementor graph) { - merge( graph, true ); + public void merge(GraphImplementor graph) { + if ( graph != null ) { + verifyMutability(); + mergeInternal( graph ); + } } @Override - public void merge(GraphImplementor graph, boolean mutable) { - if ( graph != null ) { - verifyMutability(); - mergeInternal( graph, mutable ); + public void mergeInternal(GraphImplementor graph) { + // skip verifyMutability() + graph.getNodes().forEach( this::mergeNode ); + graph.getSubGraphs().values().forEach( this::mergeGraph ); + } + + private void mergeNode(PersistentAttribute attribute, AttributeNodeImplementor node) { + final AttributeNodeImplementor existingNode = getNodeForPut( attribute ); + if ( existingNode == null ) { + attributeNodes.put( attribute, node.makeCopy( isMutable() ) ); + } + else { + // keep the local one, but merge in the incoming one + mergeNode( node, existingNode ); } } - private void mergeInternal(GraphImplementor graph, boolean mutable) { - graph.getAttributeNodesByAttribute().forEach( (attribute, node) -> { - final AttributeNodeImplementor existingNode = findAttributeNode( attribute ); - if ( existingNode != null ) { - // keep the local one, but merge in the incoming one - mergeNode( node, existingNode, mutable ); - } - else { - addAttributeNode( attribute, node.makeCopy( mutable ), mutable ); - } - } ); - graph.getSubGraphMap().forEach( (type, subgraph) -> { - final SubGraphImplementor existing = subgraphs.get( type ); - if ( existing != null ) { - existing.merge( (SubGraphImplementor) subgraph, mutable ); - } - else { - subgraphs.put( type, subgraph.makeCopy( mutable ) ); - } - } ); + private void mergeGraph(SubGraphImplementor subgraph) { + final Class javaType = subgraph.getClassType(); + final SubGraphImplementor existing = getTreatedSubgraphForPut( javaType ); + if ( existing == null ) { + treatedSubgraphs.put( javaType, subgraph.makeCopy( isMutable() ) ); + } + else { + // even if immutable, we need to merge here + existing.mergeInternal( subgraph ); + } } private static void mergeNode( - AttributeNodeImplementor node, AttributeNodeImplementor existingNode, boolean mutable) { + AttributeNodeImplementor node, AttributeNodeImplementor existingNode) { if ( existingNode.getAttributeDescriptor() == node.getAttributeDescriptor() ) { @SuppressWarnings("unchecked") // safe, we just checked final AttributeNodeImplementor castNode = (AttributeNodeImplementor) node; - existingNode.merge( castNode, mutable ); + existingNode.merge( castNode ); } else { throw new AssertionFailure( "Attributes should have been identical" ); } } - private void addAttributeNode( - PersistentAttribute attribute, AttributeNodeImplementor node, boolean mutable) { - final AttributeNodeImplementor attributeNode = getNodeForPut( node.getAttributeDescriptor() ); - if ( attributeNode == null ) { - attributeNodes.put( attribute, node ); - } - else { - // we assume the subgraph has been properly copied if needed - node.merge( attributeNode, mutable ); - } - } - @Override public List> getAttributeNodeList() { return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() ); @@ -145,8 +172,8 @@ public AttributeNodeImplementor findAttributeNode(String attributeName) @SuppressWarnings("unchecked") // The JPA API is unsafe by nature final PersistentAttribute persistentAttribute = (PersistentAttribute) attribute; final AttributeNodeImplementor node = attribute == null ? null : findAttributeNode( persistentAttribute ); - if ( node == null ) { - for ( SubGraphImplementor subgraph : subgraphs.values() ) { + if ( node == null && treatedSubgraphs != null ) { + for ( SubGraphImplementor subgraph : treatedSubgraphs.values() ) { final AttributeNodeImplementor subgraphNode = subgraph.findAttributeNode( attributeName ); if ( subgraphNode != null ) { return subgraphNode; @@ -161,7 +188,7 @@ public AttributeNodeImplementor findAttributeNode(String attributeName) @Override public AttributeNodeImplementor findAttributeNode(PersistentAttribute attribute) { - return attributeNodes == null ? null : getNode( attribute ); + return getNode( attribute ); } @Override @@ -170,7 +197,7 @@ public List> getAttributeNodes() { } @Override - public Map, AttributeNodeImplementor> getAttributeNodesByAttribute() { + public Map, AttributeNodeImplementor> getNodes() { return attributeNodes == null ? emptyMap() : unmodifiableMap( attributeNodes ); } @@ -205,16 +232,19 @@ public final void addAttributeNodes(Attribute... attributes) { @Override public void removeAttributeNode(String attributeName) { + verifyMutability(); attributeNodes.remove( managedType.findAttribute( attributeName ) ); } @Override public void removeAttributeNode(Attribute attribute) { + verifyMutability(); attributeNodes.remove( (PersistentAttribute) attribute ); } @Override public void removeAttributeNodes(Attribute.PersistentAttributeType nodeType) { + verifyMutability(); attributeNodes.keySet().removeIf( entry -> entry.getPersistentAttributeType() == nodeType ); } @@ -223,7 +253,7 @@ public AttributeNodeImplementor findOrCreateAttributeNode(PersistentAtt verifyMutability(); final AttributeNodeImplementor node = getNodeForPut( attribute ); if ( node == null ) { - final AttributeNodeImpl newAttrNode = new AttributeNodeImpl<>( attribute, isMutable() ); + final AttributeNodeImplementor newAttrNode = new AttributeNodeImpl<>( attribute, isMutable() ); attributeNodes.put( attribute, newAttrNode ); return newAttrNode; } @@ -254,21 +284,6 @@ public AttributeNodeImplementor findOrCreateAttributeNode(String attrib : attribute; } - private AttributeNodeImplementor getNodeForPut(PersistentAttribute attribute) { - if ( attributeNodes == null ) { - attributeNodes = new HashMap<>(); - return null; - } - else { - return getNode( attribute ); - } - } - - @SuppressWarnings("unchecked") - private AttributeNodeImplementor getNode(PersistentAttribute attribute) { - return (AttributeNodeImplementor) attributeNodes.get( attribute ); - } - @Override @SuppressWarnings("unchecked") // The API is unsafe by nature public SubGraphImplementor addSubGraph(String attributeName) { @@ -341,12 +356,12 @@ public SubGraphImplementor addElementSubgraph(String attributeName) { @Override public SubGraphImplementor addElementSubgraph(PluralAttribute attribute) { return findOrCreateAttributeNode( attribute.getName() ) - .makeSubGraph( (ManagedDomainType) attribute.getElementType() ); + .makeSubGraph( asManagedType( attribute.getElementType() ) ); } @Override public SubGraphImplementor addElementSubgraph(String attributeName, Class type) { - return findOrCreateAttributeNode( attributeName ).makeSubGraph( type); + return findOrCreateAttributeNode( attributeName ).makeSubGraph( type ); } @Override @@ -358,16 +373,17 @@ public SubGraphImplementor addTreatedElementSubgraph( @Override public SubGraphImplementor addTreatedSubGraph(ManagedDomainType type) { + verifyMutability(); if ( getGraphedType().equals( type ) ) { //noinspection unchecked return (SubGraphImplementor) this; } else { final Class javaType = type.getJavaType(); - final SubGraphImplementor castSubgraph = subgraph( javaType ); + final SubGraphImplementor castSubgraph = getTreatedSubgraphForPut( javaType ); if ( castSubgraph == null ) { final SubGraphImpl subgraph = new SubGraphImpl<>( type, true ); - subgraphs.put( javaType, subgraph ); + treatedSubgraphs.put( javaType, subgraph ); return subgraph; } else { @@ -376,25 +392,22 @@ public SubGraphImplementor addTreatedSubGraph(ManagedDomainType } } - private SubGraphImplementor subgraph(Class javaType) { - final SubGraphImplementor existing = subgraphs.get( javaType ); - if ( existing != null ) { - @SuppressWarnings("unchecked") - final SubGraphImplementor castSubgraph = (SubGraphImplementor) existing; - return castSubgraph; - } - else { - return null; - } - } - @Override public SubGraphImplementor addTreatedSubGraph(Class type) { return addTreatedSubGraph( getGraphedType().getMetamodel().managedType( type ) ); } @Override - public Map, SubGraphImplementor> getSubGraphMap() { - return subgraphs; + public Map, SubGraphImplementor> getSubGraphs() { + return treatedSubgraphs == null ? emptyMap() : unmodifiableMap( treatedSubgraphs ); + } + + static ManagedDomainType asManagedType(Type domainType) { + if ( domainType instanceof ManagedDomainType managedDomainType ) { + return managedDomainType; + } + else { + throw new CannotContainSubGraphException( "Not a managed domain type: " + domainType.getJavaType().getName() ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java index 6784c30cc8b4..f4b297a190e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java @@ -4,7 +4,7 @@ */ package org.hibernate.graph.internal; -import jakarta.persistence.Subgraph; +import org.hibernate.graph.CannotContainSubGraphException; import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.model.domain.DomainType; @@ -22,28 +22,24 @@ * * @author Steve Ebersole */ -public class AttributeNodeImpl +public class AttributeNodeImpl extends AbstractGraphNode implements AttributeNodeImplementor { private final PersistentAttribute attribute; - private SubGraphImplementor subgraph; - private SubGraphImplementor keySubgraph; + private SubGraphImplementor valueSubgraph; + private SubGraphImplementor keySubgraph; public AttributeNodeImpl(PersistentAttribute attribute, boolean mutable) { - this(attribute, mutable, null, null); + super( mutable ); + this.attribute = attribute; } - /** - * Intended only for use from making a copy - */ - private AttributeNodeImpl( - PersistentAttribute attribute, boolean mutable, - SubGraphImplementor subgraph, SubGraphImplementor keySubgraph) { + private AttributeNodeImpl(AttributeNodeImpl that, boolean mutable) { super( mutable ); - this.attribute = attribute; - this.subgraph = subgraph; - this.keySubgraph = keySubgraph; + attribute = that.attribute; + valueSubgraph = that.valueSubgraph == null ? null : that.valueSubgraph.makeCopy( mutable ); + keySubgraph = that.keySubgraph == null ? null : that.keySubgraph.makeCopy( mutable ); } @Override @@ -57,201 +53,161 @@ public PersistentAttribute getAttributeDescriptor() { } @Override - public SubGraphImplementor getSubGraph() { - return subgraph; + public SubGraphImplementor getSubGraph() { + return valueSubgraph; } @Override - public SubGraphImplementor getKeySubGraph() { + public SubGraphImplementor getKeySubGraph() { return keySubgraph; } - private SubGraphImplementor subgraph(ManagedDomainType valueType) { - if ( subgraph == null ) { - final SubGraphImplementor graph = new SubGraphImpl<>( valueType, true ); - subgraph = graph; + @Override + public SubGraphImplementor makeSubGraph() { + verifyMutability(); + if ( valueSubgraph == null ) { + final ManagedDomainType managedType = asManagedType( attribute.getValueGraphType() ); + @SuppressWarnings("unchecked") + final ManagedDomainType valueGraphType = (ManagedDomainType) managedType; + final SubGraphImplementor graph = new SubGraphImpl<>( valueGraphType, true ); + valueSubgraph = graph; return graph; } else { - //noinspection unchecked - return (SubGraphImplementor) subgraph; + return valueSubgraph; } } - @Override - public SubGraphImplementor makeSubGraph() { - verifyMutability(); - return subgraph( (ManagedDomainType) attribute.getValueGraphType() ); - } - @Override public SubGraphImplementor makeSubGraph(Class subtype) { - verifyMutability(); - final DomainType type = attribute.getValueGraphType(); - if ( !type.getBindableJavaType().isAssignableFrom( subtype ) ) { + final ManagedDomainType managedType = asManagedType( attribute.getValueGraphType() ); + if ( !managedType.getBindableJavaType().isAssignableFrom( subtype ) ) { throw new IllegalArgumentException( "Not a subtype: " + subtype.getName() ); } @SuppressWarnings("unchecked") - final ManagedDomainType valueType = (ManagedDomainType) type; - SubGraphImplementor subgraph = subgraph( valueType ); - if ( type.getBindableJavaType() == subtype ) { - //noinspection unchecked - return (SubGraphImplementor) subgraph; - } - else { - return subgraph.addTreatedSubGraph( subtype ); - } + final Class castSuptype = (Class) subtype; + final SubGraphImplementor result = makeSubGraph().addTreatedSubGraph( castSuptype ); + //noinspection unchecked + return (SubGraphImplementor) result; } @Override public SubGraphImplementor makeSubGraph(ManagedDomainType subtype) { - verifyMutability(); - final DomainType type = attribute.getValueGraphType(); + final ManagedDomainType managedType = asManagedType( attribute.getValueGraphType() ); final Class javaType = subtype.getBindableJavaType(); - if ( !type.getBindableJavaType().isAssignableFrom( javaType ) ) { + if ( !managedType.getBindableJavaType().isAssignableFrom( javaType ) ) { throw new IllegalArgumentException( "Not a subtype: " + javaType.getName() ); } @SuppressWarnings("unchecked") - final ManagedDomainType valueType = (ManagedDomainType) type; - SubGraphImplementor subgraph = subgraph( valueType ); - if ( type.getBindableJavaType() == javaType ) { - //noinspection unchecked - return (SubGraphImplementor) subgraph; - } - else { - return subgraph.addTreatedSubGraph( subtype ); - } + final ManagedDomainType castType = (ManagedDomainType) subtype; + final SubGraphImplementor result = makeSubGraph().addTreatedSubGraph( castType ); + //noinspection unchecked + return (SubGraphImplementor) result; } - private SubGraphImplementor keySubgraph(ManagedDomainType keyType) { + @Override + public SubGraphImplementor makeKeySubGraph() { + verifyMutability(); if ( keySubgraph == null ) { - final SubGraphImplementor graph = new SubGraphImpl<>( keyType, true ); + final ManagedDomainType managedType = asManagedType( attribute.getKeyGraphType() ); + @SuppressWarnings("unchecked") + final ManagedDomainType keyGraphType = (ManagedDomainType) managedType; + final SubGraphImplementor graph = new SubGraphImpl<>( keyGraphType, true ); keySubgraph = graph; return graph; } else { - //noinspection unchecked - return (SubGraphImplementor) keySubgraph; + return keySubgraph; } } - @Override - public SubGraphImplementor makeKeySubGraph() { - verifyMutability(); - return keySubgraph( (ManagedDomainType) attribute.getKeyGraphType() ); - } - @Override public SubGraphImplementor makeKeySubGraph(Class subtype) { - verifyMutability(); - final DomainType type = attribute.getKeyGraphType(); + final ManagedDomainType type = asManagedType( attribute.getKeyGraphType() ); if ( !type.getBindableJavaType().isAssignableFrom( subtype ) ) { throw new IllegalArgumentException( "Not a key subtype: " + subtype.getName() ); } @SuppressWarnings("unchecked") - final ManagedDomainType keyType = (ManagedDomainType) type; - final SubGraphImplementor keySubgraph = keySubgraph( keyType ); - if ( type.getBindableJavaType() == subtype ) { - //noinspection unchecked - return (SubGraphImplementor) keySubgraph; - } - else { - return keySubgraph.addTreatedSubGraph( subtype ); - } + final Class castType = (Class) subtype; + final SubGraphImplementor result = makeKeySubGraph().addTreatedSubGraph( castType ); + //noinspection unchecked + return (SubGraphImplementor) result; } @Override public SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype) { - verifyMutability(); - final DomainType type = attribute.getKeyGraphType(); + final ManagedDomainType type = asManagedType( attribute.getKeyGraphType() ); final Class javaType = subtype.getBindableJavaType(); if ( !type.getBindableJavaType().isAssignableFrom( javaType ) ) { throw new IllegalArgumentException( "Not a key subtype: " + javaType.getName() ); } @SuppressWarnings("unchecked") - final ManagedDomainType keyType = (ManagedDomainType) type; - final SubGraphImplementor keySubgraph = keySubgraph( keyType ); - if ( type.getBindableJavaType() == javaType ) { - //noinspection unchecked - return (SubGraphImplementor) keySubgraph; + final ManagedDomainType castType = (ManagedDomainType) subtype; + final SubGraphImplementor result = makeKeySubGraph().addTreatedSubGraph( castType ); + //noinspection unchecked + return (SubGraphImplementor) result; + } + + private static ManagedDomainType asManagedType(DomainType domainType) { + if ( domainType instanceof ManagedDomainType managedDomainType ) { + return managedDomainType; } else { - return keySubgraph.addTreatedSubGraph( subtype ); + throw new CannotContainSubGraphException( "Not a managed domain type: " + domainType.getTypeName() ); } } @Override public AttributeNodeImplementor makeCopy(boolean mutable) { - return new AttributeNodeImpl<>( this.attribute, mutable, - subgraph == null ? null : subgraph.makeCopy( mutable ), - keySubgraph == null ? null : keySubgraph.makeCopy( mutable ) ); + return !mutable && !isMutable() ? this : new AttributeNodeImpl<>( this, mutable ); } @Override - public void merge(AttributeNodeImplementor other, boolean mutable) { - final SubGraphImplementor otherSubgraph = other.getSubGraph(); - if ( otherSubgraph != null ) { - if ( subgraph == null ) { - subgraph = otherSubgraph.makeCopy( mutable ); + public void merge(AttributeNodeImplementor other) { + assert other.isMutable() == isMutable(); + assert other.getAttributeDescriptor() == attribute; + final AttributeNodeImpl that = (AttributeNodeImpl) other; + final SubGraphImplementor otherValueSubgraph = that.valueSubgraph; + if ( otherValueSubgraph != null ) { + if ( valueSubgraph == null ) { + valueSubgraph = otherValueSubgraph.makeCopy( isMutable() ); } else { - subgraph.merge( (SubGraphImplementor) otherSubgraph, mutable ); + // even if immutable, we need to merge here + valueSubgraph.mergeInternal( otherValueSubgraph ); } } - final SubGraphImplementor otherKeySubgraph = other.getKeySubGraph(); + final SubGraphImplementor otherKeySubgraph = that.keySubgraph; if ( otherKeySubgraph != null ) { if ( keySubgraph == null ) { - keySubgraph = otherKeySubgraph.makeCopy( mutable ); + keySubgraph = otherKeySubgraph.makeCopy( isMutable() ); } else { - keySubgraph.merge( (SubGraphImplementor) otherKeySubgraph, mutable ); + // even if immutable, we need to merge here + keySubgraph.mergeInternal( otherKeySubgraph ); } } } @Override - public Map, SubGraphImplementor> getSubGraphMap() { - if ( subgraph == null ) { - return emptyMap(); - } - else { - final HashMap, SubGraphImplementor> map = new HashMap<>( subgraph.getSubGraphMap() ); - map.put( attribute.getValueGraphType().getBindableJavaType(), subgraph ); - return map; - } - } - - @Override - public Map, SubGraphImplementor> getKeySubGraphMap() { - if ( keySubgraph == null ) { - return emptyMap(); - } - else { - final HashMap, SubGraphImplementor> map = new HashMap<>( keySubgraph.getSubGraphMap() ); - map.put( attribute.getKeyGraphType().getJavaType(), keySubgraph ); - return map; - } - } - - @Override - public @SuppressWarnings("rawtypes") Map getSubgraphs() { - if ( subgraph == null ) { + public Map, SubGraphImplementor> getSubGraphs() { + if ( valueSubgraph == null ) { return emptyMap(); } else { - final HashMap map = new HashMap<>( subgraph.getSubGraphMap() ); - map.put( attribute.getValueGraphType().getBindableJavaType(), subgraph ); + final HashMap, SubGraphImplementor> map = new HashMap<>( valueSubgraph.getSubGraphs() ); + map.put( attribute.getValueGraphType().getBindableJavaType(), valueSubgraph ); return map; } } @Override - public @SuppressWarnings("rawtypes") Map getKeySubgraphs() { + public Map, SubGraphImplementor> getKeySubGraphs() { if ( keySubgraph == null ) { return emptyMap(); } else { - final HashMap map = new HashMap<>( keySubgraph.getSubGraphMap() ); + final HashMap, SubGraphImplementor> map = new HashMap<>( keySubgraph.getSubGraphs() ); map.put( attribute.getKeyGraphType().getJavaType(), keySubgraph ); return map; } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java index 1e2f24537bbc..339ecbe359de 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java @@ -24,11 +24,11 @@ public SubGraphImpl(AbstractGraph original, boolean mutable) { @Override public SubGraphImplementor makeCopy(boolean mutable) { - return new SubGraphImpl<>( this, mutable ); + return !mutable && !isMutable() ? this : new SubGraphImpl<>( this, mutable ); } @Override @Deprecated(forRemoval = true) public SubGraphImplementor makeSubGraph(boolean mutable) { - return !mutable && !isMutable() ? this : makeCopy( true ); + return makeCopy( mutable ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java index 1a1d66b7285a..e3119af3db2a 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java @@ -5,11 +5,11 @@ package org.hibernate.graph.spi; import org.hibernate.graph.AttributeNode; -import org.hibernate.graph.SubGraph; import org.hibernate.metamodel.model.domain.ManagedDomainType; import java.util.Map; + /** * Integration version of the {@link AttributeNode} contract * @@ -39,23 +39,15 @@ public interface AttributeNodeImplementor extends AttributeNode, GraphNode @Override SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype); - void merge(AttributeNodeImplementor other, boolean mutable); + void merge(AttributeNodeImplementor other); SubGraphImplementor getSubGraph(); SubGraphImplementor getKeySubGraph(); - Map, SubGraphImplementor> getSubGraphMap(); - - Map, SubGraphImplementor> getKeySubGraphMap(); - @Override - default Map, ? extends SubGraph> getSubGraphs() { - return getSubGraphMap(); - } + Map, SubGraphImplementor> getSubGraphs(); @Override - default Map, ? extends SubGraph> getKeySubGraphs() { - return getKeySubGraphMap(); - } + Map, SubGraphImplementor> getKeySubGraphs(); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java index 81afe4cf5860..90fc6e15e3db 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; +import org.hibernate.Internal; import org.hibernate.graph.CannotBecomeEntityGraphException; import org.hibernate.graph.Graph; import org.hibernate.metamodel.model.domain.ManagedDomainType; @@ -24,9 +25,10 @@ */ public interface GraphImplementor extends Graph, GraphNodeImplementor { - void merge(GraphImplementor other); + void merge(GraphImplementor other); - void merge(GraphImplementor other, boolean mutable); + @Internal + void mergeInternal(GraphImplementor graph); @Override @Deprecated(forRemoval = true) RootGraphImplementor makeRootGraph(String name, boolean mutable) @@ -41,7 +43,7 @@ RootGraphImplementor makeRootGraph(String name, boolean mutable) @Override List> getAttributeNodeList(); - Map, AttributeNodeImplementor> getAttributeNodesByAttribute(); + Map, AttributeNodeImplementor> getNodes(); @Override AttributeNodeImplementor findAttributeNode(String attributeName); @@ -89,5 +91,5 @@ RootGraphImplementor makeRootGraph(String name, boolean mutable) SubGraphImplementor addTreatedSubGraph(ManagedDomainType type); - Map, SubGraphImplementor> getSubGraphMap(); + Map, SubGraphImplementor> getSubGraphs(); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/SubGraphImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/SubGraphImplementor.java index 9f7fe8ab844c..12dc432efea2 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/SubGraphImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/SubGraphImplementor.java @@ -25,5 +25,4 @@ public interface SubGraphImplementor extends SubGraph, GraphImplementor @Override @Deprecated(forRemoval = true) RootGraphImplementor makeRootGraph(String name, boolean mutable) throws CannotBecomeEntityGraphException; - } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java index ba35ceecfbd9..e2f454738e5c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java @@ -26,11 +26,11 @@ public static boolean containsCollectionFetches(QueryOptions queryOptions) { } private static boolean containsCollectionFetches(GraphImplementor graph) { - for ( AttributeNodeImplementor node : graph.getAttributeNodeList() ) { + for ( AttributeNodeImplementor node : graph.getNodes().values() ) { if ( node.getAttributeDescriptor().isCollection() ) { return true; } - for ( SubGraphImplementor subgraph : node.getSubGraphMap().values() ) { + for ( SubGraphImplementor subgraph : node.getSubGraphs().values() ) { if ( containsCollectionFetches( subgraph ) ) { return true; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java index 312a84a8ac3f..b4831f05590f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java @@ -67,17 +67,17 @@ public TraversalResult traverse(FetchParent fetchParent, Fetchable fetchable, bo final Class subgraphMapKey; if ( fetchable instanceof PluralAttributeMapping pluralAttributeMapping ) { if ( exploreKeySubgraph ) { - subgraphMap = attributeNode.getKeySubGraphMap(); + subgraphMap = attributeNode.getKeySubGraphs(); subgraphMapKey = getEntityCollectionPartJavaClass( pluralAttributeMapping.getIndexDescriptor() ); } else { - subgraphMap = attributeNode.getSubGraphMap(); + subgraphMap = attributeNode.getSubGraphs(); subgraphMapKey = getEntityCollectionPartJavaClass( pluralAttributeMapping.getElementDescriptor() ); } } else { assert !exploreKeySubgraph; - subgraphMap = attributeNode.getSubGraphMap(); + subgraphMap = attributeNode.getSubGraphs(); subgraphMapKey = fetchable.getJavaType().getJavaTypeClass(); } if ( subgraphMap != null && subgraphMapKey != null ) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java index 7758b090ece2..0b32ffea7c31 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java @@ -186,7 +186,7 @@ public void testLinkSubtypeParsing() { assertNullOrEmpty( linkToOneNode.getKeySubgraphs() ); - final SubGraphImplementor subgraph = linkToOneNode.getSubGraphMap().get( GraphParsingTestSubEntity.class ); + final SubGraphImplementor subgraph = linkToOneNode.getSubGraphs().get( GraphParsingTestSubEntity.class ); assertNotNull( subgraph ); assertBasicAttributes( subgraph, "sub" ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/graph/EntityGraphsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/graph/EntityGraphsTest.java index db1bbd8b8e16..7a684534b6d5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/graph/EntityGraphsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/graph/EntityGraphsTest.java @@ -86,7 +86,6 @@ public void testDifferentLinksEqual2() { } @Test - @Ignore("Cannot run due to Hibernate bug: https://hibernate.atlassian.net/browse/HHH-10378") public void testDifferentLinksEqual3() { EntityGraph a = parseGraph( "linkToOne(name), linkToOne:MockSubentity(description)" ); EntityGraph b = parseGraph( "linkToOne(name, description)" ); From e168efad40a7d1b2aecc74a7ed19e871b832de25 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Thu, 2 Jan 2025 13:56:15 +0100 Subject: [PATCH 9/9] Graphpocalypse: major revision/refactoring of EntityGraph support - improve error nessages and add toStrings() --- .../graph/internal/AbstractGraph.java | 26 +++++-- .../graph/internal/AttributeNodeImpl.java | 69 ++++++++++++------- 2 files changed, 65 insertions(+), 30 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java index 9f27b280896d..8a19c27f6b59 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java @@ -105,9 +105,8 @@ public RootGraphImplementor makeRootGraph(String name, boolean mutable) { return new RootGraphImpl<>( name, this, mutable); } else { - throw new CannotBecomeEntityGraphException( - "Cannot transform Graph to RootGraph because '" + getGraphedType() + "' is not an entity type" - ); + throw new CannotBecomeEntityGraphException( "Graph cannot be a root graph because '" + + getGraphedType() + "' is not an entity type" ); } } @@ -253,7 +252,7 @@ public AttributeNodeImplementor findOrCreateAttributeNode(PersistentAtt verifyMutability(); final AttributeNodeImplementor node = getNodeForPut( attribute ); if ( node == null ) { - final AttributeNodeImplementor newAttrNode = new AttributeNodeImpl<>( attribute, isMutable() ); + final AttributeNodeImplementor newAttrNode = AttributeNodeImpl.create( attribute, isMutable() ); attributeNodes.put( attribute, newAttrNode ); return newAttrNode; } @@ -407,7 +406,24 @@ static ManagedDomainType asManagedType(Type domainType) { return managedDomainType; } else { - throw new CannotContainSubGraphException( "Not a managed domain type: " + domainType.getJavaType().getName() ); + throw new CannotContainSubGraphException( "Type '" + domainType.getJavaType().getName() + + "' is not a managed type" ); } } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder( "Graph[" ).append( managedType.getTypeName() ); + if ( attributeNodes != null ) { + builder.append( ", nodes=" ) + .append( attributeNodes.values().stream() + .map( node -> node.getAttributeDescriptor().getName() ).toList() ); + } + if ( treatedSubgraphs != null ) { + builder.append( ", subgraphs=" ) + .append( treatedSubgraphs.values().stream() + .map( subgraph -> subgraph.getGraphedType().getTypeName() ).toList() ); + } + return builder.append( ']' ).toString(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java index f4b297a190e6..ddc756218cc0 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java @@ -10,6 +10,7 @@ import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; +import org.hibernate.metamodel.model.domain.SimpleDomainType; import java.util.HashMap; import java.util.Map; @@ -26,18 +27,30 @@ public class AttributeNodeImpl extends AbstractGraphNode implements AttributeNodeImplementor { private final PersistentAttribute attribute; + private final DomainType valueGraphType; + private final SimpleDomainType keyGraphType; private SubGraphImplementor valueSubgraph; private SubGraphImplementor keySubgraph; - public AttributeNodeImpl(PersistentAttribute attribute, boolean mutable) { + static AttributeNodeImpl create(PersistentAttribute attribute, boolean mutable) { + return new AttributeNodeImpl<>( attribute, mutable, attribute.getValueGraphType(), attribute.getKeyGraphType() ); + } + + private AttributeNodeImpl( + PersistentAttribute attribute, boolean mutable, + DomainType valueGraphType, SimpleDomainType keyGraphType) { super( mutable ); this.attribute = attribute; + this.valueGraphType = valueGraphType; + this.keyGraphType = keyGraphType; } private AttributeNodeImpl(AttributeNodeImpl that, boolean mutable) { super( mutable ); attribute = that.attribute; + valueGraphType = that.valueGraphType; + keyGraphType = that.keyGraphType; valueSubgraph = that.valueSubgraph == null ? null : that.valueSubgraph.makeCopy( mutable ); keySubgraph = that.keySubgraph == null ? null : that.keySubgraph.makeCopy( mutable ); } @@ -66,21 +79,14 @@ public SubGraphImplementor getKeySubGraph() { public SubGraphImplementor makeSubGraph() { verifyMutability(); if ( valueSubgraph == null ) { - final ManagedDomainType managedType = asManagedType( attribute.getValueGraphType() ); - @SuppressWarnings("unchecked") - final ManagedDomainType valueGraphType = (ManagedDomainType) managedType; - final SubGraphImplementor graph = new SubGraphImpl<>( valueGraphType, true ); - valueSubgraph = graph; - return graph; - } - else { - return valueSubgraph; + valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true ); } + return valueSubgraph; } @Override public SubGraphImplementor makeSubGraph(Class subtype) { - final ManagedDomainType managedType = asManagedType( attribute.getValueGraphType() ); + final ManagedDomainType managedType = asManagedType( valueGraphType ); if ( !managedType.getBindableJavaType().isAssignableFrom( subtype ) ) { throw new IllegalArgumentException( "Not a subtype: " + subtype.getName() ); } @@ -93,7 +99,7 @@ public SubGraphImplementor makeSubGraph(Class subtype) { @Override public SubGraphImplementor makeSubGraph(ManagedDomainType subtype) { - final ManagedDomainType managedType = asManagedType( attribute.getValueGraphType() ); + final ManagedDomainType managedType = asManagedType( valueGraphType ); final Class javaType = subtype.getBindableJavaType(); if ( !managedType.getBindableJavaType().isAssignableFrom( javaType ) ) { throw new IllegalArgumentException( "Not a subtype: " + javaType.getName() ); @@ -108,22 +114,17 @@ public SubGraphImplementor makeSubGraph(ManagedDomainType subtype) { @Override public SubGraphImplementor makeKeySubGraph() { verifyMutability(); + checkMap(); if ( keySubgraph == null ) { - final ManagedDomainType managedType = asManagedType( attribute.getKeyGraphType() ); - @SuppressWarnings("unchecked") - final ManagedDomainType keyGraphType = (ManagedDomainType) managedType; - final SubGraphImplementor graph = new SubGraphImpl<>( keyGraphType, true ); - keySubgraph = graph; - return graph; - } - else { - return keySubgraph; + keySubgraph = new SubGraphImpl<>( asManagedType( keyGraphType ), true ); } + return keySubgraph; } @Override public SubGraphImplementor makeKeySubGraph(Class subtype) { - final ManagedDomainType type = asManagedType( attribute.getKeyGraphType() ); + checkMap(); + final ManagedDomainType type = asManagedType( keyGraphType ); if ( !type.getBindableJavaType().isAssignableFrom( subtype ) ) { throw new IllegalArgumentException( "Not a key subtype: " + subtype.getName() ); } @@ -136,7 +137,8 @@ public SubGraphImplementor makeKeySubGraph(Class subtype) { @Override public SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype) { - final ManagedDomainType type = asManagedType( attribute.getKeyGraphType() ); + checkMap(); + final ManagedDomainType type = asManagedType( keyGraphType ); final Class javaType = subtype.getBindableJavaType(); if ( !type.getBindableJavaType().isAssignableFrom( javaType ) ) { throw new IllegalArgumentException( "Not a key subtype: " + javaType.getName() ); @@ -148,15 +150,32 @@ public SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype) return (SubGraphImplementor) result; } - private static ManagedDomainType asManagedType(DomainType domainType) { + private void checkMap() { + if ( keyGraphType == null ) { + throw new CannotContainSubGraphException( "Attribute '" + description() + "' is not a Map" ); + } + } + + private ManagedDomainType asManagedType(DomainType domainType) { if ( domainType instanceof ManagedDomainType managedDomainType ) { return managedDomainType; } else { - throw new CannotContainSubGraphException( "Not a managed domain type: " + domainType.getTypeName() ); + throw new CannotContainSubGraphException( "Attribute '" + description() + + "' is of type '" + domainType.getTypeName() + + "' which is not a managed type" ); } } + private String description() { + return attribute.getDeclaringType().getTypeName() + "." + attribute.getName(); + } + + @Override + public String toString() { + return "AttributeNode[" + description() + "]"; + } + @Override public AttributeNodeImplementor makeCopy(boolean mutable) { return !mutable && !isMutable() ? this : new AttributeNodeImpl<>( this, mutable );