The cycle detection introduced in #632 / #645 uses a HashSet, and detects if the object being serialized contains another object that is equal using Object.equals. This reports errors for objects where there isn't actually a cycle, but a contained object tests equal with an enclosing one, like in the following example.
Using IdentityHashMap instead of HashSet would detect actual cycles, but avoid reporting the following error.
import org.json.JSONObject;
class Json {
public static void main(String[] args) {
new JSONObject(new Foo(1, new Foo(1, new Foo(1, null))));
}
public static class Foo {
final int x;
final Foo f;
Foo(int x, Foo f) {
this.x = x;
this.f = f;
}
public Foo getFoo() {
return f;
}
@Override
public boolean equals(Object other) {
return other instanceof Foo && ((Foo) other).x == x;
}
@Override
public int hashCode() {
return x;
}
}
}
Exception in thread "main" org.json.JSONException: JavaBean object contains recursively defined member variable of key "foo"
at org.json.JSONObject.recursivelyDefinedObjectException(JSONObject.java:2722)
at org.json.JSONObject.populateMap(JSONObject.java:1558)
at org.json.JSONObject.<init>(JSONObject.java:371)
at org.json.JSONObject.wrap(JSONObject.java:2496)
at org.json.JSONObject.populateMap(JSONObject.java:1563)
at org.json.JSONObject.populateMap(JSONObject.java:1529)
at org.json.JSONObject.<init>(JSONObject.java:366)
at Json.main(Json.java:6)
The cycle detection introduced in #632 / #645 uses a
HashSet, and detects if the object being serialized contains another object that is equal usingObject.equals. This reports errors for objects where there isn't actually a cycle, but a contained object tests equal with an enclosing one, like in the following example.Using
IdentityHashMapinstead ofHashSetwould detect actual cycles, but avoid reporting the following error.