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 3f8582ef87e7..8aaa100167d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java @@ -14,17 +14,53 @@ import static java.util.Collections.unmodifiableMap; /** - * Extends the JPA-defined {@link AttributeNode} with additional operations. + * Represents a fetched {@linkplain jakarta.persistence.metamodel.Attribute attribute} in an + * {@linkplain Graph entity graph}. + *

+ * An {@code AttributeNode} representing an attribute whose type is a managed type or collection + * of some managed type may have an associated value subgraph, which is represented by + * an instance of {@link SubGraph}. + *

+ *

+ * Or, if the represented attribute is a {@link Map}, the {@code AttributeNode} maye have an + * associated key subgraph, similarly represented by a {@link SubGraph}. + *

+ * Not every attribute node has a subgraph. + *

+ * Extends the JPA-defined {@link jakarta.persistence.AttributeNode} with additional operations. + * + * @apiNote Historically, this interface declared operations with incorrect generic types, + * leading to unsound code. This was in Hibernate 7, with possible breakage to older code. * * @author Strong Liu * @author Steve Ebersole * @author Andrea Boriero + * @author Gavin King */ public interface AttributeNode extends GraphNode, jakarta.persistence.AttributeNode { + /** + * The {@link PersistentAttribute} represented by this node. + */ PersistentAttribute getAttributeDescriptor(); + /** + * All value subgraphs rooted at this node. + * + * @see jakarta.persistence.AttributeNode#getSubgraphs + */ Map, ? extends SubGraph> getSubGraphs(); + + /** + * All key subgraphs rooted at this node. + * + * @see jakarta.persistence.AttributeNode#getKeySubgraphs + */ Map, ? extends SubGraph> getKeySubGraphs(); @Override @@ -37,13 +73,43 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr return unmodifiableMap( getKeySubGraphs() ); } + /** + * Create and return a new value {@link SubGraph} rooted at this node, + * or return an existing such {@link SubGraph} if there is one. + */ SubGraph makeSubGraph(); + + /** + * Create and return a new key {@link SubGraph} rooted at this node, + * or return an existing such {@link SubGraph} if there is one. + */ SubGraph makeKeySubGraph(); + /** + * Create and return a new value {@link SubGraph} rooted at this node, + * with the given type, which may be a subtype of the value type, + * or return an existing such {@link SubGraph} if there is one. + */ SubGraph makeSubGraph(Class subtype); + + /** + * Create and return a new value {@link SubGraph} rooted at this node, + * with the given type, which may be a subtype of the key type, + * or return an existing such {@link SubGraph} if there is one. + */ SubGraph makeKeySubGraph(Class subtype); + /** + * Create and return a new value {@link SubGraph} rooted at this node, + * with the given type, which may be a subtype of the value type, + * or return an existing such {@link SubGraph} if there is one. + */ SubGraph makeSubGraph(ManagedDomainType subtype); - SubGraph makeKeySubGraph(ManagedDomainType subtype); + /** + * Create and return a new value {@link SubGraph} rooted at this node, + * with the given type, which may be a subtype of the key type, + * or return an existing such {@link SubGraph} if there is one. + */ + SubGraph makeKeySubGraph(ManagedDomainType subtype); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java index fc34e1c7686d..09a8a894a9d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java @@ -7,6 +7,7 @@ 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; @@ -14,16 +15,32 @@ import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; /** - * A container for {@link AttributeNode} references. + * Represents a {@link jakarta.persistence.metamodel.ManagedType managed type} in an + * {@linkplain Graph entity graph}, acting as a container for: + *

+ *

+ * A treated (narrowed) subgraph allows fetching to be specified for any attribute of + * any subtype of the type represented by this graph. The usual way to create a treated + * subgraph is by calling {@link jakarta.persistence.EntityGraph#addTreatedSubgraph(Class)} + * or {@link #addTreatedSubGraph(Class)}. There are various shortcut operations such as + * {@link jakarta.persistence.EntityGraph#addTreatedSubgraph(Attribute, Class)} and + * {@link #addSubGraph(PersistentAttribute, Class)} which combine creation of a subgraph + * with creation of a treated subgraph. + *

+ * Extends the JPA-defined {@link jakarta.persistence.Graph} with additional operations. * - * @apiNote Acts as an abstraction over the JPA-defined interfaces - * {@link jakarta.persistence.EntityGraph} and - * {@link jakarta.persistence.Subgraph}, which have no - * common supertype. + * @apiNote Historically, both {@link jakarta.persistence.EntityGraph} and this interface + * declared operations with incorrect generic types, leading to unsound code. This was + * rectified in JPA 3.2 and Hibernate 7, with possible breakage to older code. * * @author Strong Liu * @author Steve Ebersole * @author Andrea Boriero + * @author Gavin King * * @see RootGraph * @see SubGraph @@ -33,23 +50,17 @@ public interface Graph extends GraphNode, jakarta.persistence.Graph { /** - * Get a list of all existing AttributeNodes within this container. - * - * @see #getAttributeNodes - */ - List> getAttributeNodeList(); - - /** - * Graphs apply only to {@link jakarta.persistence.metamodel.ManagedType}s. + * The {@linkplain jakarta.persistence.metamodel.ManagedType managed type} + * of the node. * * @return the {@code ManagedType} being graphed here. */ ManagedDomainType getGraphedType(); /** - * Create a named root {@link Graph} if the given name is not null. + * Create a named {@linkplain RootGraph root graph} representing this node. * - * @param mutable controls whether the resulting {@code Graph} is mutable + * @param mutable controls whether the resulting graph is mutable * * @throws CannotBecomeEntityGraphException If the named attribute is not entity-valued * @@ -60,20 +71,32 @@ RootGraph makeRootGraph(String name, boolean mutable) throws CannotBecomeEntityGraphException; /** - * Create a new (mutable or immutable) {@link SubGraph} rooted at - * this {@link Graph}. + * Create a new {@linkplain SubGraph subgraph} representing this node. * * @deprecated This will be removed */ @Deprecated(since = "7.0", forRemoval = true) SubGraph makeSubGraph(boolean mutable); + /** + * Make a copy of this graph node, with the given mutability. + *

+ * If this graph is immutable, and the argument is {@code false}, + * simply return this instance. + */ @Override Graph makeCopy(boolean mutable); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // AttributeNode handling + // AttributeNodes + + /** + * All {@linkplain AttributeNode nodes} belonging to this container. + * + * @see #getAttributeNodes + */ + List> getAttributeNodeList(); /** * Find an already existing AttributeNode by attributeName within @@ -112,8 +135,8 @@ default boolean hasAttributeNode(Attribute attribute) { } /** - * Add an {@link AttributeNode} (with no associated {@link SubGraph}) - * to this container by attribute reference. + * Add an {@link AttributeNode} representing the given {@link PersistentAttribute} + * to this node of the graph without creating any associated {@link SubGraph}. * * @see #addAttributeNode(Attribute) */ @@ -126,53 +149,135 @@ default AttributeNode addAttributeNode(Attribute attribute) // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // Subgraph nodes + // Subgraphs + /** + * Create and return a new (mutable) {@link SubGraph} representing + * the given subtype of the type of this node, or return an existing + * such {@link SubGraph} if there is one. + * + * @see jakarta.persistence.EntityGraph#addTreatedSubgraph(Class) + */ SubGraph addTreatedSubGraph(Class type); + /** + * Create and return a new (mutable) {@link SubGraph} representing + * the given subtype of the type of this node, or return an existing + * such {@link SubGraph} if there is one. + */ SubGraph addTreatedSubGraph(ManagedDomainType type); /** * Create and return a new (mutable) {@link SubGraph} associated with - * the named {@link AttributeNode}. + * the named {@link Attribute}, or return an existing such {@link SubGraph} + * if there is one. * - * @apiNote If no such AttributeNode exists yet, it is created. + * @see #addSubgraph(String) */ @Deprecated SubGraph addSubGraph(String attributeName) throws CannotContainSubGraphException; + /** + * Create and return a new (mutable) {@link SubGraph} associated with + * the named {@link Attribute}, and with the given type, which may be + * a subtype of the attribute type, or return an existing such + * {@link SubGraph} if there is one. + * + * @see #addSubgraph(String, Class) + */ SubGraph addSubGraph(String attributeName, Class type) throws CannotContainSubGraphException; /** * Create and return a new (mutable) {@link SubGraph} associated with - * the {@link AttributeNode} for the given attribute. + * the given {@link PersistentAttribute}, or return an existing such + * {@link SubGraph} if there is one. * - * @apiNote If no such AttributeNode exists yet, it is created. + * @see #addSubgraph(Attribute) */ SubGraph addSubGraph(PersistentAttribute attribute) throws CannotContainSubGraphException; + /** + * Create and return a new (mutable) {@link SubGraph} associated with + * the given {@link PersistentAttribute}, and with the given type, + * which may be a subtype of the attribute type, or return an existing + * such {@link SubGraph} if there is one. + * + * @see #addSubgraph(Attribute, Class) + */ SubGraph addSubGraph(PersistentAttribute attribute, Class type) throws CannotContainSubGraphException; + /** + * Create and return a new (mutable) {@link SubGraph} associated with + * the given {@link PersistentAttribute}, and with the given type, + * which may be a subtype of the attribute type, or return an existing + * such {@link SubGraph} if there is one. + */ SubGraph addSubGraph(PersistentAttribute attribute, ManagedDomainType type) throws CannotContainSubGraphException; + /** + * Create and return a new (mutable) {@link SubGraph} associated with + * the element of the given collection, and with the given type, which + * may be a subtype of the attribute type, or return an existing such + * {@link SubGraph} if there is one. + * + * @see #addTreatedElementSubgraph(PluralAttribute, Class) + */ SubGraph addElementSubGraph(PluralPersistentAttribute attribute, Class type) throws CannotContainSubGraphException; + /** + * Create and return a new (mutable) {@link SubGraph} associated with + * the element of the given collection, and with the given type, which + * may be a subtype of the attribute type, or return an existing such + * {@link SubGraph} if there is one. + */ SubGraph addElementSubGraph(PluralPersistentAttribute attribute, ManagedDomainType type) throws CannotContainSubGraphException; + /** + * Create and return a new (mutable) {@link SubGraph} associated with + * the key of the named map or return an existing such {@link SubGraph} + * if there is one. + * + * @see #addKeySubgraph(String) + */ @Deprecated SubGraph addKeySubGraph(String attributeName) throws CannotContainSubGraphException; + /** + * Create and return a new (mutable) {@link SubGraph} associated with + * the key of the named map, and with the given type, which may be a + * subtype of the attribute type, or return an existing such + * {@link SubGraph} if there is one. + * + * @see #addKeySubgraph(String, Class) + */ SubGraph addKeySubGraph(String attributeName, Class type) throws CannotContainSubGraphException; + /** + * Create and return a new (mutable) {@link SubGraph} associated with + * the key of the named map, and with the given type, which may be a + * subtype of the attribute type, or return an existing such + * {@link SubGraph} if there is one. + * + * @see #addTreatedMapKeySubgraph(MapAttribute, Class) + */ + SubGraph addKeySubGraph(MapPersistentAttribute attribute, Class type) + throws CannotContainSubGraphException; + + /** + * Create and return a new (mutable) {@link SubGraph} associated with + * the key of the named map, and with the given type, which may be a + * subtype of the attribute type, or return an existing such + * {@link SubGraph} if there is one. + */ SubGraph addKeySubGraph(MapPersistentAttribute attribute, ManagedDomainType type) throws CannotContainSubGraphException; 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 8a19c27f6b59..97783563760a 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 @@ -38,6 +38,7 @@ * Base class for {@link RootGraph} and {@link SubGraph} implementations. * * @author Steve Ebersole + * @author Gavin King */ public abstract class AbstractGraph extends AbstractGraphNode implements GraphImplementor { @@ -319,6 +320,11 @@ public SubGraphImplementor addElementSubGraph(PluralPersistentAttribute return findOrCreateAttributeNode( attribute ).makeSubGraph( type ); } + @Override + public SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, Class subtype) { + return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subtype ); + } + @Override public SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, ManagedDomainType subtype) { return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subtype ); 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 ddc756218cc0..334504569f8f 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 @@ -22,6 +22,7 @@ * Implementation of {@link jakarta.persistence.AttributeNode}. * * @author Steve Ebersole + * @author Gavin King */ public class AttributeNodeImpl extends AbstractGraphNode 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 90fc6e15e3db..d351b874a45e 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 @@ -71,17 +71,22 @@ RootGraphImplementor makeRootGraph(String name, boolean mutable) SubGraphImplementor addSubGraph(PersistentAttribute attribute, Class subtype); @Override - SubGraphImplementor addKeySubGraph(String attributeName); + SubGraphImplementor addSubGraph(PersistentAttribute attribute, ManagedDomainType subtype); @Override - SubGraphImplementor addKeySubGraph(String attributeName, Class subtype); + SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, Class type); @Override - SubGraphImplementor addSubGraph(PersistentAttribute attribute, ManagedDomainType subtype); + SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, ManagedDomainType type); - SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, Class type); + @Override + SubGraphImplementor addKeySubGraph(String attributeName); - SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, ManagedDomainType type); + @Override + SubGraphImplementor addKeySubGraph(String attributeName, Class subtype); + + @Override + SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, Class subtype); @Override SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, ManagedDomainType subtype);