Gizmo fails with ConcurrentModificationException using "delete //prefix:local~
java -cp ~/bin/10.5/he/saxon-he-10.5.jar:/Users/mike/bin/10.5/he/jline-2.14.6.jar net.sf.saxon.Gizmo Saxon Gizmo 10.5 />load /Users/mike/GitHub/saxon2020/src/samples/schemas/validation-reports.xsd />delete //xs:annotation Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) at java.util.ArrayList$Itr.next(ArrayList.java:851) at net.sf.saxon.Gizmo.delete(Gizmo.java:439) at net.sf.saxon.Gizmo.executeCommands(Gizmo.java:304) at net.sf.saxon.Gizmo.<init>(Gizmo.java:231) at net.sf.saxon.Gizmo.main(Gizmo.java:168)
#1 Updated by Martin Honnen 23 days ago
https://docs.oracle.com/javase/8/docs/api/java/util/ConcurrentModificationException.html says "If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.". I think the Iterator Saxon creates breaks the contract to implement and solely use the
remove method when deleting items it iterates over.
#2 Updated by Michael Kay 23 days ago
Yes, something like that must be going on, but I'm having trouble seeing exactly where. We call the delete() method on the Item affected, but that doesn't actually delete the Java object or remove it from the List of items we are iterating over.
I've established that if we change the code to just use the SequenceIterator returned by
getSelectedItems(buffer, Token.EOF) directly, then it works, but I feel there must be a reason why the code wasn't written to do just that, and that changing it would break something else. Unfortunately debugging and testing Gizmo isn't a very well-developed art, partly because there have been very few problems with it.
#3 Updated by Martin Honnen 22 days ago
delete //child, the
GroundedValue all has a property
value with an
ElementImpl that I think is iterated over with
for (Item item : all.asIterable()). It is not changed during the iteration and not shared with other objects.
namespace ex http://example.com and
delete //ex:child that same
ArrayList is shared as the
_value property of the
elementList property of the
DocumentImpl that is the root of all elements and that way in
deIndex the element nodes are removed from that ArrayList in line 509
list.remove(node); which then causes the iterator to fail as it doesn't expect any deletion from the ArrayList.
#4 Updated by Martin Honnen 21 days ago
public GroundedValue materialize() does
return SequenceExtent.makeSequenceExtent(list); but the description of
SequenceExtent.makeSequenceExtent says "@param input a List containing the items in the sequence. The caller guarantees that this list will not be subsequently modified.". So perhaps ListIterator needs to call makeSequence with a shallow copy
return SequenceExtent.makeSequenceExtent(new ArrayList<>(list)); instead?
Please register to edit this issue