Skip to content

Commit c16fb1c

Browse files
committed
HHH-18714 add support for inheritance in entity graphs
1 parent e006427 commit c16fb1c

File tree

10 files changed

+764
-122
lines changed

10 files changed

+764
-122
lines changed

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

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,28 @@
1919
import org.hibernate.graph.spi.AttributeNodeImplementor;
2020
import org.hibernate.graph.spi.GraphImplementor;
2121
import org.hibernate.graph.spi.RootGraphImplementor;
22+
import org.hibernate.graph.spi.SubGraphImplementor;
2223
import org.hibernate.metamodel.model.domain.EntityDomainType;
2324
import org.hibernate.metamodel.model.domain.ManagedDomainType;
2425
import org.hibernate.metamodel.model.domain.PersistentAttribute;
26+
import org.hibernate.metamodel.model.domain.internal.DomainModelHelper;
2527
import org.hibernate.query.sqm.SqmPathSource;
2628

2729
import jakarta.persistence.metamodel.Attribute;
2830

2931
import static java.util.Collections.emptyList;
32+
import static java.util.Collections.emptyMap;
3033

3134
/**
32-
* Base class for {@link RootGraph} and {@link SubGraph} implementations.
35+
* Base class for {@link RootGraph} and {@link SubGraph} implementations.
3336
*
3437
* @author Steve Ebersole
3538
*/
3639
public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements GraphImplementor<J> {
3740
private final ManagedDomainType<J> managedType;
38-
private Map<PersistentAttribute<?,?>, AttributeNodeImplementor<?>> attrNodeMap;
41+
42+
private Map<PersistentAttribute<?, ?>, AttributeNodeImplementor<?>> attrNodeMap;
43+
private Map<Class<? extends J>, SubGraphImplementor<? extends J>> subclassSubgraphs;
3944

4045
public AbstractGraph(ManagedDomainType<J> managedType, boolean mutable) {
4146
super( mutable );
@@ -45,6 +50,7 @@ public AbstractGraph(ManagedDomainType<J> managedType, boolean mutable) {
4550
protected AbstractGraph(GraphImplementor<J> original, boolean mutable) {
4651
this( original.getGraphedType(), mutable );
4752
this.attrNodeMap = new ConcurrentHashMap<>( original.getAttributeNodeList().size() );
53+
this.subclassSubgraphs = Map.copyOf( original.getSubclassSubgraphs() );
4854
original.visitAttributeNodes(
4955
node -> attrNodeMap.put(
5056
node.getAttributeDescriptor(),
@@ -53,6 +59,43 @@ protected AbstractGraph(GraphImplementor<J> original, boolean mutable) {
5359
);
5460
}
5561

62+
@Override
63+
public Map<Class<? extends J>, SubGraphImplementor<? extends J>> getSubclassSubgraphs() {
64+
return subclassSubgraphs == null ? emptyMap() : subclassSubgraphs;
65+
}
66+
67+
@Override
68+
public <S extends J> SubGraphImplementor<S> getSubclassSubgraph(Class<S> subtype) {
69+
return subclassSubgraphs == null ? null : (SubGraphImplementor) subclassSubgraphs.get( subtype );
70+
}
71+
72+
@Override
73+
public <S extends J> SubGraphImplementor<S> addTreatedSubgraph(Class<S> subType) {
74+
if ( subclassSubgraphs == null ) {
75+
this.subclassSubgraphs = new HashMap<>();
76+
}
77+
78+
final SubGraphImplementor<S> existingSubgraph = (SubGraphImplementor) subclassSubgraphs.get( subType );
79+
80+
if ( existingSubgraph != null ) {
81+
return existingSubgraph;
82+
}
83+
84+
ManagedDomainType<S> subTypeEntityDomainType = DomainModelHelper.findSubType( this.managedType, subType );
85+
86+
SubGraphImplementor<S> subgraph = new SubGraphImpl<S>( subTypeEntityDomainType, (GraphImplementor) this, true );
87+
88+
subclassSubgraphs.put( subType, subgraph );
89+
90+
return subgraph;
91+
}
92+
93+
@Override
94+
public <Y> SubGraphImplementor<Y> addTreatedSubgraph(Attribute<? super J, ? super Y> attribute, Class<Y> type) {
95+
AttributeNodeImplementor<Y> attributeNode = findOrCreateAttributeNode( attribute.getName() );
96+
return attributeNode.makeSubGraph( type );
97+
}
98+
5699
@Override
57100
public ManagedDomainType<J> getGraphedType() {
58101
return managedType;
@@ -61,7 +104,7 @@ public ManagedDomainType<J> getGraphedType() {
61104
@Override
62105
public RootGraphImplementor<J> makeRootGraph(String name, boolean mutable) {
63106
if ( getGraphedType() instanceof EntityDomainType ) {
64-
return new RootGraphImpl<>( name, this, mutable);
107+
return new RootGraphImpl<>( name, this, mutable );
65108
}
66109

67110
throw new CannotBecomeEntityGraphException(
@@ -76,9 +119,24 @@ public void merge(GraphImplementor<? extends J> other) {
76119
return;
77120
}
78121

122+
other
123+
.getSubclassSubgraphs()
124+
.forEach( (otherSubType, otherSubTypeSubgraph) -> {
125+
126+
var alreadyExistingSubtypeSubgraph = subclassSubgraphs.get( otherSubType );
127+
if ( alreadyExistingSubtypeSubgraph == null ) {
128+
subclassSubgraphs.put( otherSubType, otherSubTypeSubgraph );
129+
}
130+
else {
131+
alreadyExistingSubtypeSubgraph.merge( (GraphImplementor) otherSubTypeSubgraph );
132+
}
133+
134+
} );
135+
136+
79137
for ( AttributeNodeImplementor<?> attributeNode : other.getAttributeNodeImplementors() ) {
80138
final AttributeNodeImplementor<?> localAttributeNode = findAttributeNode(
81-
(PersistentAttribute<? super J,?>) attributeNode.getAttributeDescriptor()
139+
(PersistentAttribute<? super J, ?>) attributeNode.getAttributeDescriptor()
82140
);
83141
if ( localAttributeNode != null ) {
84142
// keep the local one, but merge in the incoming one
@@ -146,8 +204,8 @@ public AttributeNodeImplementor<?> addAttributeNode(AttributeNodeImplementor<?>
146204
attrNodeMap.put( incomingAttributeNode.getAttributeDescriptor(), attributeNode );
147205
}
148206
else {
149-
@SuppressWarnings("rawtypes")
150-
final AttributeNodeImplementor attributeNodeFinal = attributeNode;
207+
@SuppressWarnings("rawtypes") final AttributeNodeImplementor attributeNodeFinal = attributeNode;
208+
attributeNodeFinal.getSubgraph().merge( this );
151209
incomingAttributeNode.visitSubGraphs(
152210
// we assume the subGraph has been properly copied if needed
153211
(subType, subGraph) -> attributeNodeFinal.addSubGraph( subGraph )
@@ -161,7 +219,7 @@ public AttributeNodeImplementor<?> addAttributeNode(AttributeNodeImplementor<?>
161219
@SuppressWarnings("unchecked")
162220
public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(String attributeName) {
163221
PersistentAttribute<? super J, ?> attribute = managedType.findAttributeInSuperTypes( attributeName );
164-
if ( attribute instanceof SqmPathSource && ( (SqmPathSource<?>) attribute ).isGeneric() ) {
222+
if ( attribute instanceof SqmPathSource && ((SqmPathSource<?>) attribute).isGeneric() ) {
165223
attribute = managedType.findConcreteGenericAttribute( attributeName );
166224
}
167225
return attribute == null ? null : findAttributeNode( (PersistentAttribute<? super J, AJ>) attribute );
@@ -185,7 +243,8 @@ public List<AttributeNodeImplementor<?>> getAttributeNodeImplementors() {
185243
}
186244

187245
@Override
188-
public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(String attributeName) throws CannotContainSubGraphException {
246+
public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(String attributeName)
247+
throws CannotContainSubGraphException {
189248
return findOrCreateAttributeNode( attributeName );
190249
}
191250

@@ -208,7 +267,8 @@ public void addAttributeNodes(String... attributeNames) {
208267
}
209268
}
210269

211-
@Override @SafeVarargs
270+
@Override
271+
@SafeVarargs
212272
public final void addAttributeNodes(Attribute<? super J, ?>... attributes) {
213273
for ( int i = 0; i < attributes.length; i++ ) {
214274
addAttributeNode( attributes[i] );
@@ -245,7 +305,7 @@ public <AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(PersistentAtt
245305
}
246306

247307
if ( attrNode == null ) {
248-
attrNode = new AttributeNodeImpl<>(attribute, isMutable());
308+
attrNode = new AttributeNodeImpl<>( attribute, isMutable() );
249309
attrNodeMap.put( attribute, attrNode );
250310
}
251311

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

Lines changed: 70 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.graph.internal;
66

7+
import java.util.Collections;
78
import java.util.HashMap;
89
import java.util.Locale;
910
import java.util.Map;
@@ -20,6 +21,7 @@
2021
import org.hibernate.metamodel.model.domain.SimpleDomainType;
2122

2223
import org.hibernate.metamodel.model.domain.internal.DomainModelHelper;
24+
2325
import org.jboss.logging.Logger;
2426

2527
import static java.util.Collections.emptyMap;
@@ -35,24 +37,25 @@ public class AttributeNodeImpl<J>
3537
implements AttributeNodeImplementor<J> {
3638
private final PersistentAttribute<?, J> attribute;
3739

38-
private Map<Class<? extends J>, SubGraphImplementor<? extends J>> subGraphMap;
3940
private Map<Class<? extends J>, SubGraphImplementor<? extends J>> keySubGraphMap;
41+
private SubGraphImplementor<J> subgraph;
42+
4043

4144
public <X> AttributeNodeImpl(PersistentAttribute<X, J> attribute, boolean mutable) {
42-
this(attribute, null, null, mutable);
45+
this( attribute, null, null, mutable );
4346
}
4447

4548
/**
4649
* Intended only for use from making a copy
4750
*/
4851
private AttributeNodeImpl(
4952
PersistentAttribute<?, J> attribute,
50-
Map<Class<? extends J>, SubGraphImplementor<? extends J>> subGraphMap,
53+
SubGraphImplementor<J> subgraph,
5154
Map<Class<? extends J>, SubGraphImplementor<? extends J>> keySubGraphMap,
5255
boolean mutable) {
5356
super( mutable );
5457
this.attribute = attribute;
55-
this.subGraphMap = subGraphMap;
58+
this.subgraph = subgraph;
5659
this.keySubGraphMap = keySubGraphMap;
5760
}
5861

@@ -68,7 +71,24 @@ public PersistentAttribute<?, J> getAttributeDescriptor() {
6871

6972
@Override
7073
public Map<Class<? extends J>, SubGraphImplementor<? extends J>> getSubGraphMap() {
71-
return subGraphMap == null ? emptyMap() : subGraphMap;
74+
if ( this.subgraph == null ) {
75+
return emptyMap();
76+
}
77+
78+
var subclassSubgraphs = subgraph.getSubclassSubgraphs();
79+
80+
if ( subclassSubgraphs.isEmpty() ) {
81+
return Collections.singletonMap( subgraph.getClassType(), subgraph );
82+
}
83+
84+
subclassSubgraphs.put( subgraph.getClassType(), subgraph );
85+
86+
return subclassSubgraphs;
87+
}
88+
89+
@Override
90+
public SubGraphImplementor<J> getSubgraph() {
91+
return subgraph;
7292
}
7393

7494
@Override
@@ -91,12 +111,21 @@ public <S extends J> SubGraphImplementor<S> makeSubGraph(ManagedDomainType<S> su
91111
return internalMakeSubgraph( subtype );
92112
}
93113

114+
@SuppressWarnings({"unchecked"})
94115
private <S extends J> SubGraphImplementor<S> internalMakeSubgraph(ManagedDomainType<S> type) {
95116
assert type != null;
117+
96118
log.debugf( "Making sub-graph : ( (%s) %s )", type.getTypeName(), getAttributeName() );
97-
final SubGraphImplementor<S> subGraph = DomainModelHelper.makeSubGraph( type, type.getBindableJavaType() );
98-
internalAddSubGraph( subGraph );
99-
return subGraph;
119+
120+
if ( this.subgraph == null ) {
121+
this.subgraph = new SubGraphImpl<>( valueGraphTypeAsManaged(), true );
122+
}
123+
124+
if ( type.equals( valueGraphTypeAsManaged() ) ) {
125+
return (SubGraphImplementor<S>) this.subgraph;
126+
}
127+
128+
return this.subgraph.addTreatedSubgraph( type.getJavaType() );
100129
}
101130

102131
@SuppressWarnings("unchecked")
@@ -122,17 +151,29 @@ private <T extends J> ManagedDomainType<T> valueGraphTypeAsManaged() {
122151
private <S extends J> SubGraphImplementor<S> internalMakeSubgraph(Class<S> subType) {
123152
verifyMutability();
124153
final ManagedDomainType<S> managedType = valueGraphTypeAsManaged();
125-
return internalMakeSubgraph( findSubType( managedType, subType == null ? managedType.getJavaType() : subType ) );
154+
return internalMakeSubgraph( findSubType(
155+
managedType,
156+
subType == null ? managedType.getJavaType() : subType
157+
) );
126158
}
127159

128-
protected void internalAddSubGraph(SubGraphImplementor<? extends J> subGraph) {
160+
protected <S extends J> void internalAddSubGraph(SubGraphImplementor<S> subGraph) {
129161
log.tracef( "Adding sub-graph : ( (%s) %s )", subGraph.getGraphedType().getTypeName(), getAttributeName() );
130-
if ( subGraphMap == null ) {
131-
subGraphMap = new HashMap<>();
162+
163+
if ( this.subgraph == null ) {
164+
this.subgraph = new SubGraphImpl<>( valueGraphTypeAsManaged(), true );
132165
}
133-
final SubGraphImplementor<? extends J> previous = subGraphMap.put( subGraph.getClassType(), subGraph );
134-
if ( previous != null ) {
135-
log.debugf( "Adding sub-graph [%s] over-wrote existing [%s]", subGraph, previous );
166+
167+
ManagedDomainType<S> incomingSubGraphType = subGraph.getGraphedType();
168+
169+
if ( incomingSubGraphType.equals( this.subgraph.getGraphedType() ) ) {
170+
this.subgraph.merge( subGraph );
171+
return;
172+
}
173+
174+
if ( this.subgraph.getGraphedType().getSubTypes().contains( incomingSubGraphType ) ) {
175+
var subclassSubgraph = this.subgraph.addTreatedSubgraph( incomingSubGraphType.getBindableJavaType() );
176+
subclassSubgraph.merge( subGraph );
136177
}
137178
}
138179

@@ -218,7 +259,10 @@ public <S extends J> void addKeySubGraph(Class<S> subType, SubGraph<S> subGraph)
218259
@Override
219260
public AttributeNodeImplementor<J> makeCopy(boolean mutable) {
220261
return new AttributeNodeImpl<>(
221-
this.attribute, makeMapCopy( mutable, subGraphMap ), makeMapCopy( mutable, keySubGraphMap ), mutable
262+
this.attribute,
263+
this.subgraph == null ? null : this.subgraph.makeCopy( mutable ),
264+
makeMapCopy( mutable, keySubGraphMap ),
265+
mutable
222266
);
223267
}
224268

@@ -230,32 +274,22 @@ private Map<Class<? extends J>, SubGraphImplementor<? extends J>> makeMapCopy(
230274
}
231275
else {
232276
return nodeMap.entrySet().stream()
233-
.map(entry -> Map.entry( entry.getKey(), entry.getValue().makeCopy( mutable ) ))
234-
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
277+
.map( entry -> Map.entry( entry.getKey(), entry.getValue().makeCopy( mutable ) ) )
278+
.collect( Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue ) );
235279
}
236280
}
237281

238282
@Override
283+
@SuppressWarnings({"unchecked", "rawtypes"})
239284
public void merge(AttributeNodeImplementor<?> attributeNode) {
240-
attributeNode.visitSubGraphs(
241-
(incomingSubType, incomingGraph) -> {
242-
SubGraphImplementor<?> existing;
243-
if ( subGraphMap == null ) {
244-
subGraphMap = new HashMap<>();
245-
existing = null;
246-
}
247-
else {
248-
existing = subGraphMap.get( incomingSubType );
249-
}
250285

251-
if ( existing != null ) {
252-
existing.merge( (GraphImplementor) incomingGraph );
253-
}
254-
else {
255-
internalAddSubGraph( (SubGraphImplementor) incomingGraph.makeCopy( true ) );
256-
}
257-
}
258-
);
286+
287+
if ( this.subgraph != null ) {
288+
this.subgraph.merge( (SubGraphImplementor) attributeNode.getSubgraph() );
289+
}
290+
else {
291+
this.subgraph = (SubGraphImplementor) attributeNode.getSubgraph();
292+
}
259293

260294
attributeNode.visitKeySubGraphs(
261295
(incomingSubType, incomingGraph) -> {

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

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import org.hibernate.graph.spi.SubGraphImplementor;
1111
import org.hibernate.metamodel.model.domain.EntityDomainType;
1212

13-
import jakarta.persistence.metamodel.Attribute;
1413
import jakarta.persistence.metamodel.MapAttribute;
1514
import jakarta.persistence.metamodel.PluralAttribute;
1615

@@ -62,18 +61,6 @@ public RootGraphImplementor<J> makeRootGraph(String name, boolean mutable) {
6261
return !mutable && !isMutable() ? this : super.makeRootGraph( name, mutable );
6362
}
6463

65-
@Override
66-
public <S extends J> SubGraphImplementor<S> addTreatedSubgraph(Class<S> type) {
67-
//noinspection unchecked,rawtypes
68-
return new SubGraphImpl(this, false );
69-
}
70-
71-
@Override
72-
public <Y> SubGraphImplementor<Y> addTreatedSubgraph(Attribute<? super J, ? super Y> attribute, Class<Y> type) {
73-
//noinspection unchecked
74-
return (SubGraphImplementor<Y>) super.makeRootGraph( name, false );
75-
}
76-
7764
@Override
7865
public <E> SubGraphImplementor<E> addTreatedElementSubgraph(
7966
PluralAttribute<? super J, ?, ? super E> attribute,
@@ -88,7 +75,7 @@ public <K> SubGraphImplementor<K> addTreatedMapKeySubgraph(MapAttribute<? super
8875

8976
@Override
9077
public <T1> SubGraphImplementor<? extends T1> addSubclassSubgraph(Class<? extends T1> type) {
91-
throw new UnsupportedOperationException();
78+
return addTreatedSubgraph( (Class) type );
9279
}
9380

9481
@Override

0 commit comments

Comments
 (0)