From cfe4346ef80cea5ce8df6cd92c356b69ac2b0a1c Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 3 Jan 2025 01:28:53 +0100 Subject: [PATCH] Graphpocalypse: actually let's just deprecate the makeXxxxSubGraph() operations... ... and delete the new ones I added. The reasoning here is that they just aren't properly typesafe, as you can see by the hoops I had to go through to actually implement them. And since the whole package is marked @Incubating, we're not committed to them. This lets me make the implementation even more typesafe and detect more user errors and bugs. --- .../org/hibernate/graph/AttributeNode.java | 50 ++-- .../main/java/org/hibernate/graph/Graph.java | 4 +- .../graph/internal/AttributeNodeImpl.java | 147 ++++++----- .../{AbstractGraph.java => GraphImpl.java} | 233 ++++++++++++------ .../graph/internal/RootGraphImpl.java | 2 +- .../graph/internal/SubGraphImpl.java | 4 +- .../graph/internal/parse/GraphParser.java | 2 +- .../internal/parse/PathQualifierType.java | 14 +- .../internal/parse/SubGraphGenerator.java | 2 +- .../graph/spi/AttributeNodeImplementor.java | 58 +++-- .../hibernate/graph/spi/GraphImplementor.java | 113 +++------ .../model/domain/MapPersistentAttribute.java | 3 + .../domain/internal/JpaMetamodelImpl.java | 56 +++-- .../query/sqm/internal/AppliedGraphs.java | 2 +- .../EntityDelayedFetchInitializer.java | 7 +- ...StandardEntityGraphTraversalStateImpl.java | 2 +- .../parser/EntityGraphParserTest.java | 6 +- 17 files changed, 404 insertions(+), 301 deletions(-) rename hibernate-core/src/main/java/org/hibernate/graph/internal/{AbstractGraph.java => GraphImpl.java} (62%) 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 5caef0f929..3bcdadd3d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java @@ -6,8 +6,6 @@ package org.hibernate.graph; import jakarta.persistence.Subgraph; -import jakarta.persistence.metamodel.ManagedType; -import org.hibernate.Incubating; import org.hibernate.metamodel.model.domain.PersistentAttribute; import java.util.Map; @@ -38,6 +36,8 @@ import static java.util.Collections.unmodifiableMap; * @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. * + * @param The type of the {@linkplain #getAttributeDescriptor attribute} + * * @author Strong Liu * @author Steve Ebersole * @author Andrea Boriero @@ -99,23 +99,27 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr /** * Create and return a new value {@link SubGraph} rooted at this node, * or return an existing such {@link SubGraph} if there is one. - *

+ * + * @deprecated This operation is not properly type safe. * Note that {@code graph.addAttributeNode(att).makeSubGraph()} is a * synonym for {@code graph.addSubgraph(att)}. * * @see Graph#addSubgraph(jakarta.persistence.metamodel.Attribute) */ + @Deprecated(since = "7.0") 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. - *

+ * + * @deprecated This operation is not properly type safe. * Note that {@code graph.addAttributeNode(att).makeKeySubGraph()} is a * synonym for {@code graph.addMapKeySubgraph(att)}. * * @see Graph#addMapKeySubgraph(jakarta.persistence.metamodel.MapAttribute) */ + @Deprecated(since = "7.0") SubGraph makeKeySubGraph(); /** @@ -125,7 +129,8 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr *

* If the given type is a proper subtype of the value type, the result * is a treated subgraph. - *

+ * + * @deprecated This operation is not properly type safe. * Note that {@code graph.addAttributeNode(att).makeSubGraph(cl)} * is a synonym for {@code graph.addTreatedSubgraph(att,cl)}. * @@ -133,6 +138,7 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr * * @see Graph#addTreatedSubgraph(jakarta.persistence.metamodel.Attribute, Class) */ + @Deprecated(since = "7.0") SubGraph makeSubGraph(Class subtype); /** @@ -142,7 +148,8 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr *

* If the given type is a proper subtype of the key type, the result * is a treated subgraph. - *

+ * + * @deprecated This operation is not properly type safe. * Note that {@code graph.addAttributeNode(att).makeKeySubGraph(cl)} * is a synonym for {@code graph.addTreatedMapKeySubgraph(att,cl)}. * @@ -150,35 +157,6 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr * * @see Graph#addTreatedMapKeySubgraph(jakarta.persistence.metamodel.MapAttribute,Class) */ + @Deprecated(since = "7.0") 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. - *

