File tree Expand file tree Collapse file tree 2 files changed +13
-1
lines changed
parse/src/main/java/com/parse Expand file tree Collapse file tree 2 files changed +13
-1
lines changed Original file line number Diff line number Diff line change @@ -1474,6 +1474,9 @@ public Date getCreatedAt() {
14741474 /**
14751475 * Returns a set view of the keys contained in this object. This does not include createdAt,
14761476 * 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.
14771480 */
14781481 public Set <String > keySet () {
14791482 synchronized (mutex ) {
Original file line number Diff line number Diff line change 88 */
99package com .parse ;
1010
11+ import java .util .HashSet ;
1112import java .util .IdentityHashMap ;
1213import java .util .Iterator ;
1314import java .util .List ;
1415import java .util .Map ;
16+ import java .util .Set ;
1517import org .json .JSONArray ;
1618import org .json .JSONException ;
1719import org .json .JSONObject ;
@@ -94,7 +96,14 @@ private void traverseInternal(
9496 } else if (root instanceof ParseObject ) {
9597 if (traverseParseObjects ) {
9698 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 ) {
98107 traverseInternal (object .get (key ), true , seen );
99108 }
100109 }
You can’t perform that action at this time.
0 commit comments