Skip to content

Commit f81b26a

Browse files
committed
Graphpocalypse: major revision/refactoring of EntityGraph support
- attempt to fill in unimplemented operations from JPA 3.2
1 parent cced717 commit f81b26a

File tree

4 files changed

+171
-21
lines changed

4 files changed

+171
-21
lines changed

hibernate-core/src/main/java/org/hibernate/graph/Graph.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public interface Graph<J> extends GraphNode<J>, jakarta.persistence.Graph<J> {
4242
* @since 6.3
4343
*/
4444
default <AJ> SubGraph<AJ> addPluralSubgraph(PluralAttribute<? super J, ?, AJ> attribute) {
45-
return addSubGraph( attribute.getName() );
45+
return addSubGraph( attribute.getName(), attribute.getBindableJavaType() );
4646
}
4747

4848
/**
@@ -146,6 +146,7 @@ default List<AttributeNode<?>> getGraphAttributeNodes() {
146146
*
147147
* @apiNote If no such AttributeNode exists yet, it is created.
148148
*/
149+
@Deprecated
149150
<AJ> SubGraph<AJ> addSubGraph(String attributeName);
150151

151152
<AJ> SubGraph<AJ> addSubGraph(String attributeName, Class<AJ> type);
@@ -160,6 +161,8 @@ default List<AttributeNode<?>> getGraphAttributeNodes() {
160161

161162
<AJ> SubGraph<AJ> addSubGraph(PersistentAttribute<? super J, ? super AJ> attribute, Class<AJ> type);
162163

164+
<AJ> SubGraph<AJ> addSubGraph(PersistentAttribute<? super J, ? super AJ> attribute, ManagedDomainType<AJ> type);
165+
163166
@Override
164167
default <Y> SubGraph<Y> addTreatedSubgraph(Attribute<? super J, ? super Y> attribute, Class<Y> type) {
165168
return addSubGraph( (PersistentAttribute<? super J, ? super Y>) attribute, type );
@@ -185,9 +188,13 @@ default <X> SubGraph<X> addSubgraph(String name, Class<X> type) {
185188
return addSubGraph( name, type );
186189
}
187190

191+
@Deprecated
188192
<AJ> SubGraph<AJ> addKeySubGraph(String attributeName);
193+
189194
<AJ> SubGraph<AJ> addKeySubGraph(String attributeName, Class<AJ> type);
190195

196+
<AJ> SubGraph<AJ> addKeySubGraph(PersistentAttribute<? super J, ? super AJ> attribute, ManagedDomainType<AJ> type);
197+
191198
@Override @Deprecated(forRemoval = true)
192199
default <X> SubGraph<X> addKeySubgraph(Attribute<? super J, X> attribute) {
193200
throw new UnsupportedOperationException("This operation will be removed in JPA 4");

hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ private <T> AttributeNodeImplementor<T> getNode(PersistentAttribute<?, ? extends
243243
}
244244

245245
@Override
246-
@SuppressWarnings("unchecked") // The JPA API is unsafe by nature
246+
@SuppressWarnings("unchecked") // The API is unsafe by nature
247247
public <AJ> SubGraphImplementor<AJ> addSubGraph(String attributeName) {
248248
return (SubGraphImplementor<AJ>) findOrCreateAttributeNode( attributeName ).makeSubGraph();
249249
}
@@ -259,11 +259,19 @@ public <AJ> SubGraphImplementor<AJ> addSubGraph(PersistentAttribute<? super J, A
259259
}
260260

261261
@Override
262-
public <AJ> SubGraphImplementor<AJ> addSubGraph(
263-
PersistentAttribute<? super J, ? super AJ> attribute, Class<AJ> subtype) {
262+
public <AJ> SubGraphImplementor<AJ> addSubGraph(PersistentAttribute<? super J, ? super AJ> attribute, Class<AJ> subtype) {
264263
return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype );
265264
}
266265

266+
@Override
267+
public <AJ> SubGraphImplementor<AJ> addSubGraph(PersistentAttribute<? super J, ? super AJ> attribute, ManagedDomainType<AJ> subtype) {
268+
return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype );
269+
}
270+
271+
@Override
272+
public <AJ> SubGraphImplementor<AJ> addKeySubGraph(PersistentAttribute<? super J, ? super AJ> attribute, ManagedDomainType<AJ> subtype) {
273+
return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subtype );
274+
}
267275
@Override
268276
public <Y> SubGraphImplementor<Y> addTreatedSubgraph(Attribute<? super J, ? super Y> attribute, Class<Y> type) {
269277
// TODO Test this it's probably not right!
@@ -272,7 +280,7 @@ public <Y> SubGraphImplementor<Y> addTreatedSubgraph(Attribute<? super J, ? supe
272280
}
273281

274282
@Override
275-
@SuppressWarnings("unchecked") // The JPA API is unsafe by nature
283+
@SuppressWarnings("unchecked") // The API is unsafe by nature
276284
public <AJ> SubGraphImplementor<AJ> addKeySubGraph(String attributeName) {
277285
return (SubGraphImplementor<AJ>) findOrCreateAttributeNode( attributeName ).makeKeySubGraph();
278286
}
@@ -282,37 +290,38 @@ public <AJ> SubGraphImplementor<AJ> addKeySubGraph(String attributeName, Class<A
282290
return findOrCreateAttributeNode( attributeName ).makeKeySubGraph( subtype );
283291
}
284292

285-
////////////////// TODO //////////////////
286-
287293
@Override
288-
public <E> SubGraphImplementor<E> addTreatedElementSubgraph(
289-
PluralAttribute<? super J, ?, ? super E> attribute,
290-
Class<E> type) {
291-
throw new UnsupportedOperationException( "Not yet implemented" );
294+
public <K> SubGraphImplementor<K> addMapKeySubgraph(MapAttribute<? super J, K, ?> attribute) {
295+
return findOrCreateAttributeNode( attribute.getName() ).makeKeySubGraph( attribute.getKeyJavaType() );
292296
}
293297

294298
@Override
295-
public <K> SubGraphImplementor<K> addTreatedMapKeySubgraph(MapAttribute<? super J, ? super K, ?> attribute, Class<K> type) {
296-
throw new UnsupportedOperationException( "Not yet implemented" );
299+
public <K> SubGraphImplementor<K> addTreatedMapKeySubgraph(
300+
MapAttribute<? super J, ? super K, ?> attribute,
301+
Class<K> type) {
302+
return findOrCreateAttributeNode( attribute.getName() ).makeKeySubGraph( type );
297303
}
298304

299-
@Override
300-
public <E> SubGraphImplementor<E> addElementSubgraph(PluralAttribute<? super J, ?, E> attribute) {
301-
throw new UnsupportedOperationException( "Not yet implemented" );
305+
@Override @SuppressWarnings("unchecked") // The JPA API is unsafe by nature
306+
public <X> SubGraphImplementor<X> addElementSubgraph(String attributeName) {
307+
return (SubGraphImplementor<X>) findOrCreateAttributeNode( attributeName ).makeSubGraph();
302308
}
303309

304310
@Override
305-
public <X> SubGraphImplementor<X> addElementSubgraph(String attributeName) {
306-
throw new UnsupportedOperationException( "Not yet implemented" );
311+
public <E> SubGraphImplementor<E> addElementSubgraph(PluralAttribute<? super J, ?, E> attribute) {
312+
return findOrCreateAttributeNode( attribute.getName() )
313+
.makeSubGraph( (ManagedDomainType<E>) attribute.getElementType() );
307314
}
308315

309316
@Override
310317
public <X> SubGraphImplementor<X> addElementSubgraph(String attributeName, Class<X> type) {
311-
throw new UnsupportedOperationException( "Not yet implemented" );
318+
return findOrCreateAttributeNode( attributeName ).makeSubGraph( type);
312319
}
313320

314321
@Override
315-
public <K> SubGraphImplementor<K> addMapKeySubgraph(MapAttribute<? super J, K, ?> attribute) {
316-
throw new UnsupportedOperationException( "Not yet implemented" );
322+
public <E> SubGraphImplementor<E> addTreatedElementSubgraph(
323+
PluralAttribute<? super J, ?, ? super E> attribute,
324+
Class<E> type) {
325+
return findOrCreateAttributeNode( attribute.getName() ).makeSubGraph( type );
317326
}
318327
}

hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import org.hibernate.graph.CannotBecomeEntityGraphException;
1111
import org.hibernate.graph.Graph;
12+
import org.hibernate.metamodel.model.domain.ManagedDomainType;
1213
import org.hibernate.metamodel.model.domain.PersistentAttribute;
1314

1415
import jakarta.persistence.metamodel.Attribute;
@@ -84,4 +85,10 @@ default boolean hasAttributeNode(Attribute<? super J, ?> attribute) {
8485

8586
@Override
8687
<AJ> SubGraphImplementor<AJ> addKeySubGraph(String attributeName, Class<AJ> subtype);
88+
89+
@Override
90+
<AJ> SubGraphImplementor<AJ> addSubGraph(PersistentAttribute<? super J, ? super AJ> attribute, ManagedDomainType<AJ> subtype);
91+
92+
@Override
93+
<AJ> SubGraphImplementor<AJ> addKeySubGraph(PersistentAttribute<? super J, ? super AJ> attribute, ManagedDomainType<AJ> subtype);
8794
}

hibernate-core/src/test/java/org/hibernate/orm/test/jpa/graphs/EntityGraphTest.java

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.orm.test.jpa.graphs;
66

7+
import jakarta.persistence.ManyToMany;
78
import jakarta.persistence.MapKey;
89
import java.util.HashMap;
910
import java.util.HashSet;
@@ -34,6 +35,8 @@
3435
import jakarta.persistence.criteria.Expression;
3536
import jakarta.persistence.criteria.Root;
3637

38+
import jakarta.persistence.metamodel.Attribute;
39+
import jakarta.persistence.metamodel.PluralAttribute;
3740
import org.hibernate.Hibernate;
3841
import org.hibernate.testing.util.uuid.SafeRandomUUIDGenerator;
3942
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
@@ -519,6 +522,127 @@ public void testTreatedSubgraph() {
519522
em.close();
520523
}
521524

525+
@Test
526+
public void testElementSubgraph() {
527+
EntityManager em = getOrCreateEntityManager();
528+
em.getTransaction().begin();
529+
Bar bar = new Bar();
530+
Foo foo = new Foo();
531+
Baz baz = new Baz();
532+
foo.baz = baz;
533+
foo.bar = bar;
534+
bar.foos.add( foo );
535+
baz.foos.add( foo );
536+
em.persist( bar );
537+
em.persist( baz );
538+
em.persist( foo );
539+
em.flush();
540+
em.clear();
541+
542+
EntityGraph<Bar> graph = em.createEntityGraph( Bar.class );
543+
Subgraph<Foo> subgraph = graph.addElementSubgraph( "foos", Foo.class );
544+
subgraph.addAttributeNode( "baz" );
545+
Bar b = em.find( graph, bar.id );
546+
assertTrue( Hibernate.isInitialized( b.foos ) );
547+
assertTrue( Hibernate.isInitialized( b.foos.iterator().next().baz ) );
548+
549+
em.getTransaction().rollback();
550+
em.close();
551+
}
552+
553+
@Test
554+
public void testTreatedElementSubgraph() {
555+
EntityManager em = getOrCreateEntityManager();
556+
em.getTransaction().begin();
557+
AnimalOwner animalOwner = new AnimalOwner();
558+
Dog dog = new Dog();
559+
Cat cat = new Cat();
560+
Kennel kennel = new Kennel();
561+
dog.kennel = kennel;
562+
animalOwner.animals.add( dog );
563+
animalOwner.animals.add( cat );
564+
em.persist( animalOwner );
565+
em.persist( kennel );
566+
em.persist( dog );
567+
em.persist( cat );
568+
em.flush();
569+
em.clear();
570+
571+
PluralAttribute<? super AnimalOwner, ?, Animal> animalsAttribute =
572+
(PluralAttribute<? super AnimalOwner, ?, Animal>)
573+
em.getEntityManagerFactory().getMetamodel()
574+
.entity( AnimalOwner.class )
575+
.getAttribute( "animals" );
576+
577+
EntityGraph<AnimalOwner> graph = em.createEntityGraph( AnimalOwner.class );
578+
Subgraph<Animal> subgraph = graph.addElementSubgraph( animalsAttribute );
579+
AnimalOwner owner = em.find( graph, animalOwner.id );
580+
assertTrue( Hibernate.isInitialized( owner.animals ) );
581+
assertEquals( 2, owner.animals.size() );
582+
owner.animals.forEach( animal -> {
583+
if (animal instanceof Dog d ) {
584+
assertFalse( Hibernate.isInitialized( d.kennel ) );
585+
}
586+
} );
587+
588+
em.clear();
589+
590+
// graph = em.createEntityGraph( AnimalOwner.class );
591+
// subgraph = graph.addElementSubgraph( animalsAttribute );
592+
// Subgraph<Dog> treated = graph.addTreatedElementSubgraph( animalsAttribute, Dog.class );
593+
// treated.addAttributeNode( "kennel" );
594+
// owner = em.find( graph, animalOwner.id );
595+
// assertTrue( Hibernate.isInitialized( owner.animals ) );
596+
// assertEquals( 2, owner.animals.size() );
597+
// owner.animals.forEach( animal -> {
598+
// if (animal instanceof Dog d ) {
599+
// assertTrue( Hibernate.isInitialized( d.kennel ) );
600+
// }
601+
// } );
602+
603+
em.getTransaction().rollback();
604+
em.close();
605+
}
606+
607+
@Test
608+
public void testTreatedElementSubgraph2() {
609+
EntityManager em = getOrCreateEntityManager();
610+
em.getTransaction().begin();
611+
AnimalOwner animalOwner = new AnimalOwner();
612+
Dog dog = new Dog();
613+
Cat cat = new Cat();
614+
Kennel kennel = new Kennel();
615+
dog.kennel = kennel;
616+
animalOwner.animals.add( dog );
617+
animalOwner.animals.add( cat );
618+
em.persist( animalOwner );
619+
em.persist( kennel );
620+
em.persist( dog );
621+
em.persist( cat );
622+
em.flush();
623+
em.clear();
624+
625+
Attribute<? super Dog, Kennel> kennelAttribute =
626+
(Attribute<? super Dog, Kennel>)
627+
em.getEntityManagerFactory().getMetamodel()
628+
.entity( Dog.class )
629+
.getAttribute( "kennel" );
630+
631+
EntityGraph<Animal> graph = em.createEntityGraph( Animal.class );
632+
Animal animal = em.find( graph, dog.id );
633+
assertFalse( Hibernate.isInitialized( ((Dog) animal).kennel ) );
634+
635+
em.clear();
636+
637+
graph = em.createEntityGraph( Animal.class );
638+
graph.addTreatedSubgraph( Dog.class ).addAttributeNode( kennelAttribute );
639+
animal = em.find( graph, dog.id );
640+
assertTrue( Hibernate.isInitialized( ((Dog) animal).kennel ) );
641+
642+
em.getTransaction().rollback();
643+
em.close();
644+
}
645+
522646
@Entity(name = "Foo")
523647
@Table(name = "foo")
524648
public static class Foo {
@@ -637,6 +761,9 @@ public static class AnimalOwner {
637761

638762
@ManyToOne(fetch = FetchType.LAZY)
639763
public Animal animal;
764+
765+
@ManyToMany
766+
public Set<Animal> animals = new HashSet<>();
640767
}
641768

642769
@Entity(name = "Animal")

0 commit comments

Comments
 (0)