From 96d4b9c8060dddbf1b880c35c8f919c8786827da Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 3 Jan 2025 00:36:46 +0100 Subject: [PATCH 1/4] mention org.hibernate.graph in migration guide --- migration-guide.adoc | 51 ++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/migration-guide.adoc b/migration-guide.adoc index dc8f59edfdce..f9f9e85d7f4f 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -15,12 +15,12 @@ earlier versions, see any other pertinent migration guides as well. 7.0 migrates to Jakarta Persistence 3.2 which is fairly disruptive, mainly around: -* type parameters +* Type parameters: ** Affects much of the Criteria API - especially roots, joins, paths ** Affects much of the Graph API - - *** org.hibernate.graph.Graph.addAttributeNode(java.lang.String) defines a return while + *** `org.hibernate.graph.Graph.addAttributeNode(java.lang.String)` defines a return while `jakarta.persistence.Graph.addAttributeNode(java.lang.String)` does not. -* new JPA features colliding with previous Hibernate extension features +* New JPA features colliding with previous Hibernate extension features: ** `Nulls` (JPA) v. `NullPrecedence` (Hibernate), including JPA's new `Order#getNullPrecedence()` returning `Nulls` colliding with Hibernate's `SqmSortSpecification#getNullPrecedence` returning `NullPrecedence`. Hibernate's form was renamed to `SqmSortSpecification#getHibernateNullPrecedence` to avoid the collision. @@ -86,18 +86,19 @@ private Employee manager; === Misplaced Annotations 7.0 does much more in-depth checking that annotations appear in the proper place. While previous versions -did not necessarily throw errors, in most cases these annotations were simply ignored. E.g. +did not necessarily throw errors, in most cases these annotations were simply ignored. +For example, this code now results in an error: [source,java] ---- @Entity class Book { - // defines FIELD access-type + // specifies FIELD access, properties should not be annotated @Id Integer id; - // previously ignored, this is an error now + // previously ignored, this is an error now @Column(name="category") String getType() { ... } } @@ -114,7 +115,8 @@ versions did not validate this particularly well. [[java-beans]] === JavaBean Conventions -Previous versions allowed some questionable (at best) attribute naming patterns. These are no longer supported. E.g. +Previous versions allowed some questionable (at best) attribute naming patterns. +For example, this property declaration is no longer allowed: [source,java] ---- @@ -204,16 +206,16 @@ Applications will need to replace usages of the removed `@Proxy` annotation. `@Proxy#proxyClass` has no direct replacement, but was also never needed/useful. -Here we focus on `@Proxy#laxy` attribute which, again, was hardly ever useful. +Here we focus on `@Proxy#lazy` attribute which, again, was hardly ever useful. By default (true), Hibernate would proxy an entity when possible and when asked for. "Asked for" includes calls to `Session#getReference` and lazy associations. All such cases though are already controllable by the application. * Instead of `Session#getReference`, use `Session#find` -* Use eager associations, using -** `FetchType.EAGER` (the default for to-one associations anyway), possibly combined with `@Fetch` -** `EntityGraph` -** `@FetchProfiles` +* Use eager association fetching, for example, +** `FetchType.EAGER` (the default for to-one associations anyway), possibly combined with `@Fetch`, +** `EntityGraph`, or a +** `@FetchProfile`. The effect can also often be mitigated using Hibernate's bytecode-based laziness (possibly combined with `@ConcreteProxy`). @@ -310,8 +312,8 @@ The previous behavior may be recovered by setting `hibernate.query.native.prefer [[ddl-implicit-datatype-timestamp]] == Default precision for `timestamp` on some databases -The default precision for Oracle timestamps was changed to 9 i.e. nanosecond precision. -The default precision for SQL Server timestamps was changed to 7 i.e. 100 nanosecond precision. +The default precision for Oracle timestamps was changed to 9, i.e. nanosecond precision. +The default precision for SQL Server timestamps was changed to 7, i.e. 100 nanosecond precision. Note that these changes only affect DDL generation. @@ -339,12 +341,12 @@ The migration requires to read data and re-save it. To retain backwards compatibility, configure the setting `hibernate.type.preferred_array_jdbc_type` to `VARBINARY`. [[xml-format-mapper-changes]] -== XML FormatMapper changes +== XML `FormatMapper` changes Previous versions of Hibernate ORM used an undefined/provider-specific format for serialization/deserialization of -collections, maps and byte arrays to/from XML, which is not portable. +collections, maps and byte arrays to/from XML, which was not portable. -XML FormatMapper implementations were changed to now use a portable format for collections, maps and byte arrays. +XML `FormatMapper` implementations now use a portable format for collections, maps, and byte arrays. This change is necessary to allow mapping basic arrays as `SqlTypes.XML_ARRAY`. The migration requires to read data and re-save it. @@ -365,7 +367,7 @@ To align with Jakarta Persistence (the 3.2 TCK tests this), Hibernate now consid However, because `hibernate.session_factory_name` is also a trigger to attempt to bind the SessionFactory into JNDI, this change to consider persistence-unit name, means that each `SessionFactory` created through Jakarta Persistence now -have a name and Hibernate attempted to bind these to JNDI. +has a name and Hibernate attempts to bind it to JNDI. To work around this we have introduced a new `hibernate.session_factory_jndi_name` setting that can be used to explicitly specify a name for JNDI binding. The new behavior is as follows (assuming `hibernate.session_factory_name_is_jndi` is not explicitly configured): @@ -461,6 +463,19 @@ Hibernate now reports an error in this situation. This includes auto-applied converters. To suppress the error for an auto-applied converter, use `@Convert(disableConversion=true)`. +== `org.hibernate.graph` package + +The `EntityGraph` API was enhanced in JPA 3.2, and made much more useful. +The package `org.hibernate.graph` contains extensions to that API, which have been significantly impacted by the migration to JPA 3.2, and by the additional of new functionality. +Furthermore, some legacy operations were declared with incorrect generic type signatures (by both JPA, and by Hibernate). + +This package has been significantly re-engineered, and the impact of this effort includes: + +- some breaking changes to type signatures, and +- a number of deprecations of legacy operations which are now covered by JPA. + +We encourage migration to the use of the new JPA-standard operations. + == Deprecations * `@Comment` is deprecated in favor of the JPA 3.2 `comment` members From 07f816bef4c96073e136b397978f46168303f1a7 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 3 Jan 2025 00:37:03 +0100 Subject: [PATCH 2/4] add missing @since --- .../src/main/java/org/hibernate/cfg/PersistenceSettings.java | 2 ++ migration-guide.adoc | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/PersistenceSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/PersistenceSettings.java index 78a2f2e0a27e..fc255ca14fd9 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/PersistenceSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/PersistenceSettings.java @@ -78,6 +78,8 @@ public interface PersistenceSettings { * @see #SESSION_FACTORY_NAME_IS_JNDI * @see org.hibernate.internal.SessionFactoryRegistry * @see org.hibernate.boot.SessionFactoryBuilder#applyName(String) + * + * @since 7.0 */ String SESSION_FACTORY_JNDI_NAME = "hibernate.session_factory_jndi_name"; diff --git a/migration-guide.adoc b/migration-guide.adoc index f9f9e85d7f4f..be56d0d6721b 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -466,7 +466,7 @@ To suppress the error for an auto-applied converter, use `@Convert(disableConver == `org.hibernate.graph` package The `EntityGraph` API was enhanced in JPA 3.2, and made much more useful. -The package `org.hibernate.graph` contains extensions to that API, which have been significantly impacted by the migration to JPA 3.2, and by the additional of new functionality. +The incubating package `org.hibernate.graph` contains extensions to that API, which have been significantly impacted by the migration to JPA 3.2, and by the additional of new functionality. Furthermore, some legacy operations were declared with incorrect generic type signatures (by both JPA, and by Hibernate). This package has been significantly re-engineered, and the impact of this effort includes: From b612512d822362284567fcc829711743d186cce9 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 3 Jan 2025 01:07:52 +0100 Subject: [PATCH 3/4] add some @since annotations and a lil' bit more Javadoc --- .../org/hibernate/graph/AttributeNode.java | 42 +++++++++++++++++++ .../main/java/org/hibernate/graph/Graph.java | 20 +++++++++ 2 files changed, 62 insertions(+) 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 94e0fbaad964..5caef0f92997 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java @@ -68,11 +68,29 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr */ Map, ? extends SubGraph> getKeySubGraphs(); + /** + * All value subgraphs rooted at this node. + *

+ * Includes treated subgraphs. + * + * @apiNote This operation is declared with raw types by JPA + * + * @see #getSubGraphs() + */ @Override default @SuppressWarnings("rawtypes") Map getSubgraphs() { return unmodifiableMap( getSubGraphs() ); } + /** + * All key subgraphs rooted at this node. + *

+ * Includes treated subgraphs. + * + * @apiNote This operation is declared with raw types by JPA + * + * @see #getKeySubGraphs() + */ @Override default @SuppressWarnings("rawtypes") Map getKeySubgraphs() { return unmodifiableMap( getKeySubGraphs() ); @@ -81,12 +99,22 @@ 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. + *

+ * Note that {@code graph.addAttributeNode(att).makeSubGraph()} is a + * synonym for {@code graph.addSubgraph(att)}. + * + * @see Graph#addSubgraph(jakarta.persistence.metamodel.Attribute) */ 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. + *

+ * Note that {@code graph.addAttributeNode(att).makeKeySubGraph()} is a + * synonym for {@code graph.addMapKeySubgraph(att)}. + * + * @see Graph#addMapKeySubgraph(jakarta.persistence.metamodel.MapAttribute) */ SubGraph makeKeySubGraph(); @@ -97,8 +125,13 @@ 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. + *

+ * Note that {@code graph.addAttributeNode(att).makeSubGraph(cl)} + * is a synonym for {@code graph.addTreatedSubgraph(att,cl)}. * * @param subtype The type or treated type of the value type + * + * @see Graph#addTreatedSubgraph(jakarta.persistence.metamodel.Attribute, Class) */ SubGraph makeSubGraph(Class subtype); @@ -109,8 +142,13 @@ 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. + *

+ * Note that {@code graph.addAttributeNode(att).makeKeySubGraph(cl)} + * is a synonym for {@code graph.addTreatedMapKeySubgraph(att,cl)}. * * @param subtype The type or treated type of the key type + * + * @see Graph#addTreatedMapKeySubgraph(jakarta.persistence.metamodel.MapAttribute,Class) */ SubGraph makeKeySubGraph(Class subtype); @@ -123,6 +161,8 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr * is a treated subgraph. * * @param subtype The type or treated type of the value type + * + * @since 7.0 */ @Incubating SubGraph makeSubGraph(ManagedType subtype); @@ -136,6 +176,8 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr * 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 78b89466ed79..a1db88d16d30 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java @@ -100,6 +100,8 @@ RootGraph makeRootGraph(String name, boolean mutable) /** * Find an existing {@link AttributeNode} by name within this container. + * + * @since 7.0 */ @Override AttributeNode getAttributeNode(String attributeName); @@ -107,6 +109,8 @@ RootGraph makeRootGraph(String name, boolean mutable) /** * Find an existing {@link AttributeNode} by corresponding attribute * reference, within this container. + * + * @since 7.0 */ @Override AttributeNode getAttributeNode(Attribute attribute); @@ -145,6 +149,8 @@ RootGraph makeRootGraph(String name, boolean mutable) * such {@link SubGraph} if there is one. * * @see jakarta.persistence.EntityGraph#addTreatedSubgraph(Class) + * + * @since 7.0 */ SubGraph addTreatedSubgraph(Class type); @@ -152,6 +158,8 @@ RootGraph makeRootGraph(String name, boolean mutable) * 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. + * + * @since 7.0 */ @Incubating SubGraph addTreatedSubgraph(ManagedType type); @@ -244,6 +252,8 @@ SubGraph addSubgraph(Attribute attribute) * @param type A subtype of the attribute type * * @see #addSubgraph(Attribute, Class) + * + * @since 7.0 */ @Override SubGraph addTreatedSubgraph(Attribute attribute, Class type) @@ -260,6 +270,8 @@ SubGraph addTreatedSubgraph(Attribute attribute, Cl * * @param attribute An attribute of the represented type * @param type A subtype of the attribute type + * + * @since 7.0 */ @Incubating SubGraph addTreatedSubgraph(Attribute attribute, ManagedType type) @@ -337,6 +349,8 @@ SubGraph addSubGraph(PersistentAttribute attribu * {@link SubGraph} if there is one. * * @param attribute A collection-valued attribute of the represented type + * + * @since 7.0 */ @Override SubGraph addElementSubgraph(PluralAttribute attribute); @@ -352,6 +366,8 @@ SubGraph addSubGraph(PersistentAttribute attribu * * @param attribute A collection-valued attribute of the represented type * @param type A subtype of the element type + * + * @since 7.0 */ @Override SubGraph addTreatedElementSubgraph(PluralAttribute attribute, Class type) @@ -368,6 +384,8 @@ SubGraph addTreatedElementSubgraph(PluralAttribute SubGraph addTreatedElementSubgraph(PluralAttribute attribute, ManagedType type) @@ -468,6 +486,8 @@ SubGraph addKeySubGraph(String attributeName, Class type) * * @param attribute A map-valued attribute of the represented type * @param type A subtype of the key type + * + * @since 7.0 */ @Incubating SubGraph addTreatedMapKeySubgraph(MapAttribute attribute, ManagedType type) From 7b8e36baad1335d1a4795aa12f581b7105b924f8 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 3 Jan 2025 01:28:53 +0100 Subject: [PATCH 4/4] 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 | 133 +++++++---- .../{AbstractGraph.java => GraphImpl.java} | 225 +++++++++++++----- .../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 | 60 +++-- .../hibernate/graph/spi/GraphImplementor.java | 109 +++------ .../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, 392 insertions(+), 289 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 5caef0f92997..3bcdadd3d67b 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 @@ 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 @@ * @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 a1db88d16d30..f356be84d36f 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 @@ RootGraph makeRootGraph(String name, boolean mutable) * @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 fef40f45ca36..229a20c6ab12 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 @@ * @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,29 @@ public PersistentAttribute getAttributeDescriptor() { } @Override - public SubGraphImplementor getSubGraph() { + public SubGraphImplementor addValueSubgraph() { + // this one is intentionally lenient and disfavored + if ( valueSubgraph == null ) { + valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true ); + } return valueSubgraph; } @Override - public SubGraphImplementor getKeySubGraph() { - return keySubgraph; + 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 makeSubGraph() { - verifyMutability(); + public SubGraphImplementor addElementSubgraph() { + checkToMany(); if ( valueSubgraph == null ) { valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true ); } @@ -87,33 +113,51 @@ public SubGraphImplementor makeSubGraph() { } @Override - public SubGraphImplementor makeSubGraph(Class subtype) { - final ManagedDomainType managedType = asManagedType( valueGraphType ); - if ( !managedType.getBindableJavaType().isAssignableFrom( subtype ) ) { - throw new IllegalArgumentException( "Not a subtype: " + subtype.getName() ); + public SubGraphImplementor addKeySubgraph() { + checkMap(); + if ( keySubgraph == null ) { + keySubgraph = new SubGraphImpl<>( asManagedType( keyGraphType ), true ); } - @SuppressWarnings("unchecked") - final Class castSuptype = (Class) subtype; - final SubGraphImplementor result = makeSubGraph().addTreatedSubgraph( castSuptype ); - //noinspection unchecked - return (SubGraphImplementor) result; + return keySubgraph; } - @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() ); + 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 ); + if ( !managedType.getBindableJavaType().isAssignableFrom( subtype ) ) { + throw new IllegalArgumentException( "Not a subtype: " + subtype.getName() ); } @SuppressWarnings("unchecked") - final ManagedDomainType castType = (ManagedDomainType) subtype; - final SubGraphImplementor result = makeSubGraph().addTreatedSubgraph( castType ); + final Class castSuptype = (Class) subtype; + final SubGraphImplementor result = makeSubGraph().addTreatedSubgraph( castSuptype ); //noinspection unchecked return (SubGraphImplementor) result; } - @Override + @Override @Deprecated public SubGraphImplementor makeKeySubGraph() { verifyMutability(); checkMap(); @@ -123,7 +167,7 @@ public SubGraphImplementor makeKeySubGraph() { return keySubgraph; } - @Override + @Override @Deprecated public SubGraphImplementor makeKeySubGraph(Class subtype) { checkMap(); final ManagedDomainType type = asManagedType( keyGraphType ); @@ -137,21 +181,6 @@ public SubGraphImplementor makeKeySubGraph(Class subtype) { 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 String toString() { } @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 Map, SubGraphImplementor> getSubGraphs() { 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 Map, SubGraphImplementor> getKeySubGraphs() { 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 0d8d2d8b4972..95ff3b94ea82 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.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 @@ * @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 @@ private SubGraphImplementor getTreatedSubgraph(Class javaTyp } @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 @@ private SubGraphImplementor getTreatedSubgraphForPut(Class j } } - 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 void merge(GraphImplementor graph) { 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 @@ private void mergeGraph(SubGraphImplementor subgraph) { } } - 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 @@ private static void mergeNode( } @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 AttributeNodeImplementor findAttributeNode(String attributeName) } @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 void removeAttributeNodes(Attribute.PersistentAttributeType nodeType) { } @Override - public AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute) { + 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; + } + } + + 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 node = getNodeForPut( attribute ); + final AttributeNodeImplementor,V,K> node = getNodeForPut( attribute ); if ( node == null ) { - final AttributeNodeImplementor newAttrNode = AttributeNodeImpl.create( attribute, isMutable() ); + final AttributeNodeImplementor,V,K> newAttrNode = AttributeNodeImpl.create( attribute, isMutable() ); attributeNodes.put( attribute, newAttrNode ); return newAttrNode; } @@ -264,7 +331,7 @@ public AttributeNodeImplementor findOrCreateAttributeNode(PersistentAtt } @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,96 +352,112 @@ public AttributeNodeImplementor findOrCreateAttributeNode(String attrib : 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 ).makeKeySubGraph(); + public SubGraphImplementor addKeySubgraph(String attributeName) { + return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).addKeySubgraph(); } @Override - public SubGraphImplementor addKeySubGraph(String attributeName, Class subtype) { - return findOrCreateAttributeNode( attributeName ).makeKeySubGraph( subtype ); + public SubGraphImplementor addKeySubgraph(String attributeName, Class type) { + return addKeySubgraph( attributeName ).addTreatedSubgraph( type ); } @Override - public SubGraphImplementor addMapKeySubgraph(MapAttribute attribute) { - return findOrCreateAttributeNode( attribute.getName() ).makeKeySubGraph( attribute.getKeyJavaType() ); + public SubGraphImplementor addKeySubGraph(String attributeName) { + return addKeySubgraph( attributeName ); } @Override - public SubGraphImplementor addTreatedMapKeySubgraph( - MapAttribute attribute, - Class type) { - return addMapKeySubgraph( attribute ).addTreatedSubgraph( type ); + public SubGraphImplementor addKeySubGraph(String attributeName, Class subtype) { + return addKeySubGraph( attributeName ).addTreatedSubgraph( subtype ); } - @Override @SuppressWarnings("unchecked") // The JPA API is unsafe by nature - public SubGraphImplementor addElementSubgraph(String attributeName) { - return (SubGraphImplementor) findOrCreateAttributeNode( attributeName ).makeSubGraph(); + @Override + public SubGraphImplementor addMapKeySubgraph(MapAttribute attribute) { + return findOrCreateAttributeNode( (MapPersistentAttribute) attribute ).addKeySubgraph(); } @Override - public SubGraphImplementor addElementSubgraph(PluralAttribute attribute) { - return findOrCreateAttributeNode( attribute.getName() ) - .makeSubGraph( asManagedType( attribute.getElementType() ) ); + public SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, Class subtype) { + return addTreatedMapKeySubgraph( attribute, subtype ); } @Override - public SubGraphImplementor addElementSubgraph(String attributeName, Class type) { - return findOrCreateAttributeNode( attributeName ).makeSubGraph( type ); + public SubGraphImplementor addTreatedMapKeySubgraph(MapAttribute attribute, ManagedType type) { + return addMapKeySubgraph( attribute ).addTreatedSubgraph( type ); } @Override - public SubGraphImplementor addTreatedElementSubgraph( - PluralAttribute attribute, - Class type) { - return addElementSubgraph( attribute ).addTreatedSubgraph( type ); + public SubGraphImplementor addTreatedMapKeySubgraph( + MapAttribute attribute, + Class type) { + return addMapKeySubgraph( attribute ).addTreatedSubgraph( type ); } @Override @@ -409,7 +492,7 @@ public SubGraphImplementor addTreatedSubgraph(Class type) { } @Override - public Map, SubGraphImplementor> getSubGraphs() { + public Map, SubGraphImplementor> getTreatedSubgraphs() { return treatedSubgraphs == null ? emptyMap() : unmodifiableMap( treatedSubgraphs ); } @@ -423,6 +506,16 @@ static ManagedDomainType asManagedType(Type domainType) { } } + 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 2e8965910bfb..fb34bc78db8f 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 @@ * * @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 339ecbe359de..82170ad1f0e3 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 @@ * * @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 5697f5bd3d78..e3873f9a048a 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 SubGraphImplementor visitSubGraph(GraphLanguageParser.SubGraphContext ctx ); } - 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 5d2f7e12ad5b..b1b6a1dfbd96 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 @@ 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 094858dcfa88..f19aa465e64d 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 @@ @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 9a1a0966797a..9f6961226283 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 { - - @Override - AttributeNodeImplementor makeCopy(boolean mutable); +public interface AttributeNodeImplementor extends AttributeNode, GraphNodeImplementor { @Override + AttributeNodeImplementor makeCopy(boolean mutable); + + /** + * 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 b1d6be723bb0..95e1a2cc92a1 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.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,124 +45,91 @@ public interface GraphImplementor extends Graph, GraphNodeImplementor { GraphImplementor makeCopy(boolean mutable); @Override - List> getAttributeNodeList(); + List> getAttributeNodeList(); - Map, AttributeNodeImplementor> getNodes(); + Map, AttributeNodeImplementor> getNodes(); - @Override - AttributeNodeImplementor findAttributeNode(String attributeName); + Map, SubGraphImplementor> getTreatedSubgraphs(); @Override - AttributeNodeImplementor findAttributeNode(PersistentAttribute attribute); - - AttributeNodeImplementor findOrCreateAttributeNode(String name); - - AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute); - - AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute); + AttributeNodeImplementor getAttributeNode(String attributeName); @Override - SubGraphImplementor addSubGraph(String attributeName); + AttributeNodeImplementor getAttributeNode(Attribute attribute); @Override - SubGraphImplementor addSubGraph(String attributeName, Class subType); + AttributeNodeImplementor findAttributeNode(String attributeName); @Override - SubGraphImplementor addSubGraph(PersistentAttribute attribute); + AttributeNodeImplementor findAttributeNode(PersistentAttribute attribute); - @Override - SubGraphImplementor addSubGraph(PersistentAttribute attribute, Class subtype); + AttributeNodeImplementor findOrCreateAttributeNode(String name); - SubGraphImplementor addTreatedSubgraph(PersistentAttribute attribute, ManagedType subtype); + AttributeNodeImplementor findOrCreateAttributeNode(PersistentAttribute attribute); - @Incubating - SubGraphImplementor addElementSubGraph(PluralPersistentAttribute attribute, Class type); - - @Incubating - SubGraphImplementor addTreatedElementSubgraph(PluralPersistentAttribute attribute, ManagedType type); + AttributeNodeImplementor addAttributeNode(PersistentAttribute attribute); @Override - SubGraphImplementor addKeySubGraph(String attributeName); + AttributeNodeImplementor addAttributeNode(Attribute attribute); @Override - SubGraphImplementor addKeySubGraph(String attributeName, Class subtype); + SubGraphImplementor addTreatedSubgraph(Class type); + + SubGraphImplementor addTreatedSubgraph(ManagedType type); @Override - SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, Class subtype); + SubGraphImplementor addSubgraph(String attributeName); - SubGraphImplementor addTreatedMapKeySubgraph(MapPersistentAttribute attribute, ManagedType subtype); + @Override + SubGraphImplementor addSubGraph(String attributeName); @Override - SubGraphImplementor addTreatedSubgraph(Class type); + SubGraphImplementor addSubGraph(String attributeName, Class subType); - SubGraphImplementor addTreatedSubgraph(ManagedType type); + @Override + SubGraphImplementor addSubGraph(PersistentAttribute attribute); - Map, SubGraphImplementor> getSubGraphs(); + @Override + SubGraphImplementor addSubGraph(PersistentAttribute attribute, Class subtype); @Override - default AttributeNode getAttributeNode(String attributeName) { - return findAttributeNode( attributeName ); - } + SubGraphImplementor addKeySubGraph(String attributeName); @Override - default AttributeNode getAttributeNode(Attribute attribute) { - return findAttributeNode( (PersistentAttribute) attribute ); - } + SubGraphImplementor addKeySubGraph(String attributeName, Class subtype); @Override - default AttributeNode addAttributeNode(Attribute attribute) { - return addAttributeNode( (PersistentAttribute) attribute ); - } + SubGraphImplementor addKeySubGraph(MapPersistentAttribute attribute, Class subtype); @Override - default SubGraphImplementor addSubgraph(String attributeName, Class type) { - return addSubGraph( attributeName ).addTreatedSubgraph( type ); - } + SubGraphImplementor addSubgraph(String attributeName, Class type); @Override - default SubGraphImplementor addSubgraph(Attribute attribute) { - return addSubGraph( (PersistentAttribute) attribute ); - } + SubGraphImplementor addSubgraph(Attribute attribute); @Override - default SubGraphImplementor addTreatedSubgraph(Attribute attribute, Class type) { - return addSubGraph( (PersistentAttribute) attribute ).addTreatedSubgraph( type ); - } + SubGraphImplementor addTreatedSubgraph(Attribute attribute, Class type); @Override - default SubGraph addTreatedSubgraph(Attribute attribute, ManagedType type) { - return addSubGraph( (PersistentAttribute) attribute ).addTreatedSubgraph( type ); - } + SubGraphImplementor addTreatedSubgraph(Attribute attribute, ManagedType type); @Override - default SubGraphImplementor addTreatedElementSubgraph(PluralAttribute attribute, Class type) { - return addElementSubGraph( (PluralPersistentAttribute) attribute, type ); - } + SubGraphImplementor addTreatedElementSubgraph(PluralAttribute attribute, Class type); @Override - default SubGraph addTreatedElementSubgraph(PluralAttribute attribute, ManagedType type) { - return addTreatedElementSubgraph( (PluralPersistentAttribute) attribute, type ); - } + SubGraph addTreatedElementSubgraph(PluralAttribute attribute, ManagedType type); @Override - default SubGraphImplementor addKeySubgraph(String attributeName) { - return addKeySubGraph( attributeName ); - } + SubGraphImplementor addKeySubgraph(String attributeName); @Override - default SubGraphImplementor addKeySubgraph(String attributeName, Class type) { - return addKeySubGraph( attributeName ).addTreatedSubgraph( type ); - } + SubGraphImplementor addKeySubgraph(String attributeName, Class type); @Override - default SubGraphImplementor addTreatedMapKeySubgraph(MapAttribute attribute, Class type) { - return addKeySubGraph( (MapPersistentAttribute) attribute, type ); - } + SubGraphImplementor addTreatedMapKeySubgraph(MapAttribute attribute, Class 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 71fa8f5266fe..fc1270d5d8d7 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 13359f68454e..6da10dc69761 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 @@ private void applyNamedAttributeNodes( 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 @@ private void applyNamedAttributeNodes( } } - 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 e2f454738e5c..222f5b48d305 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AppliedGraphs.java @@ -26,7 +26,7 @@ public static boolean containsCollectionFetches(QueryOptions queryOptions) { } private static boolean containsCollectionFetches(GraphImplementor graph) { - for ( AttributeNodeImplementor node : graph.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 d1499e2453db..e7a622de836b 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 @@ else if ( referencedModelPart.isOptional() && referencedModelPart.isLazy() ) { 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 b4831f05590f..8cc7fcb994e2 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 TraversalResult traverse(FetchParent fetchParent, Fetchable fetchable, bo } 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 0b32ffea7c31..0477bf5d076a 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 void testLinkSubtypeParsing() { 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 void testHHH10378IsNotFixedYet() { assertEquals( subGraph.getGraphedType().getJavaType(), GraphParsingTestSubEntity.class ); - final AttributeNodeImplementor subTypeAttrNode = subGraph.findOrCreateAttributeNode( "sub" ); + final AttributeNodeImplementor subTypeAttrNode = subGraph.findOrCreateAttributeNode( "sub" ); assert subTypeAttrNode != null; }