Skip to content

Commit ed8f3b5

Browse files
gsmetgunnarmorling
authored andcommitted
HV-1480 Implement a copy on write strategy for the node list
It avoids copying the list when not strictly necessary
1 parent c11fdeb commit ed8f3b5

File tree

1 file changed

+47
-4
lines changed
  • engine/src/main/java/org/hibernate/validator/internal/engine/path

1 file changed

+47
-4
lines changed

engine/src/main/java/org/hibernate/validator/internal/engine/path/PathImpl.java

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public final class PathImpl implements Path, Serializable {
5252
private static final int INDEX_GROUP = 3;
5353
private static final int REMAINING_STRING_GROUP = 5;
5454

55-
private final List<Node> nodeList;
55+
private List<Node> nodeList;
56+
private boolean nodeListRequiresCopy;
5657
private NodeImpl currentLeafNode;
5758
private int hashCode;
5859

@@ -112,6 +113,8 @@ public PathImpl getPathWithoutLeafNode() {
112113
}
113114

114115
public NodeImpl addPropertyNode(String nodeName) {
116+
requiresWriteableNodeList();
117+
115118
NodeImpl parent = nodeList.isEmpty() ? null : (NodeImpl) nodeList.get( nodeList.size() - 1 );
116119
currentLeafNode = NodeImpl.createPropertyNode( nodeName, parent );
117120
nodeList.add( currentLeafNode );
@@ -120,6 +123,8 @@ public NodeImpl addPropertyNode(String nodeName) {
120123
}
121124

122125
public NodeImpl addContainerElementNode(String nodeName) {
126+
requiresWriteableNodeList();
127+
123128
NodeImpl parent = nodeList.isEmpty() ? null : (NodeImpl) nodeList.get( nodeList.size() - 1 );
124129
currentLeafNode = NodeImpl.createContainerElementNode( nodeName, parent );
125130
nodeList.add( currentLeafNode );
@@ -128,6 +133,8 @@ public NodeImpl addContainerElementNode(String nodeName) {
128133
}
129134

130135
public NodeImpl addParameterNode(String nodeName, int index) {
136+
requiresWriteableNodeList();
137+
131138
NodeImpl parent = nodeList.isEmpty() ? null : (NodeImpl) nodeList.get( nodeList.size() - 1 );
132139
currentLeafNode = NodeImpl.createParameterNode( nodeName, parent, index );
133140
nodeList.add( currentLeafNode );
@@ -136,6 +143,8 @@ public NodeImpl addParameterNode(String nodeName, int index) {
136143
}
137144

138145
public NodeImpl addCrossParameterNode() {
146+
requiresWriteableNodeList();
147+
139148
NodeImpl parent = nodeList.isEmpty() ? null : (NodeImpl) nodeList.get( nodeList.size() - 1 );
140149
currentLeafNode = NodeImpl.createCrossParameterNode( parent );
141150
nodeList.add( currentLeafNode );
@@ -144,6 +153,8 @@ public NodeImpl addCrossParameterNode() {
144153
}
145154

146155
public NodeImpl addBeanNode() {
156+
requiresWriteableNodeList();
157+
147158
NodeImpl parent = nodeList.isEmpty() ? null : (NodeImpl) nodeList.get( nodeList.size() - 1 );
148159
currentLeafNode = NodeImpl.createBeanNode( parent );
149160
nodeList.add( currentLeafNode );
@@ -152,6 +163,8 @@ public NodeImpl addBeanNode() {
152163
}
153164

154165
public NodeImpl addReturnValueNode() {
166+
requiresWriteableNodeList();
167+
155168
NodeImpl parent = nodeList.isEmpty() ? null : (NodeImpl) nodeList.get( nodeList.size() - 1 );
156169
currentLeafNode = NodeImpl.createReturnValue( parent );
157170
nodeList.add( currentLeafNode );
@@ -160,6 +173,8 @@ public NodeImpl addReturnValueNode() {
160173
}
161174

162175
private NodeImpl addConstructorNode(String name, Class<?>[] parameterTypes) {
176+
requiresWriteableNodeList();
177+
163178
NodeImpl parent = nodeList.isEmpty() ? null : (NodeImpl) nodeList.get( nodeList.size() - 1 );
164179
currentLeafNode = NodeImpl.createConstructorNode( name, parent, parameterTypes );
165180
nodeList.add( currentLeafNode );
@@ -168,6 +183,8 @@ private NodeImpl addConstructorNode(String name, Class<?>[] parameterTypes) {
168183
}
169184

170185
private NodeImpl addMethodNode(String name, Class<?>[] parameterTypes) {
186+
requiresWriteableNodeList();
187+
171188
NodeImpl parent = nodeList.isEmpty() ? null : (NodeImpl) nodeList.get( nodeList.size() - 1 );
172189
currentLeafNode = NodeImpl.createMethodNode( name, parent, parameterTypes );
173190
nodeList.add( currentLeafNode );
@@ -176,6 +193,8 @@ private NodeImpl addMethodNode(String name, Class<?>[] parameterTypes) {
176193
}
177194

178195
public NodeImpl makeLeafNodeIterable() {
196+
requiresWriteableNodeList();
197+
179198
currentLeafNode = NodeImpl.makeIterable( currentLeafNode );
180199

181200
nodeList.set( nodeList.size() - 1, currentLeafNode );
@@ -184,6 +203,8 @@ public NodeImpl makeLeafNodeIterable() {
184203
}
185204

186205
public NodeImpl setLeafNodeIndex(Integer index) {
206+
requiresWriteableNodeList();
207+
187208
currentLeafNode = NodeImpl.setIndex( currentLeafNode, index );
188209

189210
nodeList.set( nodeList.size() - 1, currentLeafNode );
@@ -192,6 +213,8 @@ public NodeImpl setLeafNodeIndex(Integer index) {
192213
}
193214

194215
public NodeImpl setLeafNodeMapKey(Object key) {
216+
requiresWriteableNodeList();
217+
195218
currentLeafNode = NodeImpl.setMapKey( currentLeafNode, key );
196219

197220
nodeList.set( nodeList.size() - 1, currentLeafNode );
@@ -200,6 +223,8 @@ public NodeImpl setLeafNodeMapKey(Object key) {
200223
}
201224

202225
public NodeImpl setLeafNodeValue(Object value) {
226+
requiresWriteableNodeList();
227+
203228
currentLeafNode = NodeImpl.setPropertyValue( currentLeafNode, value );
204229

205230
nodeList.set( nodeList.size() - 1, currentLeafNode );
@@ -208,6 +233,8 @@ public NodeImpl setLeafNodeValue(Object value) {
208233
}
209234

210235
public NodeImpl setLeafNodeTypeParameter(Class<?> containerClass, Integer typeArgumentIndex) {
236+
requiresWriteableNodeList();
237+
211238
currentLeafNode = NodeImpl.setTypeParameter( currentLeafNode, containerClass, typeArgumentIndex );
212239

213240
nodeList.set( nodeList.size() - 1, currentLeafNode );
@@ -217,6 +244,8 @@ public NodeImpl setLeafNodeTypeParameter(Class<?> containerClass, Integer typeAr
217244

218245
public void removeLeafNode() {
219246
if ( !nodeList.isEmpty() ) {
247+
requiresWriteableNodeList();
248+
220249
nodeList.remove( nodeList.size() - 1 );
221250
currentLeafNode = nodeList.isEmpty() ? null : (NodeImpl) nodeList.get( nodeList.size() - 1 );
222251
}
@@ -259,6 +288,18 @@ public String asString() {
259288
return builder.toString();
260289
}
261290

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+
262303
@Override
263304
public String toString() {
264305
return asString();
@@ -318,12 +359,14 @@ private PathImpl(PathImpl path) {
318359

319360
private PathImpl() {
320361
nodeList = new ArrayList<>();
321-
this.hashCode = -1;
362+
hashCode = -1;
363+
nodeListRequiresCopy = false;
322364
}
323365

324366
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;
327370
}
328371

329372
private static PathImpl parseProperty(String propertyName) {

0 commit comments

Comments
 (0)