From cf3cc5e59fd1dd046bad56b31bc91dc09ce00537 Mon Sep 17 00:00:00 2001 From: Sascha Hlusiak Date: Sat, 5 Sep 2020 11:59:05 +0800 Subject: [PATCH 1/2] Create a copy of the ParseObject's keySet when iterating over it. Should fix ConcurrentModificationException in #1061. --- parse/src/main/java/com/parse/ParseObject.java | 3 +++ parse/src/main/java/com/parse/ParseTraverser.java | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/parse/src/main/java/com/parse/ParseObject.java b/parse/src/main/java/com/parse/ParseObject.java index d00526522..990675a92 100644 --- a/parse/src/main/java/com/parse/ParseObject.java +++ b/parse/src/main/java/com/parse/ParseObject.java @@ -1489,6 +1489,9 @@ public Date getCreatedAt() { /** * Returns a set view of the keys contained in this object. This does not include createdAt, * updatedAt, authData, or objectId. It does include things like username and ACL. + * + * Note that while the returned set is unmodifiable, it is in fact not thread-safe, and creating a copy + * is recommended before iterating over it. */ public Set keySet() { synchronized (mutex) { diff --git a/parse/src/main/java/com/parse/ParseTraverser.java b/parse/src/main/java/com/parse/ParseTraverser.java index 064247040..bd1e59942 100644 --- a/parse/src/main/java/com/parse/ParseTraverser.java +++ b/parse/src/main/java/com/parse/ParseTraverser.java @@ -12,10 +12,12 @@ import org.json.JSONException; import org.json.JSONObject; +import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; /** * Subclass ParseTraverser to make an function to be run recursively on every object pointed to on @@ -98,7 +100,14 @@ private void traverseInternal(Object root, boolean yieldRoot, IdentityHashMap keySet; + synchronized (object.mutex) { + keySet = new HashSet<>(object.keySet()); + } + for (String key : keySet) { traverseInternal(object.get(key), true, seen); } } From f04647519ff67e318ff0507ede02900ce9482401 Mon Sep 17 00:00:00 2001 From: Sascha Hlusiak Date: Sat, 16 Oct 2021 18:57:43 +1000 Subject: [PATCH 2/2] Run spotlessApply --- parse/src/main/java/com/parse/ParseObject.java | 4 ++-- parse/src/main/java/com/parse/ParseTraverser.java | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/parse/src/main/java/com/parse/ParseObject.java b/parse/src/main/java/com/parse/ParseObject.java index 9521d91c5..080bdc089 100644 --- a/parse/src/main/java/com/parse/ParseObject.java +++ b/parse/src/main/java/com/parse/ParseObject.java @@ -1475,8 +1475,8 @@ public Date getCreatedAt() { * Returns a set view of the keys contained in this object. This does not include createdAt, * updatedAt, authData, or objectId. It does include things like username and ACL. * - * Note that while the returned set is unmodifiable, it is in fact not thread-safe, and creating a copy - * is recommended before iterating over it. + *

Note that while the returned set is unmodifiable, it is in fact not thread-safe, and + * creating a copy is recommended before iterating over it. */ public Set keySet() { synchronized (mutex) { diff --git a/parse/src/main/java/com/parse/ParseTraverser.java b/parse/src/main/java/com/parse/ParseTraverser.java index a51886f37..08caa4ed8 100644 --- a/parse/src/main/java/com/parse/ParseTraverser.java +++ b/parse/src/main/java/com/parse/ParseTraverser.java @@ -8,16 +8,15 @@ */ package com.parse; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; /** * Subclass ParseTraverser to make an function to be run recursively on every object pointed to on