@@ -52,7 +52,8 @@ public final class PathImpl implements Path, Serializable {
52
52
private static final int INDEX_GROUP = 3 ;
53
53
private static final int REMAINING_STRING_GROUP = 5 ;
54
54
55
- private final List <Node > nodeList ;
55
+ private List <Node > nodeList ;
56
+ private boolean nodeListRequiresCopy ;
56
57
private NodeImpl currentLeafNode ;
57
58
private int hashCode ;
58
59
@@ -112,6 +113,8 @@ public PathImpl getPathWithoutLeafNode() {
112
113
}
113
114
114
115
public NodeImpl addPropertyNode (String nodeName ) {
116
+ requiresWriteableNodeList ();
117
+
115
118
NodeImpl parent = nodeList .isEmpty () ? null : (NodeImpl ) nodeList .get ( nodeList .size () - 1 );
116
119
currentLeafNode = NodeImpl .createPropertyNode ( nodeName , parent );
117
120
nodeList .add ( currentLeafNode );
@@ -120,6 +123,8 @@ public NodeImpl addPropertyNode(String nodeName) {
120
123
}
121
124
122
125
public NodeImpl addContainerElementNode (String nodeName ) {
126
+ requiresWriteableNodeList ();
127
+
123
128
NodeImpl parent = nodeList .isEmpty () ? null : (NodeImpl ) nodeList .get ( nodeList .size () - 1 );
124
129
currentLeafNode = NodeImpl .createContainerElementNode ( nodeName , parent );
125
130
nodeList .add ( currentLeafNode );
@@ -128,6 +133,8 @@ public NodeImpl addContainerElementNode(String nodeName) {
128
133
}
129
134
130
135
public NodeImpl addParameterNode (String nodeName , int index ) {
136
+ requiresWriteableNodeList ();
137
+
131
138
NodeImpl parent = nodeList .isEmpty () ? null : (NodeImpl ) nodeList .get ( nodeList .size () - 1 );
132
139
currentLeafNode = NodeImpl .createParameterNode ( nodeName , parent , index );
133
140
nodeList .add ( currentLeafNode );
@@ -136,6 +143,8 @@ public NodeImpl addParameterNode(String nodeName, int index) {
136
143
}
137
144
138
145
public NodeImpl addCrossParameterNode () {
146
+ requiresWriteableNodeList ();
147
+
139
148
NodeImpl parent = nodeList .isEmpty () ? null : (NodeImpl ) nodeList .get ( nodeList .size () - 1 );
140
149
currentLeafNode = NodeImpl .createCrossParameterNode ( parent );
141
150
nodeList .add ( currentLeafNode );
@@ -144,6 +153,8 @@ public NodeImpl addCrossParameterNode() {
144
153
}
145
154
146
155
public NodeImpl addBeanNode () {
156
+ requiresWriteableNodeList ();
157
+
147
158
NodeImpl parent = nodeList .isEmpty () ? null : (NodeImpl ) nodeList .get ( nodeList .size () - 1 );
148
159
currentLeafNode = NodeImpl .createBeanNode ( parent );
149
160
nodeList .add ( currentLeafNode );
@@ -152,6 +163,8 @@ public NodeImpl addBeanNode() {
152
163
}
153
164
154
165
public NodeImpl addReturnValueNode () {
166
+ requiresWriteableNodeList ();
167
+
155
168
NodeImpl parent = nodeList .isEmpty () ? null : (NodeImpl ) nodeList .get ( nodeList .size () - 1 );
156
169
currentLeafNode = NodeImpl .createReturnValue ( parent );
157
170
nodeList .add ( currentLeafNode );
@@ -160,6 +173,8 @@ public NodeImpl addReturnValueNode() {
160
173
}
161
174
162
175
private NodeImpl addConstructorNode (String name , Class <?>[] parameterTypes ) {
176
+ requiresWriteableNodeList ();
177
+
163
178
NodeImpl parent = nodeList .isEmpty () ? null : (NodeImpl ) nodeList .get ( nodeList .size () - 1 );
164
179
currentLeafNode = NodeImpl .createConstructorNode ( name , parent , parameterTypes );
165
180
nodeList .add ( currentLeafNode );
@@ -168,6 +183,8 @@ private NodeImpl addConstructorNode(String name, Class<?>[] parameterTypes) {
168
183
}
169
184
170
185
private NodeImpl addMethodNode (String name , Class <?>[] parameterTypes ) {
186
+ requiresWriteableNodeList ();
187
+
171
188
NodeImpl parent = nodeList .isEmpty () ? null : (NodeImpl ) nodeList .get ( nodeList .size () - 1 );
172
189
currentLeafNode = NodeImpl .createMethodNode ( name , parent , parameterTypes );
173
190
nodeList .add ( currentLeafNode );
@@ -176,6 +193,8 @@ private NodeImpl addMethodNode(String name, Class<?>[] parameterTypes) {
176
193
}
177
194
178
195
public NodeImpl makeLeafNodeIterable () {
196
+ requiresWriteableNodeList ();
197
+
179
198
currentLeafNode = NodeImpl .makeIterable ( currentLeafNode );
180
199
181
200
nodeList .set ( nodeList .size () - 1 , currentLeafNode );
@@ -184,6 +203,8 @@ public NodeImpl makeLeafNodeIterable() {
184
203
}
185
204
186
205
public NodeImpl setLeafNodeIndex (Integer index ) {
206
+ requiresWriteableNodeList ();
207
+
187
208
currentLeafNode = NodeImpl .setIndex ( currentLeafNode , index );
188
209
189
210
nodeList .set ( nodeList .size () - 1 , currentLeafNode );
@@ -192,6 +213,8 @@ public NodeImpl setLeafNodeIndex(Integer index) {
192
213
}
193
214
194
215
public NodeImpl setLeafNodeMapKey (Object key ) {
216
+ requiresWriteableNodeList ();
217
+
195
218
currentLeafNode = NodeImpl .setMapKey ( currentLeafNode , key );
196
219
197
220
nodeList .set ( nodeList .size () - 1 , currentLeafNode );
@@ -200,6 +223,8 @@ public NodeImpl setLeafNodeMapKey(Object key) {
200
223
}
201
224
202
225
public NodeImpl setLeafNodeValue (Object value ) {
226
+ requiresWriteableNodeList ();
227
+
203
228
currentLeafNode = NodeImpl .setPropertyValue ( currentLeafNode , value );
204
229
205
230
nodeList .set ( nodeList .size () - 1 , currentLeafNode );
@@ -208,6 +233,8 @@ public NodeImpl setLeafNodeValue(Object value) {
208
233
}
209
234
210
235
public NodeImpl setLeafNodeTypeParameter (Class <?> containerClass , Integer typeArgumentIndex ) {
236
+ requiresWriteableNodeList ();
237
+
211
238
currentLeafNode = NodeImpl .setTypeParameter ( currentLeafNode , containerClass , typeArgumentIndex );
212
239
213
240
nodeList .set ( nodeList .size () - 1 , currentLeafNode );
@@ -217,6 +244,8 @@ public NodeImpl setLeafNodeTypeParameter(Class<?> containerClass, Integer typeAr
217
244
218
245
public void removeLeafNode () {
219
246
if ( !nodeList .isEmpty () ) {
247
+ requiresWriteableNodeList ();
248
+
220
249
nodeList .remove ( nodeList .size () - 1 );
221
250
currentLeafNode = nodeList .isEmpty () ? null : (NodeImpl ) nodeList .get ( nodeList .size () - 1 );
222
251
}
@@ -259,6 +288,18 @@ public String asString() {
259
288
return builder .toString ();
260
289
}
261
290
291
+ private void requiresWriteableNodeList () {
292
+ if ( !nodeListRequiresCopy ) {
293
+ return ;
294
+ }
295
+
296
+ // Usually, the write operation is about adding one more node, so let's make the list one element larger.
297
+ List <Node > newNodeList = new ArrayList <>( nodeList .size () + 1 );
298
+ newNodeList .addAll ( nodeList );
299
+ nodeList = newNodeList ;
300
+ nodeListRequiresCopy = false ;
301
+ }
302
+
262
303
@ Override
263
304
public String toString () {
264
305
return asString ();
@@ -318,12 +359,14 @@ private PathImpl(PathImpl path) {
318
359
319
360
private PathImpl () {
320
361
nodeList = new ArrayList <>();
321
- this .hashCode = -1 ;
362
+ hashCode = -1 ;
363
+ nodeListRequiresCopy = false ;
322
364
}
323
365
324
366
private PathImpl (List <Node > nodeList ) {
325
- this .nodeList = new ArrayList <>( nodeList );
326
- this .hashCode = -1 ;
367
+ this .nodeList = nodeList ;
368
+ hashCode = -1 ;
369
+ nodeListRequiresCopy = true ;
327
370
}
328
371
329
372
private static PathImpl parseProperty (String propertyName ) {
0 commit comments