Skip to content

Commit 3ba9cec

Browse files
committed
HHH-18714 add support for inheritance in entity graphs
1 parent d702496 commit 3ba9cec

File tree

10 files changed

+757
-95
lines changed

10 files changed

+757
-95
lines changed

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

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,27 @@
2020
import org.hibernate.graph.spi.AttributeNodeImplementor;
2121
import org.hibernate.graph.spi.GraphImplementor;
2222
import org.hibernate.graph.spi.RootGraphImplementor;
23+
import org.hibernate.graph.spi.SubGraphImplementor;
2324
import org.hibernate.metamodel.model.domain.EntityDomainType;
2425
import org.hibernate.metamodel.model.domain.ManagedDomainType;
2526
import org.hibernate.metamodel.model.domain.PersistentAttribute;
27+
import org.hibernate.metamodel.model.domain.internal.DomainModelHelper;
2628
import org.hibernate.query.sqm.SqmPathSource;
2729

2830
import static java.util.Collections.emptyList;
31+
import static java.util.Collections.emptyMap;
32+
import static org.hibernate.query.sqm.tree.SqmNode.log;
2933

3034
/**
31-
* Base class for {@link RootGraph} and {@link SubGraph} implementations.
35+
* Base class for {@link RootGraph} and {@link SubGraph} implementations.
3236
*
3337
* @author Steve Ebersole
3438
*/
3539
public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements GraphImplementor<J> {
3640
private final ManagedDomainType<J> managedType;
37-
private Map<PersistentAttribute<?,?>, AttributeNodeImplementor<?>> attrNodeMap;
41+
private Map<PersistentAttribute<?, ?>, AttributeNodeImplementor<?>> attrNodeMap;
42+
private Map<Class<? extends J>, SubGraphImplementor<? extends J>> subclassSubgraphs;
43+
3844

3945
public AbstractGraph(ManagedDomainType<J> managedType, boolean mutable) {
4046
super( mutable );
@@ -44,6 +50,7 @@ public AbstractGraph(ManagedDomainType<J> managedType, boolean mutable) {
4450
protected AbstractGraph(GraphImplementor<J> original, boolean mutable) {
4551
this( original.getGraphedType(), mutable );
4652
this.attrNodeMap = new ConcurrentHashMap<>( original.getAttributeNodeList().size() );
53+
this.subclassSubgraphs = Map.copyOf( original.getSubclassSubgraphs() );
4754
original.visitAttributeNodes(
4855
node -> attrNodeMap.put(
4956
node.getAttributeDescriptor(),
@@ -52,6 +59,53 @@ protected AbstractGraph(GraphImplementor<J> original, boolean mutable) {
5259
);
5360
}
5461

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<S>) 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 <S extends J> SubGraphImplementor<S> addSubclassSubgraph(SubGraphImplementor<S> subgraph) {
95+
if ( subclassSubgraphs == null ) {
96+
this.subclassSubgraphs = new HashMap<>();
97+
}
98+
99+
SubGraphImplementor<? extends J> previous = subclassSubgraphs.put( subgraph.getClassType(), subgraph );
100+
101+
if ( previous != null ) {
102+
log.debugf( "Adding sub-graph [%s] over-wrote existing [%s]", subgraph, previous );
103+
}
104+
105+
return subgraph;
106+
}
107+
108+
55109
@Override
56110
public ManagedDomainType<J> getGraphedType() {
57111
return managedType;
@@ -60,7 +114,7 @@ public ManagedDomainType<J> getGraphedType() {
60114
@Override
61115
public RootGraphImplementor<J> makeRootGraph(String name, boolean mutable) {
62116
if ( getGraphedType() instanceof EntityDomainType ) {
63-
return new RootGraphImpl<>( name, this, mutable);
117+
return new RootGraphImpl<>( name, this, mutable );
64118
}
65119

66120
throw new CannotBecomeEntityGraphException(
@@ -75,9 +129,23 @@ public void merge(GraphImplementor<? extends J> other) {
75129
return;
76130
}
77131

132+
other
133+
.getSubclassSubgraphs()
134+
.forEach( (otherSubType, otherSubTypeSubgraph) -> {
135+
136+
var alreadyExistingSubtypeSubgraph = subclassSubgraphs.get( otherSubType );
137+
if ( alreadyExistingSubtypeSubgraph == null ) {
138+
subclassSubgraphs.put( otherSubType, otherSubTypeSubgraph );
139+
}
140+
else {
141+
alreadyExistingSubtypeSubgraph.merge( (GraphImplementor) otherSubTypeSubgraph );
142+
}
143+
144+
} );
145+
78146
for ( AttributeNodeImplementor<?> attributeNode : other.getAttributeNodeImplementors() ) {
79147
final AttributeNodeImplementor<?> localAttributeNode = findAttributeNode(
80-
(PersistentAttribute<? extends J,?>) attributeNode.getAttributeDescriptor()
148+
(PersistentAttribute<? extends J, ?>) attributeNode.getAttributeDescriptor()
81149
);
82150
if ( localAttributeNode != null ) {
83151
// keep the local one, but merge in the incoming one
@@ -110,8 +178,8 @@ public AttributeNodeImplementor<?> addAttributeNode(AttributeNodeImplementor<?>
110178
attrNodeMap.put( incomingAttributeNode.getAttributeDescriptor(), attributeNode );
111179
}
112180
else {
113-
@SuppressWarnings("rawtypes")
114-
final AttributeNodeImplementor attributeNodeFinal = attributeNode;
181+
@SuppressWarnings("rawtypes") final AttributeNodeImplementor attributeNodeFinal = attributeNode;
182+
attributeNodeFinal.getSubgraph().merge( this );
115183
incomingAttributeNode.visitSubGraphs(
116184
// we assume the subGraph has been properly copied if needed
117185
(subType, subGraph) -> attributeNodeFinal.addSubGraph( subGraph )
@@ -128,6 +196,7 @@ public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(String attributeName)
128196
if ( attribute instanceof SqmPathSource && ( (SqmPathSource<?>) attribute ).isGeneric() ) {
129197
attribute = managedType.findConcreteGenericAttribute( attributeName );
130198
}
199+
131200
return attribute == null ? null : findAttributeNode( (PersistentAttribute<? extends J, AJ>) attribute );
132201
}
133202

@@ -138,7 +207,7 @@ public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(PersistentAttribute<?
138207
}
139208

140209
@Override
141-
@SuppressWarnings({"unchecked", "rawtypes"})
210+
@SuppressWarnings({ "unchecked", "rawtypes" })
142211
public List<AttributeNode<?>> getGraphAttributeNodes() {
143212
return (List) getAttributeNodeImplementors();
144213
}
@@ -174,7 +243,7 @@ public <AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(PersistentAtt
174243
}
175244

176245
if ( attrNode == null ) {
177-
attrNode = new AttributeNodeImpl<>(attribute, isMutable());
246+
attrNode = new AttributeNodeImpl<>( attribute, isMutable() );
178247
attrNodeMap.put( attribute, attrNode );
179248
}
180249

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

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
package org.hibernate.graph.internal;
88

9+
import java.util.Collections;
910
import java.util.HashMap;
1011
import java.util.Locale;
1112
import java.util.Map;
@@ -22,6 +23,7 @@
2223
import org.hibernate.metamodel.model.domain.SimpleDomainType;
2324

2425
import org.hibernate.metamodel.model.domain.internal.DomainModelHelper;
26+
2527
import org.jboss.logging.Logger;
2628

2729
import static java.util.Collections.emptyMap;
@@ -37,24 +39,25 @@ public class AttributeNodeImpl<J>
3739
implements AttributeNodeImplementor<J> {
3840
private final PersistentAttribute<?, J> attribute;
3941

40-
private Map<Class<? extends J>, SubGraphImplementor<? extends J>> subGraphMap;
4142
private Map<Class<? extends J>, SubGraphImplementor<? extends J>> keySubGraphMap;
43+
private SubGraphImplementor<J> subgraph;
44+
4245

4346
public <X> AttributeNodeImpl(PersistentAttribute<X, J> attribute, boolean mutable) {
44-
this(attribute, null, null, mutable);
47+
this( attribute, null, null, mutable );
4548
}
4649

4750
/**
4851
* Intended only for use from making a copy
4952
*/
5053
private AttributeNodeImpl(
5154
PersistentAttribute<?, J> attribute,
52-
Map<Class<? extends J>, SubGraphImplementor<? extends J>> subGraphMap,
55+
SubGraphImplementor<J> subgraph,
5356
Map<Class<? extends J>, SubGraphImplementor<? extends J>> keySubGraphMap,
5457
boolean mutable) {
5558
super( mutable );
5659
this.attribute = attribute;
57-
this.subGraphMap = subGraphMap;
60+
this.subgraph = subgraph;
5861
this.keySubGraphMap = keySubGraphMap;
5962
}
6063

@@ -70,7 +73,24 @@ public PersistentAttribute<?, J> getAttributeDescriptor() {
7073

7174
@Override
7275
public Map<Class<? extends J>, SubGraphImplementor<? extends J>> getSubGraphMap() {
73-
return subGraphMap == null ? emptyMap() : subGraphMap;
76+
if ( this.subgraph == null ) {
77+
return emptyMap();
78+
}
79+
80+
var subclassSubgraphs = subgraph.getSubclassSubgraphs();
81+
82+
if ( subclassSubgraphs.isEmpty() ) {
83+
return Collections.singletonMap( subgraph.getClassType(), subgraph );
84+
}
85+
86+
subclassSubgraphs.put( subgraph.getClassType(), subgraph );
87+
88+
return subclassSubgraphs;
89+
}
90+
91+
@Override
92+
public SubGraphImplementor<J> getSubgraph() {
93+
return subgraph;
7494
}
7595

7696
@Override
@@ -95,10 +115,18 @@ public <S extends J> SubGraphImplementor<S> makeSubGraph(ManagedDomainType<S> su
95115

96116
private <S extends J> SubGraphImplementor<S> internalMakeSubgraph(ManagedDomainType<S> type) {
97117
assert type != null;
118+
98119
log.debugf( "Making sub-graph : ( (%s) %s )", type.getTypeName(), getAttributeName() );
99-
final SubGraphImplementor<S> subGraph = DomainModelHelper.makeSubGraph( type, type.getBindableJavaType() );
100-
internalAddSubGraph( subGraph );
101-
return subGraph;
120+
121+
if ( this.subgraph == null ) {
122+
this.subgraph = new SubGraphImpl<>( valueGraphTypeAsManaged(), true );
123+
}
124+
125+
if ( type.equals( valueGraphTypeAsManaged() ) ) {
126+
return (SubGraphImplementor) this.subgraph;
127+
}
128+
129+
return this.subgraph.addTreatedSubgraph( type.getJavaType() );
102130
}
103131

104132
@SuppressWarnings("unchecked")
@@ -124,18 +152,30 @@ private <T extends J> ManagedDomainType<T> valueGraphTypeAsManaged() {
124152
private <S extends J> SubGraphImplementor<S> internalMakeSubgraph(Class<S> subType) {
125153
verifyMutability();
126154
final ManagedDomainType<S> managedType = valueGraphTypeAsManaged();
127-
return internalMakeSubgraph( findSubType( managedType, subType == null ? managedType.getJavaType() : subType ) );
155+
return internalMakeSubgraph( findSubType(
156+
managedType,
157+
subType == null ? managedType.getJavaType() : subType
158+
) );
128159
}
129160

130161
protected void internalAddSubGraph(SubGraphImplementor<? extends J> subGraph) {
131162
log.tracef( "Adding sub-graph : ( (%s) %s )", subGraph.getGraphedType().getTypeName(), getAttributeName() );
132-
if ( subGraphMap == null ) {
133-
subGraphMap = new HashMap<>();
163+
164+
if ( this.subgraph == null ) {
165+
this.subgraph = new SubGraphImpl<>( valueGraphTypeAsManaged(), true );
134166
}
135-
final SubGraphImplementor<? extends J> previous = subGraphMap.put( subGraph.getClassType(), subGraph );
136-
if ( previous != null ) {
137-
log.debugf( "Adding sub-graph [%s] over-wrote existing [%s]", subGraph, previous );
167+
168+
ManagedDomainType<?> incomingSubGraphType = subGraph.getGraphedType();
169+
170+
if ( incomingSubGraphType.equals( this.subgraph.getGraphedType() ) ) {
171+
this.subgraph.merge( subGraph );
172+
return;
173+
}
174+
175+
if ( this.subgraph.getGraphedType().getSubTypes().contains( incomingSubGraphType ) ) {
176+
this.subgraph.addSubclassSubgraph( subGraph );
138177
}
178+
139179
}
140180

141181
@Override
@@ -220,7 +260,10 @@ public <S extends J> void addKeySubGraph(Class<S> subType, SubGraph<S> subGraph)
220260
@Override
221261
public AttributeNodeImplementor<J> makeCopy(boolean mutable) {
222262
return new AttributeNodeImpl<>(
223-
this.attribute, makeMapCopy( mutable, subGraphMap ), makeMapCopy( mutable, keySubGraphMap ), mutable
263+
this.attribute,
264+
this.subgraph == null ? null : this.subgraph.makeCopy( mutable ),
265+
makeMapCopy( mutable, keySubGraphMap ),
266+
mutable
224267
);
225268
}
226269

@@ -232,32 +275,21 @@ private Map<Class<? extends J>, SubGraphImplementor<? extends J>> makeMapCopy(
232275
}
233276
else {
234277
return nodeMap.entrySet().stream()
235-
.map(entry -> Map.entry( entry.getKey(), entry.getValue().makeCopy( mutable ) ))
236-
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
278+
.map( entry -> Map.entry( entry.getKey(), entry.getValue().makeCopy( mutable ) ) )
279+
.collect( Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue ) );
237280
}
238281
}
239282

240283
@Override
241284
public void merge(AttributeNodeImplementor<?> attributeNode) {
242-
attributeNode.visitSubGraphs(
243-
(incomingSubType, incomingGraph) -> {
244-
SubGraphImplementor<?> existing;
245-
if ( subGraphMap == null ) {
246-
subGraphMap = new HashMap<>();
247-
existing = null;
248-
}
249-
else {
250-
existing = subGraphMap.get( incomingSubType );
251-
}
252285

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

262294
attributeNode.visitKeySubGraphs(
263295
(incomingSubType, incomingGraph) -> {

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public RootGraphImpl(String name, EntityDomainType<J> entityType) {
3232
}
3333

3434
public RootGraphImpl(String name, GraphImplementor<J> original, boolean mutable) {
35-
super(original, mutable);
35+
super( original, mutable );
3636
this.name = name;
3737
}
3838

@@ -43,12 +43,12 @@ public String getName() {
4343

4444
@Override
4545
public RootGraphImplementor<J> makeCopy(boolean mutable) {
46-
return new RootGraphImpl<>( null, this, mutable);
46+
return new RootGraphImpl<>( null, this, mutable );
4747
}
4848

4949
@Override
5050
public SubGraphImplementor<J> makeSubGraph(boolean mutable) {
51-
return new SubGraphImpl<>(this, mutable);
51+
return new SubGraphImpl<>( this, mutable );
5252
}
5353

5454
@Override
@@ -57,8 +57,9 @@ public RootGraphImplementor<J> makeRootGraph(String name, boolean mutable) {
5757
}
5858

5959
@Override
60+
@SuppressWarnings({ "unchecked", "rawtypes" })
6061
public <T1> SubGraph<? extends T1> addSubclassSubgraph(Class<? extends T1> type) {
61-
throw new UnsupportedOperationException();
62+
return addTreatedSubgraph( (Class) type );
6263
}
6364

6465
@Override

0 commit comments

Comments
 (0)