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}.
+ *
+ * - For a {@linkplain jakarta.persistence.metamodel.SingularAttribute singular attribute},
+ * the value type is the type of the attribute.
+ *
- For a {@linkplain jakarta.persistence.metamodel.PluralAttribute plural attribute}, the
+ * value type is the collection element type.
+ *
+ *
+ * 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, J> 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:
+ *
+ * - {@link AttributeNode} references representing fetched attributes, and
+ *
- treated subgraphs, each represented by a child instance of
+ * {@link SubGraph}.
+ *
+ *
+ * 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 extends AttributeNode>> 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 extends AttributeNode>> getAttributeNodeList();
/**
* Find an already existing AttributeNode by attributeName within
@@ -112,8 +135,8 @@ default boolean hasAttributeNode(Attribute super J, ?> 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 super J, Y> 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 super J, AJ> 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 super J, ? super AJ> 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 super J, ? super AJ> 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 super J, ?, ? super AJ> 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 super J, ?, ? super AJ> 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 super J, ? super AJ, ?> 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 super J, ? super AJ, ?> 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 super J, ? super AJ, ?> attribute, Class subtype) {
+ return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subtype );
+ }
+
@Override
public SubGraphImplementor addKeySubGraph(MapPersistentAttribute super J, ? super AJ, ?> 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 super J, ? super AJ> attribute, Class subtype);
@Override
- SubGraphImplementor addKeySubGraph(String attributeName);
+ SubGraphImplementor addSubGraph(PersistentAttribute super J, ? super AJ> attribute, ManagedDomainType subtype);
@Override
- SubGraphImplementor addKeySubGraph(String attributeName, Class subtype);
+ SubGraphImplementor addElementSubGraph(PluralPersistentAttribute super J, ?, ? super AJ> attribute, Class type);
@Override
- SubGraphImplementor addSubGraph(PersistentAttribute super J, ? super AJ> attribute, ManagedDomainType subtype);
+ SubGraphImplementor addElementSubGraph(PluralPersistentAttribute super J, ?, ? super AJ> attribute, ManagedDomainType type);
- SubGraphImplementor addElementSubGraph(PluralPersistentAttribute super J, ?, ? super AJ> attribute, Class type);
+ @Override
+ SubGraphImplementor addKeySubGraph(String attributeName);
- SubGraphImplementor addElementSubGraph(PluralPersistentAttribute super J, ?, ? super AJ> attribute, ManagedDomainType type);
+ @Override
+ SubGraphImplementor addKeySubGraph(String attributeName, Class subtype);
+
+ @Override
+ SubGraphImplementor addKeySubGraph(MapPersistentAttribute super J, ? super AJ, ?> attribute, Class subtype);
@Override
SubGraphImplementor addKeySubGraph(MapPersistentAttribute super J, ? super AJ, ?> attribute, ManagedDomainType subtype);