4040public 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