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 < getSubTypes(); 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..3f8582ef87e7 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,15 @@ */ package org.hibernate.graph; -import java.util.Map; -import jakarta.persistence.Subgraph; +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. * @@ -20,27 +24,26 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr PersistentAttribute getAttributeDescriptor(); - Map, SubGraph> getSubGraphs(); - Map, SubGraph> getKeySubGraphs(); + Map, ? extends SubGraph> getSubGraphs(); + Map, ? extends SubGraph> getKeySubGraphs(); @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default Map getSubgraphs() { - return (Map) getSubGraphs(); + default @SuppressWarnings("rawtypes") Map getSubgraphs() { + return unmodifiableMap( getSubGraphs() ); } @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default Map getKeySubgraphs() { - return (Map) getKeySubGraphs(); + default @SuppressWarnings("rawtypes") Map getKeySubgraphs() { + return unmodifiableMap( getKeySubGraphs() ); } - void addSubGraph(Class subType, SubGraph subGraph); - void addKeySubGraph(Class subType, SubGraph subGraph); + SubGraph makeSubGraph(); + SubGraph makeKeySubGraph(); + + SubGraph makeSubGraph(Class subtype); + SubGraph makeKeySubGraph(Class subtype); - SubGraph makeSubGraph(); - SubGraph makeKeySubGraph(); + 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/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..021b2d5a5a89 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,37 @@ 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 +72,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 +93,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 +113,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 +132,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 +151,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 +169,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 +194,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 +229,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 +241,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 +252,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 +288,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..fc34e1c7686d 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java @@ -7,10 +7,11 @@ 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; +import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; /** * A container for {@link AttributeNode} references. @@ -32,18 +33,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. @@ -58,14 +52,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 +75,62 @@ 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); /** * Find an already existing AttributeNode by corresponding attribute * reference, within this container. + * + * @see #getAttributeNode(Attribute) */ AttributeNode findAttributeNode(PersistentAttribute attribute); - /** - * Get a list of all existing AttributeNodes within this container. - */ - List> getAttributeNodeList(); + @Override + 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. + * + * @see #addAttributeNode(Attribute) */ AttributeNode addAttributeNode(PersistentAttribute attribute); + @Override + default AttributeNode addAttributeNode(Attribute attribute) { + return addAttributeNode( (PersistentAttribute) attribute ); + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // sub graph nodes + // Subgraph nodes + + SubGraph addTreatedSubGraph(Class type); + + SubGraph addTreatedSubGraph(ManagedDomainType type); /** * Create and return a new (mutable) {@link SubGraph} associated with @@ -116,6 +138,7 @@ RootGraph makeRootGraph(String name, boolean mutable) * * @apiNote If no such AttributeNode exists yet, it is created. */ + @Deprecated SubGraph addSubGraph(String attributeName) throws CannotContainSubGraphException; @@ -131,29 +154,85 @@ SubGraph addSubGraph(String attributeName, Class type) SubGraph addSubGraph(PersistentAttribute attribute) throws CannotContainSubGraphException; - SubGraph addSubGraph(PersistentAttribute attribute, Class type) + SubGraph addSubGraph(PersistentAttribute attribute, Class type) throws CannotContainSubGraphException; - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // key sub graph nodes + SubGraph addSubGraph(PersistentAttribute attribute, ManagedDomainType type) + throws CannotContainSubGraphException; + SubGraph addElementSubGraph(PluralPersistentAttribute attribute, Class type) + throws CannotContainSubGraphException; + + SubGraph addElementSubGraph(PluralPersistentAttribute attribute, ManagedDomainType type) + throws CannotContainSubGraphException; + + @Deprecated SubGraph addKeySubGraph(String attributeName) throws CannotContainSubGraphException; + SubGraph addKeySubGraph(String attributeName, Class type) throws CannotContainSubGraphException; - SubGraph addKeySubGraph(PersistentAttribute attribute) - throws CannotContainSubGraphException; - SubGraph addKeySubGraph(PersistentAttribute attribute, Class type) + SubGraph addKeySubGraph(MapPersistentAttribute attribute, ManagedDomainType type) throws CannotContainSubGraphException; + @Override + default SubGraph addTreatedSubgraph(Attribute attribute, Class type) { + return addSubGraph( (PersistentAttribute) attribute ).addTreatedSubGraph( type ); + } @Override - SubGraph addTreatedSubgraph(Attribute attribute, Class type); + default SubGraph addSubgraph(Attribute attribute) { + return addSubGraph( (PersistentAttribute) attribute ); + } @Override - SubGraph addTreatedElementSubgraph(PluralAttribute attribute, Class type); + default SubGraph addSubgraph(Attribute attribute, Class type) { + return addSubGraph( (PersistentAttribute) attribute ).addTreatedSubGraph( type ); + } + + @Override + default SubGraph addSubgraph(String name) { + return addSubGraph( name ); + } @Override - SubGraph addTreatedMapKeySubgraph(MapAttribute attribute, Class type); + default SubGraph addSubgraph(String name, Class type) { + return addSubGraph( name ).addTreatedSubGraph( type ); + } + + @Override + default SubGraph addKeySubgraph(String name) { + return addKeySubGraph( name ); + } + + @Override + default SubGraph addKeySubgraph(String name, Class type) { + return addKeySubGraph( name ).addTreatedSubGraph( 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 @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/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..5a6c250cbaa7 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,25 @@ 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 ); + /** + * @deprecated Planned for removal in JPA 4 + */ + @Override @Deprecated(forRemoval = true) + @SuppressWarnings("unchecked") // The JPA method was defined with an incorrect generic signature + default SubGraph addSubclassSubgraph(Class type) { + return (SubGraph) addTreatedSubgraph( (Class) type ); } @Override - default Subgraph addKeySubgraph(String name, Class type) { - return addKeySubGraph( name, type ); + default SubGraph addTreatedSubgraph(Class type) { + return addTreatedSubGraph( type ); } } 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..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 @@ -8,10 +8,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Consumer; -import org.hibernate.graph.AttributeNode; +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; @@ -19,14 +20,19 @@ 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.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; 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. @@ -34,221 +40,390 @@ * @author Steve Ebersole */ public abstract class AbstractGraph extends AbstractGraphNode implements GraphImplementor { + private final ManagedDomainType managedType; - private Map, AttributeNodeImplementor> attrNodeMap; + private Map, SubGraphImplementor> treatedSubgraphs; + 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) { + 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 ); } - @Override - public ManagedDomainType getGraphedType() { - return managedType; + protected AbstractGraph(GraphImplementor graph, boolean mutable) { + this( graph.getGraphedType(), graph, mutable ); } @Override - 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" - ); + public final ManagedDomainType getGraphedType() { + return managedType; } - @Override @SuppressWarnings("unchecked") - public void merge(GraphImplementor other) { - if ( other == null ) { - return; - } - - for ( AttributeNodeImplementor attributeNode : other.getAttributeNodeImplementors() ) { - final AttributeNodeImplementor localAttributeNode = findAttributeNode( - (PersistentAttribute) attributeNode.getAttributeDescriptor() - ); - if ( localAttributeNode != null ) { - // keep the local one, but merge in the incoming one - localAttributeNode.merge( attributeNode ); - } - else { - addAttributeNode( attributeNode.makeCopy( true ) ); - } - } - + private SubGraphImplementor getTreatedSubgraph(Class javaType) { + return treatedSubgraphs == null ? null : (SubGraphImplementor) treatedSubgraphs.get( javaType ); } - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // AttributeNode handling + @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 ); + } + } - @Override - public AttributeNodeImplementor getAttributeNode(String attributeName) { - if ( attrNodeMap == null ) { + private AttributeNodeImplementor getNodeForPut(PersistentAttribute attribute) { + if ( attributeNodes == null ) { + attributeNodes = new HashMap<>(); return null; } - final PersistentAttribute attribute = managedType.findAttributeInSuperTypes( attributeName ); - //noinspection unchecked - return (AttributeNodeImplementor) attrNodeMap.get( attribute ); + else { + return getNode( attribute ); + } } - @Override - public AttributeNodeImplementor getAttributeNode(Attribute attribute) { - return null; + @Override @Deprecated(forRemoval = true) + public RootGraphImplementor makeRootGraph(String name, boolean mutable) { + if ( getGraphedType() instanceof EntityDomainType ) { + return new RootGraphImpl<>( name, this, mutable); + } + else { + throw new CannotBecomeEntityGraphException( "Graph cannot be a root graph because '" + + getGraphedType() + "' is not an entity type" ); + } } @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(); + mergeInternal( graph ); } } @Override - public List> getAttributeNodeList() { - if ( attrNodeMap == null ) { - return emptyList(); + 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 { - final List> result = new ArrayList<>(); - visitAttributeNodes( result::add ); - return result; + // keep the local one, but merge in the incoming one + mergeNode( node, existingNode ); } } - @Override - public AttributeNodeImplementor addAttributeNode(AttributeNodeImplementor incomingAttributeNode) { - verifyMutability(); - - AttributeNodeImplementor attributeNode = null; - if ( attrNodeMap == null ) { - attrNodeMap = new HashMap<>(); + 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 { - attributeNode = attrNodeMap.get( incomingAttributeNode.getAttributeDescriptor() ); + // even if immutable, we need to merge here + existing.mergeInternal( subgraph ); } + } - if ( attributeNode == null ) { - attributeNode = incomingAttributeNode; - attrNodeMap.put( incomingAttributeNode.getAttributeDescriptor(), attributeNode ); + 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 { - @SuppressWarnings("rawtypes") - final AttributeNodeImplementor attributeNodeFinal = attributeNode; - incomingAttributeNode.visitSubGraphs( - // we assume the subGraph has been properly copied if needed - (subType, subGraph) -> attributeNodeFinal.addSubGraph( subGraph ) - ); + throw new AssertionFailure( "Attributes should have been identical" ); } + } - 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 ); + final PersistentAttribute attribute = findAttributeInSupertypes( 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 && treatedSubgraphs != null ) { + for ( SubGraphImplementor subgraph : treatedSubgraphs.values() ) { + final AttributeNodeImplementor subgraphNode = subgraph.findAttributeNode( attributeName ); + if ( subgraphNode != null ) { + return subgraphNode; + } + } + return null; + } + else { + return node; } - return attribute == null ? null : findAttributeNode( (PersistentAttribute) attribute ); } @Override - @SuppressWarnings("unchecked") public AttributeNodeImplementor findAttributeNode(PersistentAttribute attribute) { - return attrNodeMap == null ? null : (AttributeNodeImplementor) attrNodeMap.get( attribute ); + return 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() ); + public Map, AttributeNodeImplementor> getNodes() { + return attributeNodes == null ? emptyMap() : unmodifiableMap( attributeNodes ); } @Override - public AttributeNodeImplementor addAttributeNode(String attributeName) throws CannotContainSubGraphException { + 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 ); + verifyMutability(); + attributeNodes.remove( managedType.findAttribute( attributeName ) ); } @Override public void removeAttributeNode(Attribute attribute) { - attrNodeMap.remove( (PersistentAttribute) attribute ); + verifyMutability(); + 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) { + verifyMutability(); + attributeNodes.keySet().removeIf( entry -> entry.getPersistentAttributeType() == nodeType ); } @Override - @SuppressWarnings("unchecked") public AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute) { verifyMutability(); + final AttributeNodeImplementor node = getNodeForPut( attribute ); + if ( node == null ) { + final AttributeNodeImplementor newAttrNode = AttributeNodeImpl.create( attribute, isMutable() ); + attributeNodes.put( attribute, newAttrNode ); + return newAttrNode; + } + else { + 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; + } - AttributeNodeImplementor attrNode = null; - if ( attrNodeMap == null ) { - attrNodeMap = new HashMap<>(); + @Override + @SuppressWarnings("unchecked") // The 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( attribute.getJavaType() ); + } + + @Override + public SubGraphImplementor addSubGraph(PersistentAttribute attribute, Class subtype) { + return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype ); + } + + @Override + public SubGraphImplementor addSubGraph(PersistentAttribute attribute, ManagedDomainType subtype) { + return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype ); + } + + @Override + 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 ); + } + + @Override + @SuppressWarnings("unchecked") // The API is unsafe by nature + public SubGraphImplementor addKeySubGraph(String attributeName) { + return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeKeySubGraph(); + } + + @Override + public SubGraphImplementor addKeySubGraph(String attributeName, Class subtype) { + return findOrCreateAttributeNode( attributeName ).makeKeySubGraph( subtype ); + } + + @Override + public SubGraphImplementor addMapKeySubgraph(MapAttribute attribute) { + return findOrCreateAttributeNode( attribute.getName() ).makeKeySubGraph( attribute.getKeyJavaType() ); + } + + @Override + 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) { + return findOrCreateAttributeNode( attribute.getName() ) + .makeSubGraph( asManagedType( attribute.getElementType() ) ); + } + + @Override + public SubGraphImplementor addElementSubgraph(String attributeName, Class type) { + return findOrCreateAttributeNode( attributeName ).makeSubGraph( type ); + } + + @Override + public SubGraphImplementor addTreatedElementSubgraph( + PluralAttribute attribute, + Class type) { + return addElementSubgraph( attribute ).addTreatedSubGraph( type ); + } + + @Override + public SubGraphImplementor addTreatedSubGraph(ManagedDomainType type) { + verifyMutability(); + if ( getGraphedType().equals( type ) ) { + //noinspection unchecked + return (SubGraphImplementor) this; } else { - attrNode = (AttributeNodeImplementor) attrNodeMap.get( attribute ); + final Class javaType = type.getJavaType(); + final SubGraphImplementor castSubgraph = getTreatedSubgraphForPut( javaType ); + if ( castSubgraph == null ) { + final SubGraphImpl subgraph = new SubGraphImpl<>( type, true ); + treatedSubgraphs.put( javaType, subgraph ); + return subgraph; + } + else { + return castSubgraph; + } } + } + + @Override + public SubGraphImplementor addTreatedSubGraph(Class type) { + return addTreatedSubGraph( getGraphedType().getMetamodel().managedType( type ) ); + } + + @Override + public Map, SubGraphImplementor> getSubGraphs() { + return treatedSubgraphs == null ? emptyMap() : unmodifiableMap( treatedSubgraphs ); + } - if ( attrNode == null ) { - attrNode = new AttributeNodeImpl<>(attribute, isMutable()); - attrNodeMap.put( attribute, attrNode ); + static ManagedDomainType asManagedType(Type domainType) { + if ( domainType instanceof ManagedDomainType managedDomainType ) { + return managedDomainType; + } + else { + throw new CannotContainSubGraphException( "Type '" + domainType.getJavaType().getName() + + "' is not a managed type" ); } + } - return attrNode; + @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 37e641e0fd7a..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 @@ -4,56 +4,55 @@ */ 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.GraphImplementor; 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 java.util.HashMap; +import java.util.Map; import static java.util.Collections.emptyMap; -import static org.hibernate.metamodel.model.domain.internal.DomainModelHelper.findSubType; + /** * Implementation of {@link jakarta.persistence.AttributeNode}. * * @author Steve Ebersole */ -public class AttributeNodeImpl +public class AttributeNodeImpl extends AbstractGraphNode implements AttributeNodeImplementor { private final PersistentAttribute attribute; + private final DomainType valueGraphType; + private final SimpleDomainType keyGraphType; - private Map, SubGraphImplementor> subGraphMap; - private Map, SubGraphImplementor> keySubGraphMap; + private SubGraphImplementor valueSubgraph; + private SubGraphImplementor keySubgraph; - public AttributeNodeImpl(PersistentAttribute attribute, boolean mutable) { - this(attribute, null, null, mutable); + static AttributeNodeImpl create(PersistentAttribute attribute, boolean mutable) { + return new AttributeNodeImpl<>( attribute, mutable, attribute.getValueGraphType(), attribute.getKeyGraphType() ); } - /** - * Intended only for use from making a copy - */ - private AttributeNodeImpl( - PersistentAttribute attribute, - Map, SubGraphImplementor> subGraphMap, - Map, SubGraphImplementor> keySubGraphMap, - boolean mutable) { + private AttributeNodeImpl( + PersistentAttribute attribute, boolean mutable, + DomainType valueGraphType, SimpleDomainType keyGraphType) { super( mutable ); this.attribute = attribute; - this.subGraphMap = subGraphMap; - this.keySubGraphMap = keySubGraphMap; + 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 ); } @Override @@ -67,214 +66,169 @@ public PersistentAttribute getAttributeDescriptor() { } @Override - public Map, SubGraphImplementor> getSubGraphMap() { - return subGraphMap == null ? emptyMap() : subGraphMap; + public SubGraphImplementor getSubGraph() { + return valueSubgraph; } @Override - public Map, SubGraphImplementor> getKeySubGraphMap() { - return keySubGraphMap == null ? emptyMap() : keySubGraphMap; + public SubGraphImplementor getKeySubGraph() { + return keySubgraph; } @Override - public SubGraphImplementor makeSubGraph() { - return internalMakeSubgraph( (Class) null ); + public SubGraphImplementor makeSubGraph() { + verifyMutability(); + if ( valueSubgraph == null ) { + valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true ); + } + return valueSubgraph; } @Override - public SubGraphImplementor makeSubGraph(Class subtype) { - return internalMakeSubgraph( subtype ); + public SubGraphImplementor makeSubGraph(Class subtype) { + final ManagedDomainType managedType = asManagedType( valueGraphType ); + if ( !managedType.getBindableJavaType().isAssignableFrom( subtype ) ) { + throw new IllegalArgumentException( "Not a subtype: " + subtype.getName() ); + } + @SuppressWarnings("unchecked") + final Class castSuptype = (Class) subtype; + final SubGraphImplementor result = makeSubGraph().addTreatedSubGraph( castSuptype ); + //noinspection unchecked + return (SubGraphImplementor) result; } @Override - public SubGraphImplementor makeSubGraph(ManagedDomainType subtype) { - return internalMakeSubgraph( subtype ); - } - - private SubGraphImplementor internalMakeSubgraph(ManagedDomainType type) { - assert type != null; - log.debugf( "Making sub-graph : ( (%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 sub-graphs", - getAttributeName(), - getAttributeDescriptor().getPersistentAttributeType().name() - ) - ); + public SubGraphImplementor makeSubGraph(ManagedDomainType subtype) { + final ManagedDomainType managedType = asManagedType( valueGraphType ); + final Class javaType = subtype.getBindableJavaType(); + if ( !managedType.getBindableJavaType().isAssignableFrom( javaType ) ) { + throw new IllegalArgumentException( "Not a subtype: " + javaType.getName() ); } + @SuppressWarnings("unchecked") + final ManagedDomainType castType = (ManagedDomainType) subtype; + final SubGraphImplementor result = makeSubGraph().addTreatedSubGraph( castType ); + //noinspection unchecked + return (SubGraphImplementor) result; } - private static final Logger log = Logger.getLogger( AttributeNodeImpl.class ); - - private SubGraphImplementor internalMakeSubgraph(Class subType) { + @Override + public SubGraphImplementor makeKeySubGraph() { verifyMutability(); - final ManagedDomainType managedType = valueGraphTypeAsManaged(); - return internalMakeSubgraph( findSubType( managedType, subType == null ? managedType.getJavaType() : subType ) ); - } - - protected void internalAddSubGraph(SubGraphImplementor subGraph) { - log.tracef( "Adding sub-graph : ( (%s) %s )", subGraph.getGraphedType().getTypeName(), getAttributeName() ); - if ( subGraphMap == null ) { - subGraphMap = new HashMap<>(); - } - final SubGraphImplementor previous = subGraphMap.put( subGraph.getClassType(), subGraph ); - if ( previous != null ) { - log.debugf( "Adding sub-graph [%s] over-wrote existing [%s]", subGraph, previous ); + checkMap(); + if ( keySubgraph == null ) { + keySubgraph = new SubGraphImpl<>( asManagedType( keyGraphType ), true ); } + return keySubgraph; } @Override - public void addSubGraph(Class subType, SubGraph subGraph) { - verifyMutability(); - assert subGraph.getClassType() == subType; - internalAddSubGraph( (SubGraphImplementor) subGraph ); + public SubGraphImplementor makeKeySubGraph(Class subtype) { + checkMap(); + final ManagedDomainType type = asManagedType( keyGraphType ); + if ( !type.getBindableJavaType().isAssignableFrom( subtype ) ) { + throw new IllegalArgumentException( "Not a key subtype: " + subtype.getName() ); + } + @SuppressWarnings("unchecked") + final Class castType = (Class) subtype; + final SubGraphImplementor result = makeKeySubGraph().addTreatedSubGraph( castType ); + //noinspection unchecked + return (SubGraphImplementor) result; } @Override - public void addSubGraph(SubGraphImplementor subGraph) { - internalAddSubGraph( subGraph ); + public SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype) { + 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() ); + } + @SuppressWarnings("unchecked") + final ManagedDomainType castType = (ManagedDomainType) subtype; + final SubGraphImplementor result = makeKeySubGraph().addTreatedSubGraph( castType ); + //noinspection unchecked + return (SubGraphImplementor) result; } - @Override - public SubGraphImplementor makeKeySubGraph() { - return internalMakeKeySubgraph( (Class) null ); + private void checkMap() { + if ( keyGraphType == null ) { + throw new CannotContainSubGraphException( "Attribute '" + description() + "' is not a Map" ); + } } - @Override - public SubGraphImplementor makeKeySubGraph(Class subtype) { - return internalMakeKeySubgraph( subtype ); + private ManagedDomainType asManagedType(DomainType domainType) { + if ( domainType instanceof ManagedDomainType managedDomainType ) { + return managedDomainType; + } + else { + throw new CannotContainSubGraphException( "Attribute '" + description() + + "' is of type '" + domainType.getTypeName() + + "' which is not a managed type" ); + } } - @Override - public SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype) { - return internalMakeKeySubgraph( subtype ); + private String description() { + return attribute.getDeclaringType().getTypeName() + "." + attribute.getName(); } - private SubGraphImplementor internalMakeKeySubgraph(ManagedDomainType type) { - assert type != null; - log.debugf( "Making key sub-graph : ( (%s) %s )", type.getTypeName(), getAttributeName() ); - final SubGraphImplementor subGraph = DomainModelHelper.makeSubGraph( type, type.getBindableJavaType() ); - internalAddKeySubGraph( subGraph ); - return subGraph; + @Override + public String toString() { + return "AttributeNode[" + description() + "]"; } - private SubGraphImplementor internalMakeKeySubgraph(Class type) { - verifyMutability(); - final ManagedDomainType managedType = keyGraphTypeAsManaged(); - return internalMakeKeySubgraph( type == null ? managedType : findSubType( managedType, type ) ); + @Override + public AttributeNodeImplementor makeCopy(boolean mutable) { + return !mutable && !isMutable() ? this : new AttributeNodeImpl<>( this, mutable ); } - protected void internalAddKeySubGraph(SubGraph subGraph) { - log.tracef( "Adding key sub-graph : ( (%s) %s )", subGraph.getClassType().getName(), getAttributeName() ); - if ( keySubGraphMap == null ) { - keySubGraphMap = new HashMap<>(); + @Override + 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 { + // even if immutable, we need to merge here + valueSubgraph.mergeInternal( otherValueSubgraph ); + } } - final SubGraphImplementor previous = - keySubGraphMap.put( subGraph.getClassType(), (SubGraphImplementor) subGraph ); - if ( previous != null ) { - log.debugf( "Adding key sub-graph [%s] over-wrote existing [%]", subGraph, previous ); + final SubGraphImplementor otherKeySubgraph = that.keySubgraph; + if ( otherKeySubgraph != null ) { + if ( keySubgraph == null ) { + keySubgraph = otherKeySubgraph.makeCopy( isMutable() ); + } + else { + // even if immutable, we need to merge here + keySubgraph.mergeInternal( otherKeySubgraph ); + } } } - @SuppressWarnings("unchecked") - private ManagedDomainType keyGraphTypeAsManaged() { - final SimpleDomainType keyGraphType = getAttributeDescriptor().getKeyGraphType(); - if ( keyGraphType instanceof ManagedDomainType ) { - return (ManagedDomainType) keyGraphType; + @Override + public Map, SubGraphImplementor> getSubGraphs() { + if ( valueSubgraph == null ) { + return emptyMap(); } else { - throw new CannotContainSubGraphException( - String.format( - Locale.ROOT, - "Attribute [%s#%s] (%s) cannot contain key sub-graphs - %s", - getAttributeDescriptor().getDeclaringType().getTypeName(), - getAttributeName(), - getAttributeDescriptor().getPersistentAttributeType().name(), - keyGraphType - ) - ); + final HashMap, SubGraphImplementor> map = new HashMap<>( valueSubgraph.getSubGraphs() ); + map.put( attribute.getValueGraphType().getBindableJavaType(), valueSubgraph ); + return map; } } @Override - public void addKeySubGraph(Class subType, SubGraph subGraph) { - assert subGraph.getClassType() == subType; - internalAddKeySubGraph( subGraph ); - } - - @Override - public AttributeNodeImplementor makeCopy(boolean mutable) { - return new AttributeNodeImpl<>( - this.attribute, makeMapCopy( mutable, subGraphMap ), makeMapCopy( mutable, keySubGraphMap ), mutable - ); - } - - private Map, SubGraphImplementor> makeMapCopy( - boolean mutable, - Map, SubGraphImplementor> nodeMap) { - if ( nodeMap == null ) { - return null; + public Map, SubGraphImplementor> getKeySubGraphs() { + if ( keySubgraph == null ) { + return emptyMap(); } 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<>( keySubgraph.getSubGraphs() ); + map.put( attribute.getKeyGraphType().getJavaType(), keySubgraph ); + return map; } } - - @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 ) ); - } - } - ); - - 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 ) ); - } - } - ); - } } 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..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 @@ -10,9 +10,6 @@ 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; /** * Implementation of the JPA-defined {@link jakarta.persistence.EntityGraph} interface. @@ -33,7 +30,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 +46,21 @@ 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" ); - } - - @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" ); - } - - @Override - public SubGraphImplementor addMapKeySubgraph(MapAttribute attribute) { - throw new UnsupportedOperationException( "Not yet implemented" ); + public RootGraphImplementor makeImmutableCopy(String name) { + return makeRootGraph( name, false ); } } 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..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 @@ -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,16 @@ public SubGraphImpl(ManagedDomainType managedType, boolean mutable) { } public SubGraphImpl(AbstractGraph original, boolean mutable) { - super(original, mutable); + super( original, mutable ); } @Override public SubGraphImplementor makeCopy(boolean mutable) { - return new SubGraphImpl<>(this, mutable); + return !mutable && !isMutable() ? this : 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" ); + return makeCopy( mutable ); } } 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 449d7a000718..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 @@ -4,14 +4,12 @@ */ 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 java.util.Map; + + /** * Integration version of the {@link AttributeNode} contract * @@ -19,61 +17,37 @@ * @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(); - } + AttributeNodeImplementor makeCopy(boolean mutable); @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default Map, SubGraph> getKeySubGraphs() { - return (Map) getKeySubGraphMap(); - } + SubGraphImplementor makeSubGraph(); @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default Map getSubgraphs() { - return (Map) getSubGraphMap(); - } + SubGraphImplementor makeKeySubGraph(); @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - default Map getKeySubgraphs() { - return (Map) getKeySubGraphMap(); - } + SubGraphImplementor makeSubGraph(Class subtype); @Override - AttributeNodeImplementor makeCopy(boolean mutable); + SubGraphImplementor makeKeySubGraph(Class subtype); @Override - SubGraphImplementor makeSubGraph(); + SubGraphImplementor makeSubGraph(ManagedDomainType subtype); @Override - SubGraphImplementor makeKeySubGraph(); + SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype); - @Override - SubGraphImplementor makeSubGraph(Class subtype); + void merge(AttributeNodeImplementor other); - @Override - SubGraphImplementor makeKeySubGraph(Class subtype); + SubGraphImplementor getSubGraph(); - SubGraphImplementor makeSubGraph(ManagedDomainType subtype); + SubGraphImplementor getKeySubGraph(); - SubGraphImplementor makeKeySubGraph(ManagedDomainType subtype); - - void merge(AttributeNodeImplementor attributeNode); + @Override + Map, SubGraphImplementor> getSubGraphs(); - void addSubGraph(SubGraphImplementor subGraph); + @Override + 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 6d5d8b4b48f9..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 @@ -5,16 +5,16 @@ 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.Internal; import org.hibernate.graph.CannotBecomeEntityGraphException; -import org.hibernate.graph.CannotContainSubGraphException; 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 org.hibernate.query.sqm.SqmPathSource; +import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; -import jakarta.persistence.metamodel.Attribute; /** * Integration version of the {@link Graph} contract @@ -25,49 +25,25 @@ */ public interface GraphImplementor extends Graph, GraphNodeImplementor { - void merge(GraphImplementor other); + void merge(GraphImplementor other); + @Internal + void mergeInternal(GraphImplementor graph); - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // 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; - } + List> getAttributeNodeList(); - @Override - 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> getNodes(); @Override AttributeNodeImplementor findAttributeNode(String attributeName); @@ -75,83 +51,45 @@ default List> getAttributeNodeList() { @Override AttributeNodeImplementor findAttributeNode(PersistentAttribute attribute); - @Override - AttributeNodeImplementor addAttributeNode(String attributeName) throws CannotContainSubGraphException; + AttributeNodeImplementor findOrCreateAttributeNode(String name); - @Override - AttributeNodeImplementor addAttributeNode(Attribute attribute); + AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute); @Override - AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute) - throws CannotContainSubGraphException; + AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute); - @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); + @Override + SubGraphImplementor addSubGraph(String attributeName); + @Override + SubGraphImplementor addSubGraph(String attributeName, Class subType); - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // sub graph nodes + @Override + SubGraphImplementor addSubGraph(PersistentAttribute attribute); @Override - @SuppressWarnings("unchecked") - default SubGraphImplementor addSubGraph(String attributeName) - throws CannotContainSubGraphException { - return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeSubGraph(); - } + SubGraphImplementor addSubGraph(PersistentAttribute attribute, Class subtype); @Override - default SubGraphImplementor addSubGraph(String attributeName, Class subType) - throws CannotContainSubGraphException { - return findOrCreateAttributeNode( attributeName ).makeSubGraph( subType ); - } + SubGraphImplementor addKeySubGraph(String attributeName); @Override - default SubGraphImplementor addSubGraph(PersistentAttribute attribute) - throws CannotContainSubGraphException { - return findOrCreateAttributeNode( attribute ).makeSubGraph(); - } + SubGraphImplementor addKeySubGraph(String attributeName, Class subtype); @Override - default SubGraphImplementor addSubGraph( - PersistentAttribute attribute, - Class subType) throws CannotContainSubGraphException { - return findOrCreateAttributeNode( attribute ).makeSubGraph( subType ); - } + SubGraphImplementor addSubGraph(PersistentAttribute attribute, ManagedDomainType subtype); + SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, Class type); - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // key sub graph nodes + SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, ManagedDomainType type); @Override - @SuppressWarnings("unchecked") - default SubGraphImplementor addKeySubGraph(String attributeName) { - return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeKeySubGraph(); - } + SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, ManagedDomainType subtype); @Override - default SubGraphImplementor addKeySubGraph(String attributeName, Class subtype) { - return findOrCreateAttributeNode( attributeName ).makeKeySubGraph( subtype ); - } + SubGraphImplementor addTreatedSubGraph(Class type); - @Override - default SubGraphImplementor addKeySubGraph(PersistentAttribute attribute) { - return findOrCreateAttributeNode( attribute ).makeKeySubGraph(); - } + SubGraphImplementor addTreatedSubGraph(ManagedDomainType type); - @Override - default SubGraphImplementor addKeySubGraph( - PersistentAttribute attribute, - Class subType) - throws CannotContainSubGraphException { - return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subType ); - } + Map, SubGraphImplementor> getSubGraphs(); } 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..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 @@ -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,10 @@ 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/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/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/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/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..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 ); } } @@ -378,11 +382,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 +623,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/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/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..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,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.getNodes().values() ) { + if ( node.getAttributeDescriptor().isCollection() ) { return true; } - for ( SubGraphImplementor subGraph : attributeNodeImplementor.getSubGraphMap().values() ) { - if ( containsCollectionFetches(subGraph) ) { + for ( SubGraphImplementor subgraph : node.getSubGraphs().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/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/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java index f3f1492440e0..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 @@ -65,20 +65,19 @@ 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(); + 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 ) { @@ -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/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..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 @@ -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() ); @@ -186,10 +186,10 @@ public void testLinkSubtypeParsing() { assertNullOrEmpty( linkToOneNode.getKeySubgraphs() ); - final SubGraphImplementor subGraph = linkToOneNode.getSubGraphMap().get( GraphParsingTestSubEntity.class ); - assertNotNull( subGraph ); + final SubGraphImplementor subgraph = linkToOneNode.getSubGraphs().get( GraphParsingTestSubEntity.class ); + assertNotNull( subgraph ); - assertBasicAttributes( subGraph, "sub" ); + assertBasicAttributes( subgraph, "sub" ); } @Test 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 ); } 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 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..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 @@ -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 ); } @@ -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)" ); 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..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,12 +4,14 @@ */ package org.hibernate.orm.test.jpa.graphs; +import jakarta.persistence.ManyToMany; import jakarta.persistence.MapKey; import java.util.HashMap; import java.util.HashSet; 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; @@ -33,11 +35,12 @@ 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; -import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.JiraKey; import org.junit.Test; @@ -55,7 +58,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 +220,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 +260,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 +270,7 @@ public void attributeNodeInheritanceTest() { @Test @JiraKey(value = "HHH-9735") - public void loadIsMemeberQueriedCollection() { + public void loadIsMemberQueriedCollection() { EntityManager em = getOrCreateEntityManager(); em.getTransaction().begin(); @@ -484,6 +488,161 @@ 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(); + } + + @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 { @@ -508,7 +667,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 +683,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; @@ -602,6 +761,9 @@ public static class AnimalOwner { @ManyToOne(fetch = FetchType.LAZY) public Animal animal; + + @ManyToMany + public Set animals = new HashSet<>(); } @Entity(name = "Animal") @@ -620,6 +782,9 @@ public static class Dog extends Animal { public Integer numberOfLegs; + @ManyToOne(fetch = FetchType.LAZY) + Kennel kennel; + public Dog() { dtype = "DOG"; } @@ -635,4 +800,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