File tree 2 files changed +13
-1
lines changed
parse/src/main/java/com/parse
2 files changed +13
-1
lines changed Original file line number Diff line number Diff line change @@ -1474,6 +1474,9 @@ public Date getCreatedAt() {
1474
1474
/**
1475
1475
* Returns a set view of the keys contained in this object. This does not include createdAt,
1476
1476
* updatedAt, authData, or objectId. It does include things like username and ACL.
1477
+ *
1478
+ * <p>Note that while the returned set is unmodifiable, it is in fact not thread-safe, and
1479
+ * creating a copy is recommended before iterating over it.
1477
1480
*/
1478
1481
public Set <String > keySet () {
1479
1482
synchronized (mutex ) {
Original file line number Diff line number Diff line change 8
8
*/
9
9
package com .parse ;
10
10
11
+ import java .util .HashSet ;
11
12
import java .util .IdentityHashMap ;
12
13
import java .util .Iterator ;
13
14
import java .util .List ;
14
15
import java .util .Map ;
16
+ import java .util .Set ;
15
17
import org .json .JSONArray ;
16
18
import org .json .JSONException ;
17
19
import org .json .JSONObject ;
@@ -94,7 +96,14 @@ private void traverseInternal(
94
96
} else if (root instanceof ParseObject ) {
95
97
if (traverseParseObjects ) {
96
98
ParseObject object = (ParseObject ) root ;
97
- for (String key : object .keySet ()) {
99
+ // Because the object's keySet is not thread safe, because the underlying Map isn't,
100
+ // we need to create a copy before iterating over the object's keys to avoid
101
+ // ConcurrentModificationExceptions
102
+ Set <String > keySet ;
103
+ synchronized (object .mutex ) {
104
+ keySet = new HashSet <>(object .keySet ());
105
+ }
106
+ for (String key : keySet ) {
98
107
traverseInternal (object .get (key ), true , seen );
99
108
}
100
109
}
You can’t perform that action at this time.
0 commit comments