- * If the given type is a proper subtype of the value type, the result - * is a treated subgraph. - * - * @param subtype The type or treated type of the value type - * - * @since 7.0 - */ - @Incubating - SubGraph makeSubGraph(ManagedType 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. - *

- * If the given type is a proper subtype of the key type, the result - * is a treated subgraph. - * - * @param subtype The type or treated type of the key type - * - * @since 7.0 - */ - @Incubating - SubGraph makeKeySubGraph(ManagedType 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 a1db88d16d..f356be84d3 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java @@ -176,9 +176,7 @@ public interface Graph extends GraphNode, jakarta.persistence.Graph { * @param attributeName The name of an attribute of the represented type */ @Override - default SubGraph addSubgraph(String attributeName) { - return addSubGraph( attributeName ); - } + SubGraph addSubgraph(String attributeName); /** * Create and return a new (mutable) {@link SubGraph} associated with 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 fef40f45ca..229a20c6ab 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,18 +4,25 @@ */ package org.hibernate.graph.internal; -import jakarta.persistence.metamodel.ManagedType; +import jakarta.persistence.metamodel.Attribute; import org.hibernate.graph.CannotContainSubGraphException; import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType; +import org.hibernate.metamodel.model.domain.MapPersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute; +import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; import org.hibernate.metamodel.model.domain.SimpleDomainType; import java.util.HashMap; import java.util.Map; +import static jakarta.persistence.metamodel.Attribute.PersistentAttributeType.EMBEDDED; +import static jakarta.persistence.metamodel.Attribute.PersistentAttributeType.MANY_TO_MANY; +import static jakarta.persistence.metamodel.Attribute.PersistentAttributeType.MANY_TO_ONE; +import static jakarta.persistence.metamodel.Attribute.PersistentAttributeType.ONE_TO_MANY; +import static jakarta.persistence.metamodel.Attribute.PersistentAttributeType.ONE_TO_ONE; import static java.util.Collections.emptyMap; @@ -25,30 +32,38 @@ import static java.util.Collections.emptyMap; * @author Steve Ebersole * @author Gavin King */ -public class AttributeNodeImpl +public class AttributeNodeImpl extends AbstractGraphNode - implements AttributeNodeImplementor { + implements AttributeNodeImplementor { private final PersistentAttribute attribute; - private final DomainType valueGraphType; + private final DomainType valueGraphType; private final SimpleDomainType keyGraphType; - private SubGraphImplementor valueSubgraph; + private SubGraphImplementor valueSubgraph; private SubGraphImplementor keySubgraph; static AttributeNodeImpl create(PersistentAttribute attribute, boolean mutable) { return new AttributeNodeImpl<>( attribute, mutable, attribute.getValueGraphType(), attribute.getKeyGraphType() ); } + static AttributeNodeImpl create(PluralPersistentAttribute attribute, boolean mutable) { + return new AttributeNodeImpl<>( attribute, mutable, attribute.getValueGraphType(), attribute.getKeyGraphType() ); + } + + static AttributeNodeImpl,V,K> create(MapPersistentAttribute attribute, boolean mutable) { + return new AttributeNodeImpl<>( attribute, mutable, attribute.getValueGraphType(), attribute.getKeyGraphType() ); + } + private AttributeNodeImpl( PersistentAttribute attribute, boolean mutable, - DomainType valueGraphType, SimpleDomainType keyGraphType) { + DomainType valueGraphType, SimpleDomainType keyGraphType) { super( mutable ); this.attribute = attribute; this.valueGraphType = valueGraphType; this.keyGraphType = keyGraphType; } - private AttributeNodeImpl(AttributeNodeImpl that, boolean mutable) { + private AttributeNodeImpl(AttributeNodeImpl that, boolean mutable) { super( mutable ); attribute = that.attribute; valueGraphType = that.valueGraphType; @@ -68,18 +83,8 @@ public class AttributeNodeImpl } @Override - public SubGraphImplementor getSubGraph() { - return valueSubgraph; - } - - @Override - public SubGraphImplementor getKeySubGraph() { - return keySubgraph; - } - - @Override - public SubGraphImplementor makeSubGraph() { - verifyMutability(); + public SubGraphImplementor addValueSubgraph() { + // this one is intentionally lenient and disfavored if ( valueSubgraph == null ) { valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true ); } @@ -87,33 +92,72 @@ public class AttributeNodeImpl } @Override + public SubGraphImplementor addSingularSubgraph() { + checkToOne(); + if ( valueSubgraph == null ) { + valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true ); + } + // Safe cast, in this case E = J + // TODO: would be more elegant to separate singularSubgraph vs elementSubgraph fields + //noinspection unchecked + return (SubGraphImplementor) valueSubgraph; + } + + @Override + public SubGraphImplementor addElementSubgraph() { + checkToMany(); + if ( valueSubgraph == null ) { + valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true ); + } + return valueSubgraph; + } + + @Override + public SubGraphImplementor addKeySubgraph() { + checkMap(); + if ( keySubgraph == null ) { + keySubgraph = new SubGraphImpl<>( asManagedType( keyGraphType ), true ); + } + return keySubgraph; + } + + private void checkToOne() { + final Attribute.PersistentAttributeType attributeType = attribute.getPersistentAttributeType(); + if ( attributeType != MANY_TO_ONE && attributeType != ONE_TO_ONE && attributeType != EMBEDDED ) { + throw new CannotContainSubGraphException( "Attribute '" + attribute.getName() + "' is not a to-one association" ); + } + } + + private void checkToMany() { + final Attribute.PersistentAttributeType attributeType = attribute.getPersistentAttributeType(); + if ( attributeType != MANY_TO_MANY && attributeType != ONE_TO_MANY ) { + throw new CannotContainSubGraphException( "Attribute '" + attribute.getName() + "' is not a to-many association" ); + } + } + + @Override @Deprecated + public SubGraphImplementor makeSubGraph() { + verifyMutability(); + if ( valueSubgraph == null ) { + valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true ); + } + return valueSubgraph; + } + + @Override @Deprecated public SubGraphImplementor makeSubGraph(Class subtype) { - final ManagedDomainType managedType = asManagedType( valueGraphType ); + 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 ); + final Class castSuptype = (Class) subtype; + final SubGraphImplementor result = makeSubGraph().addTreatedSubgraph( castSuptype ); //noinspection unchecked return (SubGraphImplementor) result; } - @Override - public SubGraphImplementor makeSubGraph(ManagedType subtype) { - final ManagedDomainType managedType = asManagedType( valueGraphType ); - final Class javaType = subtype.getJavaType(); - 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; - } - - @Override + @Override @Deprecated public SubGraphImplementor makeKeySubGraph() { verifyMutability(); checkMap(); @@ -123,7 +167,7 @@ public class AttributeNodeImpl return keySubgraph; } - @Override + @Override @Deprecated public SubGraphImplementor makeKeySubGraph(Class subtype) { checkMap(); final ManagedDomainType type = asManagedType( keyGraphType ); @@ -137,21 +181,6 @@ public class AttributeNodeImpl return (SubGraphImplementor) result; } - @Override - public SubGraphImplementor makeKeySubGraph(ManagedType subtype) { - checkMap(); - final ManagedDomainType type = asManagedType( keyGraphType ); - final Class javaType = subtype.getJavaType(); - 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; - } - private void checkMap() { if ( keyGraphType == null ) { throw new CannotContainSubGraphException( "Attribute '" + description() + "' is not a Map" ); @@ -179,16 +208,16 @@ public class AttributeNodeImpl } @Override - public AttributeNodeImplementor makeCopy(boolean mutable) { + public AttributeNodeImplementor makeCopy(boolean mutable) { return !mutable && !isMutable() ? this : new AttributeNodeImpl<>( this, mutable ); } @Override - public void merge(AttributeNodeImplementor other) { + public void merge(AttributeNodeImplementor other) { assert other.isMutable() == isMutable(); assert other.getAttributeDescriptor() == attribute; - final AttributeNodeImpl that = (AttributeNodeImpl) other; - final SubGraphImplementor otherValueSubgraph = that.valueSubgraph; + final AttributeNodeImpl that = (AttributeNodeImpl) other; + final SubGraphImplementor otherValueSubgraph = that.valueSubgraph; if ( otherValueSubgraph != null ) { if ( valueSubgraph == null ) { valueSubgraph = otherValueSubgraph.makeCopy( isMutable() ); @@ -216,7 +245,7 @@ public class AttributeNodeImpl return emptyMap(); } else { - final HashMap, SubGraphImplementor> map = new HashMap<>( valueSubgraph.getSubGraphs() ); + final HashMap, SubGraphImplementor> map = new HashMap<>( valueSubgraph.getTreatedSubgraphs() ); map.put( attribute.getValueGraphType().getBindableJavaType(), valueSubgraph ); return map; } @@ -228,7 +257,7 @@ public class AttributeNodeImpl return emptyMap(); } else { - final HashMap, SubGraphImplementor> map = new HashMap<>( keySubgraph.getSubGraphs() ); + final HashMap, SubGraphImplementor> map = new HashMap<>( keySubgraph.getTreatedSubgraphs() ); map.put( attribute.getKeyGraphType().getJavaType(), keySubgraph ); return map; } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/GraphImpl.java similarity index 62% rename from hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java rename to hibernate-core/src/main/java/org/hibernate/graph/internal/GraphImpl.java index 0d8d2d8b49..95ff3b94ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/GraphImpl.java @@ -22,6 +22,7 @@ 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.DomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.MapPersistentAttribute; @@ -41,28 +42,28 @@ import static java.util.Collections.unmodifiableMap; * @author Steve Ebersole * @author Gavin King */ -public abstract class AbstractGraph extends AbstractGraphNode implements GraphImplementor { +public abstract class GraphImpl extends AbstractGraphNode implements GraphImplementor { private final ManagedDomainType managedType; private Map, SubGraphImplementor> treatedSubgraphs; - private Map, AttributeNodeImplementor> attributeNodes; + private Map, AttributeNodeImplementor> attributeNodes; - public AbstractGraph(ManagedDomainType managedType, boolean mutable) { + public GraphImpl(ManagedDomainType managedType, boolean mutable) { super( mutable ); this.managedType = managedType; } - protected AbstractGraph(ManagedDomainType managedType, GraphImplementor graph, boolean mutable) { + protected GraphImpl(ManagedDomainType managedType, GraphImplementor graph, boolean mutable) { super( mutable ); this.managedType = managedType; var attributeNodesByAttribute = graph.getNodes(); - var subGraphMap = graph.getSubGraphs(); + var subGraphMap = graph.getTreatedSubgraphs(); attributeNodes = attributeNodesByAttribute.isEmpty() ? null : new HashMap<>( attributeNodesByAttribute.size() ); treatedSubgraphs = subGraphMap.isEmpty() ? null : new HashMap<>( subGraphMap.size() ); mergeInternal( graph ); } - protected AbstractGraph(GraphImplementor graph, boolean mutable) { + protected GraphImpl(GraphImplementor graph, boolean mutable) { this( graph.getGraphedType(), graph, mutable ); } @@ -77,8 +78,18 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G } @SuppressWarnings("unchecked") - private AttributeNodeImplementor getNode(PersistentAttribute attribute) { - return attributeNodes == null ? null : (AttributeNodeImplementor) attributeNodes.get( attribute ); + private AttributeNodeImplementor getNode(PersistentAttribute attribute) { + return attributeNodes == null ? null : (AttributeNodeImplementor) attributeNodes.get( attribute ); + } + + @SuppressWarnings("unchecked") + private AttributeNodeImplementor getNode(PluralPersistentAttribute attribute) { + return attributeNodes == null ? null : (AttributeNodeImplementor) attributeNodes.get( attribute ); + } + + @SuppressWarnings("unchecked") + private AttributeNodeImplementor, V, K> getNode(MapPersistentAttribute attribute) { + return attributeNodes == null ? null : (AttributeNodeImplementor, V, K>) attributeNodes.get( attribute ); } private SubGraphImplementor getTreatedSubgraphForPut(Class javaType) { @@ -91,7 +102,27 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G } } - private AttributeNodeImplementor getNodeForPut(PersistentAttribute attribute) { + private AttributeNodeImplementor getNodeForPut(PersistentAttribute attribute) { + if ( attributeNodes == null ) { + attributeNodes = new HashMap<>(); + return null; + } + else { + return getNode( attribute ); + } + } + + private AttributeNodeImplementor getNodeForPut(PluralPersistentAttribute attribute) { + if ( attributeNodes == null ) { + attributeNodes = new HashMap<>(); + return null; + } + else { + return getNode( attribute ); + } + } + + private AttributeNodeImplementor, V, K> getNodeForPut(MapPersistentAttribute attribute) { if ( attributeNodes == null ) { attributeNodes = new HashMap<>(); return null; @@ -124,11 +155,11 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G public void mergeInternal(GraphImplementor graph) { // skip verifyMutability() graph.getNodes().forEach( this::mergeNode ); - graph.getSubGraphs().values().forEach( this::mergeGraph ); + graph.getTreatedSubgraphs().values().forEach( this::mergeGraph ); } - private void mergeNode(PersistentAttribute attribute, AttributeNodeImplementor node) { - final AttributeNodeImplementor existingNode = getNodeForPut( attribute ); + private void mergeNode(PersistentAttribute attribute, AttributeNodeImplementor node) { + final AttributeNodeImplementor existingNode = getNodeForPut( attribute ); if ( existingNode == null ) { attributeNodes.put( attribute, node.makeCopy( isMutable() ) ); } @@ -150,11 +181,11 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G } } - private static void mergeNode( - AttributeNodeImplementor node, AttributeNodeImplementor existingNode) { + private static void mergeNode( + AttributeNodeImplementor node, AttributeNodeImplementor existingNode) { if ( existingNode.getAttributeDescriptor() == node.getAttributeDescriptor() ) { @SuppressWarnings("unchecked") // safe, we just checked - final AttributeNodeImplementor castNode = (AttributeNodeImplementor) node; + final AttributeNodeImplementor castNode = (AttributeNodeImplementor) node; existingNode.merge( castNode ); } else { @@ -163,19 +194,19 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G } @Override - public List> getAttributeNodeList() { + public List> getAttributeNodeList() { return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() ); } @Override - public AttributeNodeImplementor findAttributeNode(String attributeName) { + public AttributeNodeImplementor findAttributeNode(String 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 ); + final AttributeNodeImplementor node = attribute == null ? null : findAttributeNode( persistentAttribute ); if ( node == null && treatedSubgraphs != null ) { for ( SubGraphImplementor subgraph : treatedSubgraphs.values() ) { - final AttributeNodeImplementor subgraphNode = subgraph.findAttributeNode( attributeName ); + final AttributeNodeImplementor subgraphNode = subgraph.findAttributeNode( attributeName ); if ( subgraphNode != null ) { return subgraphNode; } @@ -188,32 +219,42 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G } @Override - public AttributeNodeImplementor findAttributeNode(PersistentAttribute attribute) { + public AttributeNodeImplementor getAttributeNode(String attributeName) { + return findAttributeNode( attributeName ); + } + + @Override + public AttributeNodeImplementor findAttributeNode(PersistentAttribute attribute) { return getNode( attribute ); } + @Override + public AttributeNodeImplementor getAttributeNode(Attribute attribute) { + return getNode( (PersistentAttribute) attribute ); + } + @Override public List> getAttributeNodes() { return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() ); } @Override - public Map, AttributeNodeImplementor> getNodes() { + public Map, AttributeNodeImplementor> getNodes() { return attributeNodes == null ? emptyMap() : unmodifiableMap( attributeNodes ); } @Override - public AttributeNodeImplementor addAttributeNode(String attributeName) { + public AttributeNodeImplementor addAttributeNode(String attributeName) { return findOrCreateAttributeNode( attributeName ); } @Override - public AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute) { + public AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute) { return findOrCreateAttributeNode( attribute ); } @Override - public AttributeNodeImplementor addAttributeNode(Attribute attribute) { + public AttributeNodeImplementor addAttributeNode(Attribute attribute) { return addAttributeNode( (PersistentAttribute) attribute ); } @@ -250,11 +291,37 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G } @Override - public AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute) { + public AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute) { verifyMutability(); - final AttributeNodeImplementor node = getNodeForPut( attribute ); + final AttributeNodeImplementor node = getNodeForPut( attribute ); if ( node == null ) { - final AttributeNodeImplementor newAttrNode = AttributeNodeImpl.create( attribute, isMutable() ); + final AttributeNodeImplementor newAttrNode = AttributeNodeImpl.create( attribute, isMutable() ); + attributeNodes.put( attribute, newAttrNode ); + return newAttrNode; + } + else { + return node; + } + } + + private AttributeNodeImplementor findOrCreateAttributeNode(PluralPersistentAttribute 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; + } + } + + private AttributeNodeImplementor,V,K> findOrCreateAttributeNode(MapPersistentAttribute attribute) { + verifyMutability(); + final AttributeNodeImplementor,V,K> node = getNodeForPut( attribute ); + if ( node == null ) { + final AttributeNodeImplementor,V,K> newAttrNode = AttributeNodeImpl.create( attribute, isMutable() ); attributeNodes.put( attribute, newAttrNode ); return newAttrNode; } @@ -264,7 +331,7 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G } @Override - public AttributeNodeImplementor findOrCreateAttributeNode(String attributeName) { + public AttributeNodeImplementor findOrCreateAttributeNode(String attributeName) { final PersistentAttribute attribute = getAttribute( attributeName ); @SuppressWarnings("unchecked") // The JPA API is unsafe by nature final PersistentAttribute persistentAttribute = (PersistentAttribute) attribute; @@ -285,66 +352,105 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G : attribute; } + @Override @SuppressWarnings("unchecked") // The JPA API is unsafe by nature + public SubGraphImplementor addSubgraph(String attributeName) { + return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).addValueSubgraph(); + } + + @Override + public SubGraphImplementor addSubgraph(String attributeName, Class type) { + return addSubgraph( attributeName ).addTreatedSubgraph( type ); + } + + @Override + public SubGraphImplementor addSubgraph(Attribute attribute) { + return findOrCreateAttributeNode( (PersistentAttribute) attribute ).addSingularSubgraph(); + } + @Override - @SuppressWarnings("unchecked") // The API is unsafe by nature public SubGraphImplementor addSubGraph(String attributeName) { - return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeSubGraph(); + return addSubgraph( attributeName ); } @Override public SubGraphImplementor addSubGraph(String attributeName, Class subtype) { - return findOrCreateAttributeNode( attributeName ).makeSubGraph( subtype ); + return addSubGraph( attributeName ).addTreatedSubgraph( subtype ); } @Override public SubGraphImplementor addSubGraph(PersistentAttribute attribute) { - return findOrCreateAttributeNode( attribute ).makeSubGraph( attribute.getJavaType() ); + return addSubgraph( attribute ); } @Override public SubGraphImplementor addSubGraph(PersistentAttribute attribute, Class subtype) { - return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype ); + return addTreatedSubgraph( attribute, subtype ); } @Override - public SubGraphImplementor addTreatedSubgraph(PersistentAttribute attribute, ManagedType subtype) { - return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype ); + public SubGraphImplementor addTreatedSubgraph(Attribute attribute, ManagedType type) { + return addSubgraph( attribute ).addTreatedSubgraph( type ); + } + + @Override @SuppressWarnings("unchecked") // The JPA API is unsafe by nature + public SubGraphImplementor addElementSubgraph(String attributeName) { + return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).addElementSubgraph(); } @Override - public SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, Class type) { - return findOrCreateAttributeNode( attribute ).makeSubGraph( type ); + public SubGraphImplementor addElementSubgraph(String attributeName, Class type) { + return addElementSubgraph( attributeName ).addTreatedSubgraph( type ); } @Override - public SubGraphImplementor addTreatedElementSubgraph(PluralPersistentAttribute attribute, ManagedType type) { - return findOrCreateAttributeNode( attribute ).makeSubGraph( type ); + public SubGraphImplementor addElementSubgraph(PluralAttribute attribute) { + return findOrCreateAttributeNode( (PluralPersistentAttribute) attribute ).addElementSubgraph(); } @Override - public SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, Class subtype) { - return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subtype ); + public SubGraphImplementor addTreatedElementSubgraph(PluralAttribute attribute, Class type) { + return addElementSubgraph( attribute ).addTreatedSubgraph( type ); } @Override - public SubGraphImplementor addTreatedMapKeySubgraph(MapPersistentAttribute attribute, ManagedType subtype) { - return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subtype ); + public SubGraph addTreatedElementSubgraph(PluralAttribute attribute, ManagedType type) { + return addElementSubgraph( attribute ).addTreatedSubgraph( type ); } @Override @SuppressWarnings("unchecked") // The API is unsafe by nature + public SubGraphImplementor addKeySubgraph(String attributeName) { + return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).addKeySubgraph(); + } + + @Override + public SubGraphImplementor addKeySubgraph(String attributeName, Class type) { + return addKeySubgraph( attributeName ).addTreatedSubgraph( type ); + } + + @Override public SubGraphImplementor addKeySubGraph(String attributeName) { - return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeKeySubGraph(); + return addKeySubgraph( attributeName ); } @Override public SubGraphImplementor addKeySubGraph(String attributeName, Class subtype) { - return findOrCreateAttributeNode( attributeName ).makeKeySubGraph( subtype ); + return addKeySubGraph( attributeName ).addTreatedSubgraph( subtype ); } @Override public SubGraphImplementor addMapKeySubgraph(MapAttribute attribute) { - return findOrCreateAttributeNode( attribute.getName() ).makeKeySubGraph( attribute.getKeyJavaType() ); + return findOrCreateAttributeNode( (MapPersistentAttribute) attribute ).addKeySubgraph(); + } + + @Override + public SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, Class subtype) { + return addTreatedMapKeySubgraph( attribute, subtype ); + } + + @Override + public SubGraphImplementor addTreatedMapKeySubgraph(MapAttribute attribute, ManagedType type) { + return addMapKeySubgraph( attribute ).addTreatedSubgraph( type ); } @Override @@ -354,29 +460,6 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G 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(Attribute attribute, Class type) { return addSubgraph( attribute ).addTreatedSubgraph( type ); @@ -409,7 +492,7 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G } @Override - public Map, SubGraphImplementor> getSubGraphs() { + public Map, SubGraphImplementor> getTreatedSubgraphs() { return treatedSubgraphs == null ? emptyMap() : unmodifiableMap( treatedSubgraphs ); } @@ -423,6 +506,16 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G } } + private ManagedDomainType asManagedType(DomainType domainType) { + if ( domainType instanceof ManagedDomainType managedDomainType ) { + return managedDomainType; + } + else { + throw new CannotContainSubGraphException( "Attribute is of type '" + domainType.getTypeName() + + "' which is not a managed type" ); + } + } + @Override public String toString() { final StringBuilder builder = new StringBuilder( "Graph[" ).append( managedType.getTypeName() ); 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 2e8965910b..fb34bc78db 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 @@ -16,7 +16,7 @@ import org.hibernate.metamodel.model.domain.EntityDomainType; * * @author Steve Ebersole */ -public class RootGraphImpl extends AbstractGraph implements RootGraphImplementor { +public class RootGraphImpl extends GraphImpl implements RootGraphImplementor { private final String name; 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 339ecbe359..82170ad1f0 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 @@ -12,13 +12,13 @@ import org.hibernate.metamodel.model.domain.ManagedDomainType; * * @author Steve Ebersole */ -public class SubGraphImpl extends AbstractGraph implements SubGraphImplementor { +public class SubGraphImpl extends GraphImpl implements SubGraphImplementor { public SubGraphImpl(ManagedDomainType managedType, boolean mutable) { super( managedType, mutable ); } - public SubGraphImpl(AbstractGraph original, boolean mutable) { + public SubGraphImpl(GraphImpl original, boolean mutable) { super( original, mutable ); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java index 5697f5bd3d..e3873f9a04 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java @@ -167,7 +167,7 @@ public class GraphParser extends GraphLanguageParserBaseVisitor { ); } - final AttributeNodeImplementor attributeNode = attributeNodeStack.getCurrent(); + final AttributeNodeImplementor attributeNode = attributeNodeStack.getCurrent(); final SubGraphGenerator subGraphCreator = graphSourceStack.getCurrent(); final SubGraphImplementor subGraph = subGraphCreator.createSubGraph( 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 5d2f7e12ad..b1b6a1dfbd 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 @@ -15,23 +15,23 @@ import org.hibernate.metamodel.model.domain.ManagedDomainType; public enum PathQualifierType { KEY( (attributeNode, subtypeName, sessionFactory) -> subtypeName == null - ? attributeNode.makeKeySubGraph() - : attributeNode.makeKeySubGraph( getSubtype( subtypeName, sessionFactory ) ) + ? attributeNode.addKeySubgraph() + : attributeNode.addKeySubgraph().addTreatedSubgraph( managedType( subtypeName, sessionFactory ) ) ), VALUE( (attributeNode, subtypeName, sessionFactory) -> subtypeName == null - ? attributeNode.makeSubGraph() - : attributeNode.makeSubGraph( getSubtype( subtypeName, sessionFactory ) ) + ? attributeNode.addValueSubgraph() + : attributeNode.addValueSubgraph().addTreatedSubgraph( managedType( subtypeName, sessionFactory ) ) ); - private static ManagedDomainType getSubtype(String subtypeName, SessionFactoryImplementor sessionFactory) { + private static ManagedDomainType managedType(String subtypeName, SessionFactoryImplementor sessionFactory) { final JpaMetamodel metamodel = sessionFactory.getJpaMetamodel(); - ManagedDomainType managedType = metamodel.findManagedType( subtypeName ); + ManagedDomainType managedType = metamodel.findManagedType( subtypeName ); if ( managedType == null ) { managedType = metamodel.getHqlEntityReference( subtypeName ); } if ( managedType == null ) { - throw new IllegalArgumentException( "Unknown type " + subtypeName ); + throw new IllegalArgumentException( "Unknown managed type: " + subtypeName ); } return managedType; } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/SubGraphGenerator.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/SubGraphGenerator.java index 094858dcfa..f19aa465e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/SubGraphGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/SubGraphGenerator.java @@ -14,7 +14,7 @@ import org.hibernate.graph.spi.SubGraphImplementor; @FunctionalInterface public interface SubGraphGenerator { SubGraphImplementor createSubGraph( - AttributeNodeImplementor attributeNode, + AttributeNodeImplementor attributeNode, String subTypeName, SessionFactoryImplementor sessionFactory); } 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 9a1a096679..9f69612262 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,46 +4,66 @@ */ package org.hibernate.graph.spi; -import jakarta.persistence.metamodel.ManagedType; import org.hibernate.graph.AttributeNode; import java.util.Map; /** - * Integration version of the {@link AttributeNode} contract + * Integration version of the {@link AttributeNode} contract. + * + * @param The type of the attribute + * @param The element type, if this node represents a + * {@linkplain jakarta.persistence.metamodel.PluralAttribute plural attribute} + * @param The map key type, if this node represents a + * {@linkplain jakarta.persistence.metamodel.MapAttribute map attribute} * * @author Strong Liu * @author Steve Ebersole + * @author Gavin King */ -public interface AttributeNodeImplementor extends AttributeNode, GraphNodeImplementor { +public interface AttributeNodeImplementor extends AttributeNode, GraphNodeImplementor { @Override - AttributeNodeImplementor makeCopy(boolean mutable); + AttributeNodeImplementor makeCopy(boolean mutable); - @Override + /** + * Create a value subgraph, without knowing whether it represents a singular value or + * plural element, rooted at this attribute node. + * + * @apiNote This version is more lenient and is therefore disfavored. Prefer the use + * of {@link #addSingularSubgraph()} and {@link #addElementSubgraph()}. + */ + SubGraphImplementor addValueSubgraph(); + + /** + * Create a value subgraph representing a singular value rooted at this attribute node. + */ + SubGraphImplementor addSingularSubgraph(); + + /** + * Create a value subgraph representing a plural element rooted at this attribute node. + */ + SubGraphImplementor addElementSubgraph(); + + /** + * Create a key subgraph rooted at this attribute node. + */ + SubGraphImplementor addKeySubgraph(); + + @Override @Deprecated SubGraphImplementor makeSubGraph(); - @Override + @Override @Deprecated SubGraphImplementor makeKeySubGraph(); - @Override + @Override @Deprecated SubGraphImplementor makeSubGraph(Class subtype); - @Override + @Override @Deprecated SubGraphImplementor makeKeySubGraph(Class subtype); - @Override - SubGraphImplementor makeSubGraph(ManagedType subtype); - - @Override - SubGraphImplementor makeKeySubGraph(ManagedType subtype); - - void merge(AttributeNodeImplementor other); - - SubGraphImplementor getSubGraph(); - - SubGraphImplementor getKeySubGraph(); + void merge(AttributeNodeImplementor other); @Override Map, SubGraphImplementor> getSubGraphs(); 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 b1d6be723b..95e1a2cc92 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 @@ -11,22 +11,20 @@ import jakarta.persistence.metamodel.Attribute; import jakarta.persistence.metamodel.ManagedType; import jakarta.persistence.metamodel.MapAttribute; import jakarta.persistence.metamodel.PluralAttribute; -import org.hibernate.Incubating; import org.hibernate.Internal; -import org.hibernate.graph.AttributeNode; import org.hibernate.graph.Graph; import org.hibernate.graph.SubGraph; import org.hibernate.metamodel.model.domain.MapPersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute; -import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; /** - * Integration version of the {@link Graph} contract + * Integration version of the {@link Graph} contract. * * @author Strong Liu * @author Steve Ebersole * @author Andrea Boriero + * @author Gavin King */ public interface GraphImplementor extends Graph, GraphNodeImplementor { @@ -47,21 +45,40 @@ public interface GraphImplementor extends Graph, GraphNodeImplementor { GraphImplementor makeCopy(boolean mutable); @Override - List> getAttributeNodeList(); + List> getAttributeNodeList(); - Map, AttributeNodeImplementor> getNodes(); + Map, AttributeNodeImplementor> getNodes(); + + Map, SubGraphImplementor> getTreatedSubgraphs(); @Override - AttributeNodeImplementor findAttributeNode(String attributeName); + AttributeNodeImplementor getAttributeNode(String attributeName); @Override - AttributeNodeImplementor findAttributeNode(PersistentAttribute attribute); + AttributeNodeImplementor getAttributeNode(Attribute attribute); - AttributeNodeImplementor findOrCreateAttributeNode(String name); + @Override + AttributeNodeImplementor findAttributeNode(String attributeName); - AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute); + @Override + AttributeNodeImplementor findAttributeNode(PersistentAttribute attribute); - AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute); + AttributeNodeImplementor findOrCreateAttributeNode(String name); + + AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute); + + AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute); + + @Override + AttributeNodeImplementor addAttributeNode(Attribute attribute); + + @Override + SubGraphImplementor addTreatedSubgraph(Class type); + + SubGraphImplementor addTreatedSubgraph(ManagedType type); + + @Override + SubGraphImplementor addSubgraph(String attributeName); @Override SubGraphImplementor addSubGraph(String attributeName); @@ -75,14 +92,6 @@ public interface GraphImplementor extends Graph, GraphNodeImplementor { @Override SubGraphImplementor addSubGraph(PersistentAttribute attribute, Class subtype); - SubGraphImplementor addTreatedSubgraph(PersistentAttribute attribute, ManagedType subtype); - - @Incubating - SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, Class type); - - @Incubating - SubGraphImplementor addTreatedElementSubgraph(PluralPersistentAttribute attribute, ManagedType type); - @Override SubGraphImplementor addKeySubGraph(String attributeName); @@ -92,79 +101,35 @@ public interface GraphImplementor extends Graph, GraphNodeImplementor { @Override SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, Class subtype); - SubGraphImplementor addTreatedMapKeySubgraph(MapPersistentAttribute attribute, ManagedType subtype); + @Override + SubGraphImplementor addSubgraph(String attributeName, Class type); @Override - SubGraphImplementor addTreatedSubgraph(Class type); - - SubGraphImplementor addTreatedSubgraph(ManagedType type); - - Map, SubGraphImplementor> getSubGraphs(); + SubGraphImplementor addSubgraph(Attribute attribute); @Override - default AttributeNode getAttributeNode(String attributeName) { - return findAttributeNode( attributeName ); - } + SubGraphImplementor addTreatedSubgraph(Attribute attribute, Class type); @Override - default AttributeNode getAttributeNode(Attribute attribute) { - return findAttributeNode( (PersistentAttribute) attribute ); - } + SubGraphImplementor addTreatedSubgraph(Attribute attribute, ManagedType type); @Override - default AttributeNode addAttributeNode(Attribute attribute) { - return addAttributeNode( (PersistentAttribute) attribute ); - } + SubGraphImplementor addTreatedElementSubgraph(PluralAttribute attribute, Class type); @Override - default SubGraphImplementor addSubgraph(String attributeName, Class type) { - return addSubGraph( attributeName ).addTreatedSubgraph( type ); - } + SubGraph addTreatedElementSubgraph(PluralAttribute attribute, ManagedType type); @Override - default SubGraphImplementor addSubgraph(Attribute attribute) { - return addSubGraph( (PersistentAttribute) attribute ); - } + SubGraphImplementor addKeySubgraph(String attributeName); @Override - default SubGraphImplementor addTreatedSubgraph(Attribute attribute, Class type) { - return addSubGraph( (PersistentAttribute) attribute ).addTreatedSubgraph( type ); - } + SubGraphImplementor addKeySubgraph(String attributeName, Class type); @Override - default SubGraph addTreatedSubgraph(Attribute attribute, ManagedType type) { - return addSubGraph( (PersistentAttribute) attribute ).addTreatedSubgraph( type ); - } + SubGraphImplementor addTreatedMapKeySubgraph(MapAttribute attribute, Class type); @Override - default SubGraphImplementor addTreatedElementSubgraph(PluralAttribute attribute, Class type) { - return addElementSubGraph( (PluralPersistentAttribute) attribute, type ); - } - - @Override - default SubGraph addTreatedElementSubgraph(PluralAttribute attribute, ManagedType type) { - return addTreatedElementSubgraph( (PluralPersistentAttribute) attribute, type ); - } - - @Override - default SubGraphImplementor addKeySubgraph(String attributeName) { - return addKeySubGraph( attributeName ); - } - - @Override - default SubGraphImplementor addKeySubgraph(String attributeName, Class type) { - return addKeySubGraph( attributeName ).addTreatedSubgraph( type ); - } - - @Override - default SubGraphImplementor addTreatedMapKeySubgraph(MapAttribute attribute, Class type) { - return addKeySubGraph( (MapPersistentAttribute) attribute, type ); - } - - @Override - default SubGraph addTreatedMapKeySubgraph(MapAttribute attribute, ManagedType type) { - return addTreatedMapKeySubgraph( (MapPersistentAttribute) attribute, type ); - } + SubGraphImplementor addTreatedMapKeySubgraph(MapAttribute attribute, ManagedType type); @Override default boolean hasAttributeNode(String attributeName) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/MapPersistentAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/MapPersistentAttribute.java index 71fa8f5266..fc1270d5d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/MapPersistentAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/MapPersistentAttribute.java @@ -19,4 +19,7 @@ public interface MapPersistentAttribute extends MapAttribute, Pl @Override SimpleDomainType getKeyType(); + + @Override + SimpleDomainType getKeyGraphType(); } 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 13359f6845..6da10dc697 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 @@ -561,8 +561,8 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable { GraphImplementor graphNode) { for ( NamedAttributeNode namedAttributeNode : namedAttributeNodes ) { final String value = namedAttributeNode.value(); - final AttributeNodeImplementor attributeNode = - (AttributeNodeImplementor) graphNode.addAttributeNode( value ); + final AttributeNodeImplementor attributeNode = + (AttributeNodeImplementor) graphNode.addAttributeNode( value ); if ( isNotEmpty( namedAttributeNode.subgraph() ) ) { applyNamedSubgraphs( @@ -583,36 +583,52 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable { } } - private void applyNamedSubgraphs( + private void applyNamedSubgraphs( NamedEntityGraph namedEntityGraph, String subgraphName, - AttributeNodeImplementor attributeNode, + AttributeNodeImplementor attributeNode, boolean isKeySubGraph) { for ( NamedSubgraph namedSubgraph : namedEntityGraph.subgraphs() ) { if ( subgraphName.equals( namedSubgraph.name() ) ) { - final boolean isDefaultSubgraphType = namedSubgraph.type().equals( void.class ); - final Class subGraphType = isDefaultSubgraphType ? null : namedSubgraph.type(); - final SubGraphImplementor subgraph = - makeAttributeNodeSubgraph( attributeNode, isKeySubGraph, subGraphType ); + final Class subgraphType = namedSubgraph.type(); + final SubGraphImplementor subgraph; + if ( subgraphType.equals( void.class ) ) { // unspecified + subgraph = attributeNode.addValueSubgraph(); + } + else { + subgraph = isKeySubGraph + ? makeAttributeNodeKeySubgraph( attributeNode, subgraphType ) + : makeAttributeNodeValueSubgraph( attributeNode, subgraphType ); + } applyNamedAttributeNodes( namedSubgraph.attributeNodes(), namedEntityGraph, subgraph ); } } } - private static SubGraphImplementor makeAttributeNodeSubgraph( - AttributeNodeImplementor attributeNode, - boolean isKeySubGraph, - Class subGraphType) { - if ( isKeySubGraph ) { - return subGraphType != null - ? attributeNode.makeKeySubGraph( subGraphType ) - : attributeNode.makeKeySubGraph(); + private static SubGraphImplementor makeAttributeNodeValueSubgraph( + AttributeNodeImplementor attributeNode, Class subgraphType) { + final Class attributeValueType = + attributeNode.getAttributeDescriptor().getValueGraphType().getBindableJavaType(); + if ( !attributeValueType.isAssignableFrom( subgraphType ) ) { + throw new AnnotationException( "Named subgraph type '" + subgraphType.getName() + + "' is not a subtype of the value type '" + attributeValueType.getName() + "'" ); } - else { - return subGraphType != null - ? attributeNode.makeSubGraph( subGraphType ) - : attributeNode.makeSubGraph(); + @SuppressWarnings("unchecked") // Safe, because we just checked + final Class castType = (Class) subgraphType; + return attributeNode.addValueSubgraph().addTreatedSubgraph( castType ); + } + + private static SubGraphImplementor makeAttributeNodeKeySubgraph( + AttributeNodeImplementor attributeNode, Class subgraphType) { + final Class attributeKeyType = + attributeNode.getAttributeDescriptor().getKeyGraphType().getBindableJavaType(); + if ( !attributeKeyType.isAssignableFrom( subgraphType ) ) { + throw new AnnotationException( "Named subgraph type '" + subgraphType.getName() + + "' is not a subtype of the key type '" + attributeKeyType.getName() + "'" ); } + @SuppressWarnings("unchecked") // Safe, because we just checked + final Class castType = (Class) subgraphType; + return attributeNode.addKeySubgraph().addTreatedSubgraph( castType ); } private Class resolveRequestedClass(String entityName) { 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 e2f454738e..222f5b48d3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java @@ -26,7 +26,7 @@ public class AppliedGraphs { } private static boolean containsCollectionFetches(GraphImplementor graph) { - for ( AttributeNodeImplementor node : graph.getNodes().values() ) { + for ( AttributeNodeImplementor node : graph.getNodes().values() ) { if ( node.getAttributeDescriptor().isCollection() ) { return true; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java index d1499e2453..e7a622de83 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java @@ -260,9 +260,10 @@ public class EntityDelayedFetchInitializer private boolean isLazyByGraph(RowProcessingState rowProcessingState) { final AppliedGraph appliedGraph = rowProcessingState.getQueryOptions().getAppliedGraph(); if ( appliedGraph != null && appliedGraph.getSemantic() == GraphSemantic.FETCH ) { - final AttributeNodeImplementor attributeNode = appliedGraph.getGraph() - .findAttributeNode( navigablePath.getLocalName() ); - if ( attributeNode != null && attributeNode.getAttributeDescriptor() == getInitializedPart().asAttributeMapping() ) { + final AttributeNodeImplementor attributeNode = + appliedGraph.getGraph().findAttributeNode( navigablePath.getLocalName() ); + if ( attributeNode != null + && attributeNode.getAttributeDescriptor() == getInitializedPart().asAttributeMapping() ) { return false; } return true; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardEntityGraphTraversalStateImpl.java index b4831f0559..8cc7fcb994 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 @@ -55,7 +55,7 @@ public class StandardEntityGraphTraversalStateImpl implements EntityGraphTravers } final GraphImplementor previousContextRoot = currentGraphContext; - final AttributeNodeImplementor attributeNode = appliesTo( fetchParent ) + final AttributeNodeImplementor attributeNode = appliesTo( fetchParent ) ? currentGraphContext.findAttributeNode( fetchable.getFetchableName() ) : null; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java index 0b32ffea7c..0477bf5d07 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,11 +176,11 @@ public class EntityGraphParserTest extends AbstractEntityGraphTest { RootGraphImplementor graph = parseGraph( "linkToOne(name, description), linkToOne(GraphParsingTestSubEntity: sub)" ); assertNotNull( graph ); - List> attrs = graph.getAttributeNodeList(); + List> attrs = graph.getAttributeNodeList(); assertNotNull( attrs ); assertEquals( 1, attrs.size() ); - AttributeNodeImplementor linkToOneNode = attrs.get( 0 ); + AttributeNodeImplementor linkToOneNode = attrs.get( 0 ); assertNotNull( linkToOneNode ); assertEquals( "linkToOne", linkToOneNode.getAttributeName() ); @@ -204,7 +204,7 @@ public class EntityGraphParserTest extends AbstractEntityGraphTest { assertEquals( subGraph.getGraphedType().getJavaType(), GraphParsingTestSubEntity.class ); - final AttributeNodeImplementor subTypeAttrNode = subGraph.findOrCreateAttributeNode( "sub" ); + final AttributeNodeImplementor subTypeAttrNode = subGraph.findOrCreateAttributeNode( "sub" ); assert subTypeAttrNode != null; }