Skip to content

Consider using IdentityHashSet for cycle detection #650

@cushon

Description

@cushon

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions