Skip to content

Commit b9ffb15

Browse files
committed
Graphpocalypse: major revision/refactoring of EntityGraph support
- sort out handling of mutability
1 parent dfd4205 commit b9ffb15

File tree

7 files changed

+166
-206
lines changed

7 files changed

+166
-206
lines changed

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

Lines changed: 82 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,22 @@
4040
public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements GraphImplementor<J> {
4141

4242
private final ManagedDomainType<J> managedType;
43-
private final Map<Class<?>, SubGraphImplementor<?>> subgraphs = new HashMap<>(1);
43+
private Map<Class<? extends J>, SubGraphImplementor<? extends J>> treatedSubgraphs;
4444
private Map<PersistentAttribute<? super J,?>, AttributeNodeImplementor<?>> attributeNodes;
4545

4646
public AbstractGraph(ManagedDomainType<J> managedType, boolean mutable) {
4747
super( mutable );
4848
this.managedType = managedType;
4949
}
5050

51-
protected AbstractGraph(ManagedDomainType<J> managedType, GraphImplementor<? super J> graph, boolean mutable) {
52-
this( managedType, mutable );
53-
attributeNodes = new HashMap<>( graph.getAttributeNodesByAttribute().size() );
54-
mergeInternal( graph, mutable );
51+
protected AbstractGraph(ManagedDomainType<J> managedType, GraphImplementor<J> graph, boolean mutable) {
52+
super( mutable );
53+
this.managedType = managedType;
54+
var attributeNodesByAttribute = graph.getAttributeNodesByAttribute();
55+
var subGraphMap = graph.getSubGraphMap();
56+
attributeNodes = attributeNodesByAttribute.isEmpty() ? null : new HashMap<>( attributeNodesByAttribute.size() );
57+
treatedSubgraphs = subGraphMap.isEmpty() ? null : new HashMap<>( subGraphMap.size() );
58+
mergeInternal( graph );
5559
}
5660

5761
protected AbstractGraph(GraphImplementor<J> graph, boolean mutable) {
@@ -63,6 +67,36 @@ public final ManagedDomainType<J> getGraphedType() {
6367
return managedType;
6468
}
6569

70+
@SuppressWarnings("unchecked")
71+
private <S extends J> SubGraphImplementor<S> getTreatedSubgraph(Class<S> javaType) {
72+
return treatedSubgraphs == null ? null : (SubGraphImplementor<S>) treatedSubgraphs.get( javaType );
73+
}
74+
75+
@SuppressWarnings("unchecked")
76+
private <T> AttributeNodeImplementor<T> getNode(PersistentAttribute<?, ? extends T> attribute) {
77+
return attributeNodes == null ? null : (AttributeNodeImplementor<T>) attributeNodes.get( attribute );
78+
}
79+
80+
private <S extends J> SubGraphImplementor<S> getTreatedSubgraphForPut(Class<S> javaType) {
81+
if ( treatedSubgraphs == null ) {
82+
treatedSubgraphs = new HashMap<>(1);
83+
return null;
84+
}
85+
else {
86+
return getTreatedSubgraph( javaType );
87+
}
88+
}
89+
90+
private <AJ> AttributeNodeImplementor<AJ> getNodeForPut(PersistentAttribute<?, AJ> attribute) {
91+
if ( attributeNodes == null ) {
92+
attributeNodes = new HashMap<>();
93+
return null;
94+
}
95+
else {
96+
return getNode( attribute );
97+
}
98+
}
99+
66100
@Override @Deprecated(forRemoval = true)
67101
public RootGraphImplementor<J> makeRootGraph(String name, boolean mutable) {
68102
if ( getGraphedType() instanceof EntityDomainType ) {
@@ -76,64 +110,55 @@ public RootGraphImplementor<J> makeRootGraph(String name, boolean mutable) {
76110
}
77111

78112
@Override
79-
public void merge(GraphImplementor<? super J> graph) {
80-
merge( graph, true );
113+
public void merge(GraphImplementor<J> graph) {
114+
if ( graph != null ) {
115+
verifyMutability();
116+
mergeInternal( graph );
117+
}
81118
}
82119

83120
@Override
84-
public void merge(GraphImplementor<? super J> graph, boolean mutable) {
85-
if ( graph != null ) {
86-
verifyMutability();
87-
mergeInternal( graph, mutable );
121+
public void mergeInternal(GraphImplementor<J> graph) {
122+
// skip verifyMutability()
123+
graph.getAttributeNodesByAttribute().forEach( this::mergeNode );
124+
graph.getSubGraphMap().values().forEach( this::mergeGraph );
125+
}
126+
127+
private void mergeNode(PersistentAttribute<? super J, ?> attribute, AttributeNodeImplementor<?> node) {
128+
final AttributeNodeImplementor<?> existingNode = getNodeForPut( attribute );
129+
if ( existingNode == null ) {
130+
attributeNodes.put( attribute, node.makeCopy( isMutable() ) );
131+
}
132+
else {
133+
// keep the local one, but merge in the incoming one
134+
mergeNode( node, existingNode );
88135
}
89136
}
90137

91-
private void mergeInternal(GraphImplementor<? super J> graph, boolean mutable) {
92-
graph.getAttributeNodesByAttribute().forEach( (attribute, node) -> {
93-
final AttributeNodeImplementor<?> existingNode = findAttributeNode( attribute );
94-
if ( existingNode != null ) {
95-
// keep the local one, but merge in the incoming one
96-
mergeNode( node, existingNode, mutable );
97-
}
98-
else {
99-
addAttributeNode( attribute, node.makeCopy( mutable ), mutable );
100-
}
101-
} );
102-
graph.getSubGraphMap().forEach( (type, subgraph) -> {
103-
final SubGraphImplementor<?> existing = subgraphs.get( type );
104-
if ( existing != null ) {
105-
existing.merge( (SubGraphImplementor) subgraph, mutable );
106-
}
107-
else {
108-
subgraphs.put( type, subgraph.makeCopy( mutable ) );
109-
}
110-
} );
138+
private <T extends J> void mergeGraph(SubGraphImplementor<T> subgraph) {
139+
final Class<T> javaType = subgraph.getClassType();
140+
final SubGraphImplementor<T> existing = getTreatedSubgraphForPut( javaType );
141+
if ( existing == null ) {
142+
treatedSubgraphs.put( javaType, subgraph.makeCopy( isMutable() ) );
143+
}
144+
else {
145+
// even if immutable, we need to merge here
146+
existing.mergeInternal( subgraph );
147+
}
111148
}
112149

113150
private static <T> void mergeNode(
114-
AttributeNodeImplementor<?> node, AttributeNodeImplementor<T> existingNode, boolean mutable) {
151+
AttributeNodeImplementor<?> node, AttributeNodeImplementor<T> existingNode) {
115152
if ( existingNode.getAttributeDescriptor() == node.getAttributeDescriptor() ) {
116153
@SuppressWarnings("unchecked") // safe, we just checked
117154
final AttributeNodeImplementor<T> castNode = (AttributeNodeImplementor<T>) node;
118-
existingNode.merge( castNode, mutable );
155+
existingNode.merge( castNode );
119156
}
120157
else {
121158
throw new AssertionFailure( "Attributes should have been identical" );
122159
}
123160
}
124161

125-
private <T> void addAttributeNode(
126-
PersistentAttribute<? super J, ?> attribute, AttributeNodeImplementor<T> node, boolean mutable) {
127-
final AttributeNodeImplementor<T> attributeNode = getNodeForPut( node.getAttributeDescriptor() );
128-
if ( attributeNode == null ) {
129-
attributeNodes.put( attribute, node );
130-
}
131-
else {
132-
// we assume the subgraph has been properly copied if needed
133-
node.merge( attributeNode, mutable );
134-
}
135-
}
136-
137162
@Override
138163
public List<AttributeNodeImplementor<?>> getAttributeNodeList() {
139164
return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() );
@@ -145,8 +170,8 @@ public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(String attributeName)
145170
@SuppressWarnings("unchecked") // The JPA API is unsafe by nature
146171
final PersistentAttribute<? super J, AJ> persistentAttribute = (PersistentAttribute<? super J, AJ>) attribute;
147172
final AttributeNodeImplementor<AJ> node = attribute == null ? null : findAttributeNode( persistentAttribute );
148-
if ( node == null ) {
149-
for ( SubGraphImplementor<?> subgraph : subgraphs.values() ) {
173+
if ( node == null && treatedSubgraphs != null ) {
174+
for ( SubGraphImplementor<?> subgraph : treatedSubgraphs.values() ) {
150175
final AttributeNodeImplementor<AJ> subgraphNode = subgraph.findAttributeNode( attributeName );
151176
if ( subgraphNode != null ) {
152177
return subgraphNode;
@@ -161,7 +186,7 @@ public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(String attributeName)
161186

162187
@Override
163188
public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(PersistentAttribute<? super J, AJ> attribute) {
164-
return attributeNodes == null ? null : getNode( attribute );
189+
return getNode( attribute );
165190
}
166191

167192
@Override
@@ -205,16 +230,19 @@ public final void addAttributeNodes(Attribute<? super J, ?>... attributes) {
205230

206231
@Override
207232
public void removeAttributeNode(String attributeName) {
233+
verifyMutability();
208234
attributeNodes.remove( managedType.findAttribute( attributeName ) );
209235
}
210236

211237
@Override
212238
public void removeAttributeNode(Attribute<? super J, ?> attribute) {
239+
verifyMutability();
213240
attributeNodes.remove( (PersistentAttribute<? super J, ?>) attribute );
214241
}
215242

216243
@Override
217244
public void removeAttributeNodes(Attribute.PersistentAttributeType nodeType) {
245+
verifyMutability();
218246
attributeNodes.keySet().removeIf( entry -> entry.getPersistentAttributeType() == nodeType );
219247
}
220248

@@ -223,7 +251,7 @@ public <AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(PersistentAtt
223251
verifyMutability();
224252
final AttributeNodeImplementor<AJ> node = getNodeForPut( attribute );
225253
if ( node == null ) {
226-
final AttributeNodeImpl<AJ> newAttrNode = new AttributeNodeImpl<>( attribute, isMutable() );
254+
final AttributeNodeImplementor<AJ> newAttrNode = new AttributeNodeImpl<>( attribute, isMutable() );
227255
attributeNodes.put( attribute, newAttrNode );
228256
return newAttrNode;
229257
}
@@ -254,21 +282,6 @@ public <AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(String attrib
254282
: attribute;
255283
}
256284

257-
private <AJ> AttributeNodeImplementor<AJ> getNodeForPut(PersistentAttribute<?, AJ> attribute) {
258-
if ( attributeNodes == null ) {
259-
attributeNodes = new HashMap<>();
260-
return null;
261-
}
262-
else {
263-
return getNode( attribute );
264-
}
265-
}
266-
267-
@SuppressWarnings("unchecked")
268-
private <T> AttributeNodeImplementor<T> getNode(PersistentAttribute<?, ? extends T> attribute) {
269-
return (AttributeNodeImplementor<T>) attributeNodes.get( attribute );
270-
}
271-
272285
@Override
273286
@SuppressWarnings("unchecked") // The API is unsafe by nature
274287
public <AJ> SubGraphImplementor<AJ> addSubGraph(String attributeName) {
@@ -358,16 +371,17 @@ public <E> SubGraphImplementor<E> addTreatedElementSubgraph(
358371

359372
@Override
360373
public <S extends J> SubGraphImplementor<S> addTreatedSubGraph(ManagedDomainType<S> type) {
374+
verifyMutability();
361375
if ( getGraphedType().equals( type ) ) {
362376
//noinspection unchecked
363377
return (SubGraphImplementor<S>) this;
364378
}
365379
else {
366380
final Class<S> javaType = type.getJavaType();
367-
final SubGraphImplementor<S> castSubgraph = subgraph( javaType );
381+
final SubGraphImplementor<S> castSubgraph = getTreatedSubgraphForPut( javaType );
368382
if ( castSubgraph == null ) {
369383
final SubGraphImpl<S> subgraph = new SubGraphImpl<>( type, true );
370-
subgraphs.put( javaType, subgraph );
384+
treatedSubgraphs.put( javaType, subgraph );
371385
return subgraph;
372386
}
373387
else {
@@ -376,25 +390,13 @@ public <S extends J> SubGraphImplementor<S> addTreatedSubGraph(ManagedDomainType
376390
}
377391
}
378392

379-
private <S extends J> SubGraphImplementor<S> subgraph(Class<S> javaType) {
380-
final SubGraphImplementor<?> existing = subgraphs.get( javaType );
381-
if ( existing != null ) {
382-
@SuppressWarnings("unchecked")
383-
final SubGraphImplementor<S> castSubgraph = (SubGraphImplementor<S>) existing;
384-
return castSubgraph;
385-
}
386-
else {
387-
return null;
388-
}
389-
}
390-
391393
@Override
392394
public <S extends J> SubGraphImplementor<S> addTreatedSubGraph(Class<S> type) {
393395
return addTreatedSubGraph( getGraphedType().getMetamodel().managedType( type ) );
394396
}
395397

396398
@Override
397-
public Map<Class<?>, SubGraphImplementor<?>> getSubGraphMap() {
398-
return subgraphs;
399+
public Map<Class<? extends J>, SubGraphImplementor<? extends J>> getSubGraphMap() {
400+
return treatedSubgraphs == null ? emptyMap() : unmodifiableMap( treatedSubgraphs );
399401
}
400402
}

0 commit comments

Comments
 (0)