Skip to content

Commit dfc8848

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

File tree

10 files changed

+2029
-1402
lines changed

10 files changed

+2029
-1402
lines changed

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

Lines changed: 212 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -20,164 +20,228 @@
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> {
36-
private final ManagedDomainType<J> managedType;
37-
private Map<PersistentAttribute<?,?>, AttributeNodeImplementor<?>> attrNodeMap;
38-
39-
public AbstractGraph(ManagedDomainType<J> managedType, boolean mutable) {
40-
super( mutable );
41-
this.managedType = managedType;
42-
}
43-
44-
protected AbstractGraph(GraphImplementor<J> original, boolean mutable) {
45-
this( original.getGraphedType(), mutable );
46-
this.attrNodeMap = new ConcurrentHashMap<>( original.getAttributeNodeList().size() );
47-
original.visitAttributeNodes(
48-
node -> attrNodeMap.put(
49-
node.getAttributeDescriptor(),
50-
node.makeCopy( mutable )
51-
)
52-
);
53-
}
54-
55-
@Override
56-
public ManagedDomainType<J> getGraphedType() {
57-
return managedType;
58-
}
59-
60-
@Override
61-
public RootGraphImplementor<J> makeRootGraph(String name, boolean mutable) {
62-
if ( getGraphedType() instanceof EntityDomainType ) {
63-
return new RootGraphImpl<>( name, this, mutable);
64-
}
65-
66-
throw new CannotBecomeEntityGraphException(
67-
"Cannot transform Graph to RootGraph - " + getGraphedType() + " is not an EntityType"
68-
);
69-
}
70-
71-
@Override
72-
@SuppressWarnings("unchecked")
73-
public void merge(GraphImplementor<? extends J> other) {
74-
if ( other == null ) {
75-
return;
76-
}
77-
78-
for ( AttributeNodeImplementor<?> attributeNode : other.getAttributeNodeImplementors() ) {
79-
final AttributeNodeImplementor<?> localAttributeNode = findAttributeNode(
80-
(PersistentAttribute<? extends J,?>) attributeNode.getAttributeDescriptor()
81-
);
82-
if ( localAttributeNode != null ) {
83-
// keep the local one, but merge in the incoming one
84-
localAttributeNode.merge( attributeNode );
85-
}
86-
else {
87-
addAttributeNode( attributeNode.makeCopy( true ) );
88-
}
89-
}
90-
91-
}
92-
93-
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
94-
// AttributeNode handling
95-
96-
@Override
97-
public AttributeNodeImplementor<?> addAttributeNode(AttributeNodeImplementor<?> incomingAttributeNode) {
98-
verifyMutability();
99-
100-
AttributeNodeImplementor<?> attributeNode = null;
101-
if ( attrNodeMap == null ) {
102-
attrNodeMap = new HashMap<>();
103-
}
104-
else {
105-
attributeNode = attrNodeMap.get( incomingAttributeNode.getAttributeDescriptor() );
106-
}
107-
108-
if ( attributeNode == null ) {
109-
attributeNode = incomingAttributeNode;
110-
attrNodeMap.put( incomingAttributeNode.getAttributeDescriptor(), attributeNode );
111-
}
112-
else {
113-
@SuppressWarnings("rawtypes")
114-
final AttributeNodeImplementor attributeNodeFinal = attributeNode;
115-
incomingAttributeNode.visitSubGraphs(
116-
// we assume the subGraph has been properly copied if needed
117-
(subType, subGraph) -> attributeNodeFinal.addSubGraph( subGraph )
118-
);
119-
}
120-
121-
return attributeNode;
122-
}
123-
124-
@Override
125-
@SuppressWarnings("unchecked")
126-
public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(String attributeName) {
127-
PersistentAttribute<? super J, ?> attribute = managedType.findAttributeInSuperTypes( attributeName );
128-
if ( attribute instanceof SqmPathSource && ( (SqmPathSource<?>) attribute ).isGeneric() ) {
129-
attribute = managedType.findConcreteGenericAttribute( attributeName );
130-
}
131-
return attribute == null ? null : findAttributeNode( (PersistentAttribute<? extends J, AJ>) attribute );
132-
}
133-
134-
@Override
135-
@SuppressWarnings("unchecked")
136-
public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(PersistentAttribute<? extends J, AJ> attribute) {
137-
return attrNodeMap == null ? null : (AttributeNodeImplementor<AJ>) attrNodeMap.get( attribute );
138-
}
139-
140-
@Override
141-
@SuppressWarnings({"unchecked", "rawtypes"})
142-
public List<AttributeNode<?>> getGraphAttributeNodes() {
143-
return (List) getAttributeNodeImplementors();
144-
}
145-
146-
@Override
147-
public List<AttributeNodeImplementor<?>> getAttributeNodeImplementors() {
148-
return attrNodeMap == null ? emptyList() : new ArrayList<>( attrNodeMap.values() );
149-
}
150-
151-
@Override
152-
public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(String attributeName)
153-
throws CannotContainSubGraphException {
154-
return findOrCreateAttributeNode( attributeName );
155-
}
156-
157-
@Override
158-
public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(PersistentAttribute<? extends J, AJ> attribute)
159-
throws CannotContainSubGraphException {
160-
return findOrCreateAttributeNode( attribute );
161-
}
162-
163-
@Override
164-
@SuppressWarnings("unchecked")
165-
public <AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(PersistentAttribute<? extends J, AJ> attribute) {
166-
verifyMutability();
167-
168-
AttributeNodeImplementor<AJ> attrNode = null;
169-
if ( attrNodeMap == null ) {
170-
attrNodeMap = new HashMap<>();
171-
}
172-
else {
173-
attrNode = (AttributeNodeImplementor<AJ>) attrNodeMap.get( attribute );
174-
}
175-
176-
if ( attrNode == null ) {
177-
attrNode = new AttributeNodeImpl<>(attribute, isMutable());
178-
attrNodeMap.put( attribute, attrNode );
179-
}
180-
181-
return attrNode;
182-
}
40+
private final ManagedDomainType<J> managedType;
41+
private Map<PersistentAttribute<?, ?>, AttributeNodeImplementor<?>> attrNodeMap;
42+
private Map<Class<? extends J>, SubGraphImplementor<? extends J>> subclassSubgraphs;
43+
44+
45+
public AbstractGraph(ManagedDomainType<J> managedType, boolean mutable) {
46+
super(mutable);
47+
this.managedType = managedType;
48+
}
49+
50+
protected AbstractGraph(GraphImplementor<J> original, boolean mutable) {
51+
this(original.getGraphedType(), mutable);
52+
this.attrNodeMap = new ConcurrentHashMap<>(original.getAttributeNodeList().size());
53+
this.subclassSubgraphs = Map.copyOf(original.getSubclassSubgraphs());
54+
original.visitAttributeNodes(
55+
node -> attrNodeMap.put(
56+
node.getAttributeDescriptor(),
57+
node.makeCopy(mutable)
58+
)
59+
);
60+
}
61+
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+
109+
@Override
110+
public ManagedDomainType<J> getGraphedType() {
111+
return managedType;
112+
}
113+
114+
@Override
115+
public RootGraphImplementor<J> makeRootGraph(String name, boolean mutable) {
116+
if (getGraphedType() instanceof EntityDomainType) {
117+
return new RootGraphImpl<>(name, this, mutable);
118+
}
119+
120+
throw new CannotBecomeEntityGraphException(
121+
"Cannot transform Graph to RootGraph - " + getGraphedType() + " is not an EntityType"
122+
);
123+
}
124+
125+
@Override
126+
@SuppressWarnings("unchecked")
127+
public void merge(GraphImplementor<? extends J> other) {
128+
if (other == null) {
129+
return;
130+
}
131+
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+
} else {
140+
alreadyExistingSubtypeSubgraph.merge((GraphImplementor) otherSubTypeSubgraph);
141+
}
142+
143+
});
144+
145+
for (AttributeNodeImplementor<?> attributeNode : other.getAttributeNodeImplementors()) {
146+
final AttributeNodeImplementor<?> localAttributeNode = findAttributeNode(
147+
(PersistentAttribute<? extends J, ?>) attributeNode.getAttributeDescriptor()
148+
);
149+
if (localAttributeNode != null) {
150+
// keep the local one, but merge in the incoming one
151+
localAttributeNode.merge(attributeNode);
152+
} else {
153+
addAttributeNode(attributeNode.makeCopy(true));
154+
}
155+
}
156+
157+
}
158+
159+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
160+
// AttributeNode handling
161+
162+
@Override
163+
public AttributeNodeImplementor<?> addAttributeNode(AttributeNodeImplementor<?> incomingAttributeNode) {
164+
verifyMutability();
165+
166+
AttributeNodeImplementor<?> attributeNode = null;
167+
if (attrNodeMap == null) {
168+
attrNodeMap = new HashMap<>();
169+
} else {
170+
attributeNode = attrNodeMap.get(incomingAttributeNode.getAttributeDescriptor());
171+
}
172+
173+
if (attributeNode == null) {
174+
attributeNode = incomingAttributeNode;
175+
attrNodeMap.put(incomingAttributeNode.getAttributeDescriptor(), attributeNode);
176+
} else {
177+
@SuppressWarnings("rawtypes") final AttributeNodeImplementor attributeNodeFinal = attributeNode;
178+
attributeNodeFinal.getSubgraph().merge(this);
179+
incomingAttributeNode.visitSubGraphs(
180+
// we assume the subGraph has been properly copied if needed
181+
(subType, subGraph) -> attributeNodeFinal.addSubGraph(subGraph)
182+
);
183+
}
184+
185+
return attributeNode;
186+
}
187+
188+
@Override
189+
@SuppressWarnings("unchecked")
190+
public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(String attributeName) {
191+
PersistentAttribute<? super J, ?> attribute = managedType.findAttributeInSuperTypes(attributeName);
192+
if (attribute instanceof SqmPathSource && ((SqmPathSource<?>) attribute).isGeneric()) {
193+
attribute = managedType.findConcreteGenericAttribute(attributeName);
194+
}
195+
196+
return attribute == null ? null : findAttributeNode((PersistentAttribute<? extends J, AJ>) attribute);
197+
}
198+
199+
@Override
200+
@SuppressWarnings("unchecked")
201+
public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(PersistentAttribute<? extends J, AJ> attribute) {
202+
return attrNodeMap == null ? null : (AttributeNodeImplementor<AJ>) attrNodeMap.get(attribute);
203+
}
204+
205+
@Override
206+
@SuppressWarnings({"unchecked", "rawtypes"})
207+
public List<AttributeNode<?>> getGraphAttributeNodes() {
208+
return (List) getAttributeNodeImplementors();
209+
}
210+
211+
@Override
212+
public List<AttributeNodeImplementor<?>> getAttributeNodeImplementors() {
213+
return attrNodeMap == null ? emptyList() : new ArrayList<>(attrNodeMap.values());
214+
}
215+
216+
@Override
217+
public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(String attributeName)
218+
throws CannotContainSubGraphException {
219+
return findOrCreateAttributeNode(attributeName);
220+
}
221+
222+
@Override
223+
public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(PersistentAttribute<? extends J, AJ> attribute)
224+
throws CannotContainSubGraphException {
225+
return findOrCreateAttributeNode(attribute);
226+
}
227+
228+
@Override
229+
@SuppressWarnings("unchecked")
230+
public <AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(PersistentAttribute<? extends J, AJ> attribute) {
231+
verifyMutability();
232+
233+
AttributeNodeImplementor<AJ> attrNode = null;
234+
if (attrNodeMap == null) {
235+
attrNodeMap = new HashMap<>();
236+
} else {
237+
attrNode = (AttributeNodeImplementor<AJ>) attrNodeMap.get(attribute);
238+
}
239+
240+
if (attrNode == null) {
241+
attrNode = new AttributeNodeImpl<>(attribute, isMutable());
242+
attrNodeMap.put(attribute, attrNode);
243+
}
244+
245+
return attrNode;
246+
}
183247
}

0 commit comments

Comments
 (0)