[jira] [Commented] (COLLECTIONS-663) Unexpected ConcurrentModificationException when altering Collection of a MultiValuedMap
[ https://issues.apache.org/jira/browse/COLLECTIONS-663?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16967846#comment-16967846 ] Christophe Schmaltz commented on COLLECTIONS-663: - Hi [~Guoping1] , thank you for looking into this. I worked around my problem since then. Maybe you want to add in the documentation of {{MultiValuedMap.mapIterator()}} (or better in it's implementation {{AbstractMultiValuedMap.mapIterator()}}) that it doesn't support {{setValue(Object)}}, as it's documented for asMap(). But I think the initial issue needs documentation even more: {code:java} @Test public void test() { MultiValuedMap multiMap = new HashSetValuedHashMap<>(); multiMap.put(1, 10); multiMap.put(2, 20); for (Collection innerCollection : multiMap.asMap().values()) { for (Iterator iterator = innerCollection.iterator(); iterator.hasNext();) { Integer i = iterator.next(); iterator.remove(); // only the innerCollection is altered } // innerCollection.add(6); // adding stuff back should also work... } }{code} This test unexpectedly throws a ConcurrentModificationException, which is a lot harder to understand than the UnsupportedOperationException of the other test. The {{ConcurrentModificationException}} needs debugging to understand that it isn't the user who removed concurrently, but the apache-commons library itself. That {{AbstractMultiValuedMap.ValuesIterator.remove()}} is calling {{AbstractMultiValuedMap.this.remove(key);}} is incorrect if the user was using an iterator over the multimap: {code:java} // AbstractMultiValuedMap.ValuesIterator.remove(): @Override public void remove() { iterator.remove(); if (values.isEmpty()) { // this is buggy if the user was iterating over the AbstractMultiValuedMap AbstractMultiValuedMap.this.remove(key); } } {code} Maybe MultiValuedMap.asMap() needs some documentation that it doesn't support {{remove()}} in case of nested usage of {{iterator()}}. Or find a way to call enclosingIterator.remove(): {code:java} // AbstractMultiValuedMap.ValuesIterator.remove(): @Override public void remove() { iterator.remove(); if (values.isEmpty()) { if (hasEnclosingIterator()) { enclosingIterator.remove(); // nested iteration } else { AbstractMultiValuedMap.this.remove(key); // non nested usage } } } {code} hasEnclosingIterator() and enclosingIterator have to be implemented, somehow :D > Unexpected ConcurrentModificationException when altering Collection of a > MultiValuedMap > --- > > Key: COLLECTIONS-663 > URL: https://issues.apache.org/jira/browse/COLLECTIONS-663 > Project: Commons Collections > Issue Type: Bug >Reporter: Christophe Schmaltz >Assignee: Bruno P. Kinoshita >Priority: Trivial > > Testcase: > {code}@Test > public void test() { > MultiValuedMap multiMap = new > HashSetValuedHashMap<>(); > multiMap.put(1, 10); > multiMap.put(2, 20); > for (Collection innerCollection : > multiMap.asMap().values()) { > for (Iterator iterator = > innerCollection.iterator(); iterator.hasNext();) { > Integer i = iterator.next(); > iterator.remove(); // only the innerCollection > is altered > } > // innerCollection.add(6); // adding stuff back should > also work... > } > }{code} > This test unexpectedly throws a ConcurrentModificationException. > The issue is that when calling {{iterator.remove()}} the > {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is > empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. > It may be better if the iterator of the inner collection had a reference on > the iterator if the outer map and called {{containerIterator.remove()}} > instead. > *Note:* this solution would again present issues if the user tries to add new > elements in this now empty collection (which was removed from the parent). > In the current state, it is quite unclear why an exception is thrown, without > debugging the code. -- This message was sent by Atlassian Jira (v8.3.4#803005)
[jira] [Comment Edited] (COLLECTIONS-663) Unexpected ConcurrentModificationException when altering Collection of a MultiValuedMap
[ https://issues.apache.org/jira/browse/COLLECTIONS-663?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16239524#comment-16239524 ] Christophe Schmaltz edited comment on COLLECTIONS-663 at 11/5/17 1:20 PM: -- Thank you for your response. I once used the {{MapIterator}}, sadly I found out that it doesn't support what I try to achieve: {code} @Test public void testWhatINeedToWork() { // ArrayListValuedHashMap multiMap = new ArrayListValuedHashMap<>(); MultiValuedMap multiMap = new HashSetValuedHashMap<>(); multiMap.put(1, 10); multiMap.put(1, 11); multiMap.put(2, 20); Iterator it = multiMap.mapIterator(); for (MapIterator iterator = multiMap.mapIterator(); iterator.hasNext();) { iterator.next(); Integer value = iterator.getValue(); if ((value % 2) == 0) { // Integer is immutable, we need to replace using setValue(.) iterator.setValue(value * 2); } } }{code} My issue was that {{MapIterator.setValue(.)}} is not supported. (My current workaround is storing the elements I need to change in a list, and pushing them back in the map afterwards) I understand the difficulty in implementing it for {{HashSetValuedHashMap}} though, as the {{HashSet.iterator}} doesn't support it either (sadly, that's what I need). I observed that {{ArrayListValuedHashMap}} doesn't support {{setValue(.)}} either (should be possible, as {{ArrayList.listIterator}} has this feature. was (Author: chris333): Than you for your response. I once used the {{MapIterator}}, sadly I found out that it doesn't support what I try to achieve: {code} @Test public void testWhatINeedToWork() { // ArrayListValuedHashMap multiMap = new ArrayListValuedHashMap<>(); MultiValuedMap multiMap = new HashSetValuedHashMap<>(); multiMap.put(1, 10); multiMap.put(1, 11); multiMap.put(2, 20); Iterator it = multiMap.mapIterator(); for (MapIterator iterator = multiMap.mapIterator(); iterator.hasNext();) { iterator.next(); Integer value = iterator.getValue(); if ((value % 2) == 0) { // Integer is immutable, we need to replace using setValue(.) iterator.setValue(value * 2); } } }{code} My issue was that {{MapIterator.setValue(.)}} is not supported. (My current workaround is storing the elements I need to change in a list, and pushing them back in the map afterwards) I understand the difficulty in implementing it for {{HashSetValuedHashMap}} though, as the {{HashSet.iterator}} doesn't support it either (sadly, that's what I need). I observed that {{ArrayListValuedHashMap}} doesn't support {{setValue(.)}} either (should be possible, as {{ArrayList.listIterator}} has this feature. > Unexpected ConcurrentModificationException when altering Collection of a > MultiValuedMap > --- > > Key: COLLECTIONS-663 > URL: https://issues.apache.org/jira/browse/COLLECTIONS-663 > Project: Commons Collections > Issue Type: Bug >Reporter: Christophe Schmaltz >Assignee: Bruno P. Kinoshita >Priority: Trivial > > Testcase: > {code}@Test > public void test() { > MultiValuedMap multiMap = new > HashSetValuedHashMap<>(); > multiMap.put(1, 10); > multiMap.put(2, 20); > for (Collection innerCollection : > multiMap.asMap().values()) { > for (Iterator iterator = > innerCollection.iterator(); iterator.hasNext();) { > Integer i = iterator.next(); > iterator.remove(); // only the innerCollection > is altered > } > // innerCollection.add(6); // adding stuff back should > also work... > } > }{code} > This test unexpectedly throws a ConcurrentModificationException. > The issue is that when calling {{iterator.remove()}} the > {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is > empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. > It may be better if the iterator of the inner collection had a reference on > the iterator if the outer map and called {{containerIterator.remove()}} > instead. > *Note:* this solution would again present issues if the
[jira] [Commented] (COLLECTIONS-663) Unexpected ConcurrentModificationException when altering Collection of a MultiValuedMap
[ https://issues.apache.org/jira/browse/COLLECTIONS-663?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16239524#comment-16239524 ] Christophe Schmaltz commented on COLLECTIONS-663: - Than you for your response. I once used the {{MapIterator}}, sadly I found out that it doesn't support what I try to achieve: {code} @Test public void testWhatINeedToWork() { // ArrayListValuedHashMap multiMap = new ArrayListValuedHashMap<>(); MultiValuedMap multiMap = new HashSetValuedHashMap<>(); multiMap.put(1, 10); multiMap.put(1, 11); multiMap.put(2, 20); Iterator it = multiMap.mapIterator(); for (MapIterator iterator = multiMap.mapIterator(); iterator.hasNext();) { iterator.next(); Integer value = iterator.getValue(); if ((value % 2) == 0) { // Integer is immutable, we need to replace using setValue(.) iterator.setValue(value * 2); } } }{code} My issue was that {{MapIterator.setValue(.)}} is not supported. (My current workaround is storing the elements I need to change in a list, and pushing them back in the map afterwards) I understand the difficulty in implementing it for {{HashSetValuedHashMap}} though, as the {{HashSet.iterator}} doesn't support it either (sadly, that's what I need). I observed that {{ArrayListValuedHashMap}} doesn't support {{setValue(.)}} either (should be possible, as {{ArrayList.listIterator}} has this feature. > Unexpected ConcurrentModificationException when altering Collection of a > MultiValuedMap > --- > > Key: COLLECTIONS-663 > URL: https://issues.apache.org/jira/browse/COLLECTIONS-663 > Project: Commons Collections > Issue Type: Bug >Reporter: Christophe Schmaltz >Assignee: Bruno P. Kinoshita >Priority: Trivial > > Testcase: > {code}@Test > public void test() { > MultiValuedMap multiMap = new > HashSetValuedHashMap<>(); > multiMap.put(1, 10); > multiMap.put(2, 20); > for (Collection innerCollection : > multiMap.asMap().values()) { > for (Iterator iterator = > innerCollection.iterator(); iterator.hasNext();) { > Integer i = iterator.next(); > iterator.remove(); // only the innerCollection > is altered > } > // innerCollection.add(6); // adding stuff back should > also work... > } > }{code} > This test unexpectedly throws a ConcurrentModificationException. > The issue is that when calling {{iterator.remove()}} the > {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is > empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. > It may be better if the iterator of the inner collection had a reference on > the iterator if the outer map and called {{containerIterator.remove()}} > instead. > *Note:* this solution would again present issues if the user tries to add new > elements in this now empty collection (which was removed from the parent). > In the current state, it is quite unclear why an exception is thrown, without > debugging the code. -- This message was sent by Atlassian JIRA (v6.4.14#64029)
[jira] [Updated] (COLLECTIONS-663) Unexpected ConcurrentModificationException when altering Collection of a MultiValuedMap
[ https://issues.apache.org/jira/browse/COLLECTIONS-663?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Christophe Schmaltz updated COLLECTIONS-663: Description: Testcase: {code} @Test public void test() { MultiValuedMap multiMap = new HashSetValuedHashMap<>(); multiMap.put(1, 10); multiMap.put(2, 20); for (Collection innerCollection : multiMap.asMap().values()) { for (Iterator iterator = innerCollection.iterator(); iterator.hasNext();) { Integer i = iterator.next(); iterator.remove(); // only the innerCollection is altered } // innerCollection.add(6); // adding stuff back should also work... } }{code} This test unexpectedly throws a ConcurrentModificationException. The issue is that when calling {{iterator.remove()}} the {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. It may be better if the iterator of the inner collection had a reference on the iterator if the outer map and called {{containerIterator.remove()}} instead. *Note:* this solution would again present issues if the user tries to add new elements in this now empty collection (which was removed from the parent). In the current state, it is quite unclear why an exception is thrown, without debugging the code. was: Testcase: {code} @Test public void test() { MultiValuedMap multiMap = new HashSetValuedHashMap<>(); multiMap.put(1, 10); multiMap.put(2, 20); for (Collection innerCollection : multiMap.asMap().values()) { for (Iterator iterator = innerCollection.iterator(); iterator.hasNext();) { Integer i = iterator.next(); iterator.remove(); // only the innerCollection is altered } } }{code} This test unexpectedly throws a ConcurrentModificationException. The issue is that when calling {{iterator.remove()}} the {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. It may be better if the iterator of the inner collection had a reference on the iterator if the outer map and called {{containerIterator.remove()}} instead. *Note:* this solution would again present issues if the user tries to add new elements in this now empty collection (which was removed from the parent). In the current state, it is quite unclear why an exception is thrown, without debugging the code. > Unexpected ConcurrentModificationException when altering Collection of a > MultiValuedMap > --- > > Key: COLLECTIONS-663 > URL: https://issues.apache.org/jira/browse/COLLECTIONS-663 > Project: Commons Collections > Issue Type: Bug >Reporter: Christophe Schmaltz > > Testcase: > {code}@Test > public void test() { > MultiValuedMap multiMap = new > HashSetValuedHashMap<>(); > multiMap.put(1, 10); > multiMap.put(2, 20); > for (Collection innerCollection : > multiMap.asMap().values()) { > for (Iterator iterator = > innerCollection.iterator(); iterator.hasNext();) { > Integer i = iterator.next(); > iterator.remove(); // only the innerCollection > is altered > } > // innerCollection.add(6); // adding stuff back should > also work... > } > }{code} > This test unexpectedly throws a ConcurrentModificationException. > The issue is that when calling {{iterator.remove()}} the > {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is > empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. > It may be better if the iterator of the inner collection had a reference on > the iterator if the outer map and called {{containerIterator.remove()}} > instead. > *Note:* this solution would again present issues if the user tries to add new > elements in this now empty collection (which was removed from the parent). > In the current state, it is quite unclear why an exception is thrown, without > debugging the code. -- This message was sent by Atlassian JIRA (v6.4.14#64029)
[jira] [Updated] (COLLECTIONS-663) Unexpected ConcurrentModificationException when altering Collection of a MultiValuedMap
[ https://issues.apache.org/jira/browse/COLLECTIONS-663?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Christophe Schmaltz updated COLLECTIONS-663: Description: Testcase: {code} @Test public void test() { MultiValuedMap multiMap = new HashSetValuedHashMap<>(); multiMap.put(1, 10); multiMap.put(2, 20); for (Collection innerCollection : multiMap.asMap().values()) { for (Iterator iterator = innerCollection.iterator(); iterator.hasNext();) { Integer i = iterator.next(); iterator.remove(); // only the innerCollection is altered } } }{code} This test unexpectedly throws a ConcurrentModificationException. The issue is that when calling {{iterator.remove()}} the {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. It may be better if the iterator of the inner collection had a reference on the iterator if the outer map and called {{containerIterator.remove()}} instead. *Note:* this solution would again present issues if the user tries to add new elements in this now empty collection (which was removed from the parent). In the current state, it is quite unclear why an exception is thrown, without debugging the code. was: Testcase: {code} @Test public void test() { MultiValuedMap multiMap = new HashSetValuedHashMap<>(); multiMap.put(1, 10); multiMap.put(2, 20); for (Collection innerCollection : multiMap.asMap().values()) { for (Iterator iterator = innerCollection.iterator(); iterator.hasNext();) { Integer i = iterator.next(); iterator.remove(); // only the innerCollection is altered } } }{code} This test unexpectedly throws a ConcurrentModificationException. The issue is that when calling {{iterator.remove()}} the {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. It would be better if the iterator of the inner collection had a reference on the iterator if the outer map and called {{containerIterator.remove()}} instead. In the current state, it is quite unclear why an exception is thrown, without debugging the code. > Unexpected ConcurrentModificationException when altering Collection of a > MultiValuedMap > --- > > Key: COLLECTIONS-663 > URL: https://issues.apache.org/jira/browse/COLLECTIONS-663 > Project: Commons Collections > Issue Type: Bug >Reporter: Christophe Schmaltz > > Testcase: > {code}@Test > public void test() { > MultiValuedMap multiMap = new > HashSetValuedHashMap<>(); > multiMap.put(1, 10); > multiMap.put(2, 20); > for (Collection innerCollection : > multiMap.asMap().values()) { > for (Iterator iterator = > innerCollection.iterator(); iterator.hasNext();) { > Integer i = iterator.next(); > iterator.remove(); // only the innerCollection > is altered > } > } > }{code} > This test unexpectedly throws a ConcurrentModificationException. > The issue is that when calling {{iterator.remove()}} the > {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is > empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. > It may be better if the iterator of the inner collection had a reference on > the iterator if the outer map and called {{containerIterator.remove()}} > instead. > *Note:* this solution would again present issues if the user tries to add new > elements in this now empty collection (which was removed from the parent). > In the current state, it is quite unclear why an exception is thrown, without > debugging the code. -- This message was sent by Atlassian JIRA (v6.4.14#64029)
[jira] [Created] (COLLECTIONS-663) Unexpected ConcurrentModificationException when altering Collection of a MultiValuedMap
Christophe Schmaltz created COLLECTIONS-663: --- Summary: Unexpected ConcurrentModificationException when altering Collection of a MultiValuedMap Key: COLLECTIONS-663 URL: https://issues.apache.org/jira/browse/COLLECTIONS-663 Project: Commons Collections Issue Type: Bug Reporter: Christophe Schmaltz Testcase: {code} @Test public void test() { MultiValuedMap multiMap = new HashSetValuedHashMap<>(); multiMap.put(1, 10); multiMap.put(2, 20); for (Collection innerCollection : multiMap.asMap().values()) { for (Iterator iterator = innerCollection.iterator(); iterator.hasNext();) { Integer i = iterator.next(); iterator.remove(); // only the innerCollection is altered } } }{code} This test unexpectedly throws a ConcurrentModificationException. The issue is that when calling {{iterator.remove()}} the {{multimap.AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. It would be better if the iterator of the inner collection had a reference on the iterator if the outer map and called {{containerIterator.remove()}} instead. In the current state, it is quite unclear why an exception is thrown, without debugging the code. -- This message was sent by Atlassian JIRA (v6.4.14#64029)
[jira] [Updated] (COLLECTIONS-663) Unexpected ConcurrentModificationException when altering Collection of a MultiValuedMap
[ https://issues.apache.org/jira/browse/COLLECTIONS-663?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Christophe Schmaltz updated COLLECTIONS-663: Description: Testcase: {code} @Test public void test() { MultiValuedMap multiMap = new HashSetValuedHashMap<>(); multiMap.put(1, 10); multiMap.put(2, 20); for (Collection innerCollection : multiMap.asMap().values()) { for (Iterator iterator = innerCollection.iterator(); iterator.hasNext();) { Integer i = iterator.next(); iterator.remove(); // only the innerCollection is altered } } }{code} This test unexpectedly throws a ConcurrentModificationException. The issue is that when calling {{iterator.remove()}} the {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. It would be better if the iterator of the inner collection had a reference on the iterator if the outer map and called {{containerIterator.remove()}} instead. In the current state, it is quite unclear why an exception is thrown, without debugging the code. was: Testcase: {code} @Test public void test() { MultiValuedMap multiMap = new HashSetValuedHashMap<>(); multiMap.put(1, 10); multiMap.put(2, 20); for (Collection innerCollection : multiMap.asMap().values()) { for (Iterator iterator = innerCollection.iterator(); iterator.hasNext();) { Integer i = iterator.next(); iterator.remove(); // only the innerCollection is altered } } }{code} This test unexpectedly throws a ConcurrentModificationException. The issue is that when calling {{iterator.remove()}} the {{multimap.AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. It would be better if the iterator of the inner collection had a reference on the iterator if the outer map and called {{containerIterator.remove()}} instead. In the current state, it is quite unclear why an exception is thrown, without debugging the code. > Unexpected ConcurrentModificationException when altering Collection of a > MultiValuedMap > --- > > Key: COLLECTIONS-663 > URL: https://issues.apache.org/jira/browse/COLLECTIONS-663 > Project: Commons Collections > Issue Type: Bug >Reporter: Christophe Schmaltz > > Testcase: > {code}@Test > public void test() { > MultiValuedMap multiMap = new > HashSetValuedHashMap<>(); > multiMap.put(1, 10); > multiMap.put(2, 20); > for (Collection innerCollection : > multiMap.asMap().values()) { > for (Iterator iterator = > innerCollection.iterator(); iterator.hasNext();) { > Integer i = iterator.next(); > iterator.remove(); // only the innerCollection > is altered > } > } > }{code} > This test unexpectedly throws a ConcurrentModificationException. > The issue is that when calling {{iterator.remove()}} the > {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is > empty and calls {{AbstractMultiValuedMap.this.remove(key);}}. > It would be better if the iterator of the inner collection had a reference on > the iterator if the outer map and called {{containerIterator.remove()}} > instead. > In the current state, it is quite unclear why an exception is thrown, without > debugging the code. -- This message was sent by Atlassian JIRA (v6.4.14#64029)