44 */
55package org .hibernate .graph ;
66
7+ import java .util .Arrays ;
78import java .util .List ;
89import java .util .Map ;
910import java .util .Set ;
11+ import java .util .stream .Stream ;
12+
1013import jakarta .persistence .AttributeNode ;
1114import jakarta .persistence .EntityGraph ;
1215import jakarta .persistence .EntityManager ;
16+ import jakarta .persistence .Graph ;
1317import jakarta .persistence .Query ;
1418import jakarta .persistence .Subgraph ;
1519import jakarta .persistence .TypedQuery ;
1620
17- import org .hibernate .Session ;
1821import org .hibernate .engine .spi .SessionImplementor ;
1922import org .hibernate .graph .spi .GraphImplementor ;
2023import org .hibernate .graph .spi .RootGraphImplementor ;
24+ import org .hibernate .query .SelectionQuery ;
2125
2226/**
2327 * A collection of {@link EntityGraph} utilities.
2428 *
25- * @apiNote These methods really belong inside other classes that we cannot modify .
29+ * @apiNote These operations are things which are arguably missing from JPA .
2630 *
2731 * @author asusnjar
32+ * @author Gavin King
2833 */
2934public final class EntityGraphs {
35+
3036 /**
3137 * Merges multiple entity graphs into a single graph that specifies the
3238 * fetching/loading of all attributes the input graphs specify.
3339 *
3440 * @param <T> Root entity type of the query and graph.
3541 *
36- * @param entityManager EntityManager to use to create the new merged graph.
37- * @param rootType Root type of the entity for which the graph is being merged.
42+ * @param entityManager {@code EntityManager} to use to create the new merged graph.
43+ * @param root Root type of the entity for which the graph is being merged.
3844 * @param graphs Graphs to merge.
3945 *
4046 * @return The merged graph.
4147 */
4248 @ SafeVarargs
43- public static <T > EntityGraph <T > merge (EntityManager entityManager , Class <T > rootType , EntityGraph <T >... graphs ) {
44- return mergeInternal ( ( SessionImplementor ) entityManager , rootType , graphs );
49+ public static <T > EntityGraph <T > merge (EntityManager entityManager , Class <T > root , Graph <T >... graphs ) {
50+ return merge ( entityManager , root , Arrays . stream ( graphs ) );
4551 }
4652
47- @ SafeVarargs
48- public static <T > EntityGraph <T > merge (Session session , Class <T > rootType , Graph <T >... graphs ) {
49- return mergeInternal ( (SessionImplementor ) session , rootType , graphs );
53+ /**
54+ * Merges multiple entity graphs into a single graph that specifies the
55+ * fetching/loading of all attributes the input graphs specify.
56+ *
57+ * @param <T> Root entity type of the query and graph.
58+ *
59+ * @param entityManager {@code EntityManager} to use to create the new merged graph.
60+ * @param root Root type of the entity for which the graph is being merged.
61+ * @param graphs Graphs to merge.
62+ *
63+ * @return The merged graph.
64+ *
65+ * @since 7.0
66+ */
67+ public static <T > EntityGraph <T > merge (EntityManager entityManager , Class <T > root , List <? extends Graph <T >> graphs ) {
68+ return merge ( entityManager , root , graphs .stream () );
5069 }
5170
52- @ SafeVarargs
53- public static <T > EntityGraph <T > merge (SessionImplementor session , Class <T > rootType , GraphImplementor <T >... graphs ) {
54- return mergeInternal ( session , rootType , graphs );
71+ /**
72+ * Merges multiple entity graphs into a single graph that specifies the
73+ * fetching/loading of all attributes the input graphs specify.
74+ *
75+ * @param <T> Root entity type of the query and graph.
76+ *
77+ * @param entityManager {@code EntityManager} to use to create the new merged graph.
78+ * @param root Root type of the entity for which the graph is being merged.
79+ * @param graphs Graphs to merge.
80+ *
81+ * @return The merged graph.
82+ *
83+ * @since 7.0
84+ */
85+ public static <T > EntityGraph <T > merge (EntityManager entityManager , Class <T > root , Stream <? extends Graph <T >> graphs ) {
86+ final RootGraphImplementor <T > merged = ((SessionImplementor ) entityManager ).createEntityGraph ( root );
87+ graphs .forEach ( graph -> merged .merge ( (GraphImplementor <T >) graph ) );
88+ return merged ;
5589 }
5690
57- private static <T > EntityGraph <T > mergeInternal (
58- SessionImplementor session , Class <T > rootType , jakarta .persistence .Graph <T >[] graphs ) {
59- final RootGraphImplementor <T > merged = session .createEntityGraph ( rootType );
60- if ( graphs != null ) {
61- for ( jakarta .persistence .Graph <T > graph : graphs ) {
62- merged .merge ( (GraphImplementor <T >) graph );
63- }
64- }
65- return merged ;
91+ /**
92+ * Convenience method to apply the given graph to the given query
93+ * without the need for a cast when working with JPA API.
94+ *
95+ * @param query The JPA {@link TypedQuery}
96+ * @param graph The JPA {@link EntityGraph} to apply
97+ * @param semantic The semantic to use when applying the graph
98+ *
99+ * @see SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)
100+ *
101+ * @since 7.0
102+ */
103+ public static <R > void setGraph (TypedQuery <R > query , EntityGraph <R > graph , GraphSemantic semantic ) {
104+ ((org .hibernate .query .Query <R >) query ).setEntityGraph ( graph , semantic );
105+ }
106+
107+ /**
108+ * Convenience method to apply the given load graph to the given
109+ * query without the need for a cast when working with JPA API.
110+ *
111+ * @param query The JPA {@link TypedQuery}
112+ * @param graph The JPA {@link EntityGraph} to apply
113+ *
114+ * @since 7.0
115+ */
116+ public static <R > void setLoadGraph (TypedQuery <R > query , EntityGraph <R > graph ) {
117+ setGraph ( query , graph , GraphSemantic .LOAD );
118+ }
119+
120+ /**
121+ * Convenience method to apply the given fetch graph to the given
122+ * query without the need for a cast when working with JPA API.
123+ *
124+ * @param query The JPA {@link TypedQuery}
125+ * @param graph The JPA {@link EntityGraph} to apply
126+ *
127+ * @since 7.0
128+ */
129+ public static <R > void setFetchGraph (TypedQuery <R > query , EntityGraph <R > graph ) {
130+ setGraph ( query , graph , GraphSemantic .FETCH );
131+ }
132+
133+ /**
134+ * Allows a treated subgraph to ve created for a {@link Subgraph}, since the
135+ * JPA-standard operation {@link EntityGraph#addTreatedSubgraph(Class)} is
136+ * declared by {@link EntityGraph}.
137+ *
138+ * @param graph any {@linkplain Graph root graph or subgraph}
139+ * @param subtype the treated (narrowed) type
140+ *
141+ * @since 7.0
142+ */
143+ public <S > Subgraph <S > addTreatedSubgraph (Graph <? super S > graph , Class <S > subtype ) {
144+ return ((org .hibernate .graph .Graph <? super S >) graph ).addTreatedSubGraph ( subtype );
66145 }
67146
68147 /**
@@ -73,7 +152,7 @@ private static <T> EntityGraph<T> mergeInternal(
73152 * @param graph The graph to apply
74153 * @param semantic The semantic to use when applying the graph
75154 *
76- * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)}
155+ * @deprecated Since it is not type safe and returns a raw type
77156 */
78157 @ Deprecated (since = "7.0" )
79158 public static @ SuppressWarnings ("rawtypes" ) List executeList (Query query , EntityGraph <?> graph , GraphSemantic semantic ) {
@@ -94,7 +173,7 @@ private static <T> EntityGraph<T> mergeInternal(
94173 * the graph applies to that entity's type. JPA does not necessarily
95174 * require that, but it is by far the most common usage.
96175 *
97- * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph( EntityGraph, GraphSemantic)}
176+ * @deprecated Use {@link #setGraph(TypedQuery, EntityGraph, GraphSemantic)} instead
98177 */
99178 @ Deprecated (since = "7.0" )
100179 public static <R > List <R > executeList (TypedQuery <R > query , EntityGraph <R > graph , GraphSemantic semantic ) {
@@ -114,7 +193,7 @@ public static <R> List<R> executeList(TypedQuery<R> query, EntityGraph<R> graph,
114193 *
115194 * @return The result list
116195 *
117- * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)}
196+ * @deprecated Since it is not type safe, returns a raw type, and accepts a string
118197 */
119198 @ Deprecated (since = "7.0" )
120199 public static @ SuppressWarnings ("rawtypes" ) List executeList (Query query , EntityGraph <?> graph , String semanticJpaHintName ) {
@@ -133,7 +212,7 @@ public static <R> List<R> executeList(TypedQuery<R> query, EntityGraph<R> graph,
133212 * the graph applies to that entity's type. JPA does not necessarily
134213 * require that, but it is by far the most common usage.
135214 *
136- * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic) }
215+ * @deprecated Since it accepts a string instead of {@link GraphSemantic}
137216 */
138217 @ Deprecated (since = "7.0" )
139218 public static <R > List <R > executeList (TypedQuery <R > query , EntityGraph <R > graph , String semanticJpaHintName ) {
@@ -152,7 +231,7 @@ public static <R> List<R> executeList(TypedQuery<R> query, EntityGraph<R> graph,
152231 * This is simply knowledge from JPA EG discussions, nothing that
153232 * is specifically mentioned or discussed in the spec.
154233 *
155- * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)}
234+ * @deprecated Since it is not type safe and returns a raw type
156235 */
157236 @ Deprecated (since = "7.0" )
158237 public static @ SuppressWarnings ("rawtypes" ) List executeList (Query query , EntityGraph <?> graph ) {
@@ -170,7 +249,7 @@ public static <R> List<R> executeList(TypedQuery<R> query, EntityGraph<R> graph,
170249 * the graph applies to that entity's type. JPA does not necessarily
171250 * require that, but it is by far the most common usage.
172251 *
173- * @deprecated Use {@link org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)}
252+ * @deprecated Use {@link #setFetchGraph(TypedQuery, EntityGraph)} instead
174253 */
175254 @ Deprecated (since = "7.0" )
176255 public static <R > List <R > executeList (TypedQuery <R > query , EntityGraph <R > graph ) {
@@ -276,7 +355,9 @@ public static boolean areEqual(
276355 * Compares two entity subgraphs and returns {@code true} if they are equal,
277356 * ignoring attribute order.
278357 */
279- public static boolean areEqual (@ SuppressWarnings ("rawtypes" ) Subgraph a , @ SuppressWarnings ("rawtypes" ) Subgraph b ) {
358+ public static boolean areEqual (
359+ @ SuppressWarnings ("rawtypes" ) Subgraph a ,
360+ @ SuppressWarnings ("rawtypes" ) Subgraph b ) {
280361 if ( a == b ) {
281362 return true ;
282363 }
0 commit comments