static boolean objectIsAcyclic(Object object)
  {
    if (object == null)
    {
      return true;
    }

    Class<?> klass = object.getClass();
    if (isPrimitiveClass(klass))
    {
      return true;
    }
    else if (isComplexClass(klass))
    {
      DataComplex complex = (DataComplex) object;
      try
      {
        Data.traverse(complex, new TraverseCallback() {});
        return true;
      }
      catch (IOException e)
      {
        return false;
      }
    }
    else
    {
      throw new IllegalStateException("Object of unknown type: " + object);
    }
  }
@Test
  public void testNoCyclesOnAddAndPut()
  {
    assertTrue(Data.objectIsAcyclic(true));
    assertTrue(Data.objectIsAcyclic(1));
    assertTrue(Data.objectIsAcyclic(1L));
    assertTrue(Data.objectIsAcyclic(1.0f));
    assertTrue(Data.objectIsAcyclic(1.0));
    assertTrue(Data.objectIsAcyclic("string"));
    assertTrue(Data.objectIsAcyclic(new DataMap()));
    assertTrue(Data.objectIsAcyclic(new DataList()));

    DataMap a = new DataMap();
    DataList b = new DataList();
    DataMap c = new DataMap();

    a.put("b", b);
    a.put("c", c);

    assertTrue(Data.objectIsAcyclic(a));
    assertTrue(Data.objectIsAcyclic(b));
    assertTrue(Data.objectIsAcyclic(c));

    DataMap dm = new DataMap();
    b.add(dm);
    c.put("d", dm);

    assertTrue(Data.objectIsAcyclic(a));
    assertTrue(Data.objectIsAcyclic(b));
    assertTrue(Data.objectIsAcyclic(c));
    assertTrue(Data.objectIsAcyclic(dm));

    DataList e = new DataList();
    DataMap f = new DataMap();

    dm.put("e", e);
    dm.put("f", f);

    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to e
    addAndExpectIllegalArgumentException(e, e);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to dm
    addAndExpectIllegalArgumentException(e, dm);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to c
    addAndExpectIllegalArgumentException(e, c);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to b
    addAndExpectIllegalArgumentException(e, b);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to a
    addAndExpectIllegalArgumentException(e, a);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from f to f
    putAndExpectIllegalArgumentException(f, "f", f);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from f to dm
    putAndExpectIllegalArgumentException(f, "d", dm);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to c
    putAndExpectIllegalArgumentException(f, "c", c);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to b
    putAndExpectIllegalArgumentException(f, "b", b);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to a
    putAndExpectIllegalArgumentException(f, "a", a);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from dm to dm
    putAndExpectIllegalArgumentException(dm, "d", dm);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from dm to c
    putAndExpectIllegalArgumentException(dm, "c", c);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from dm to b
    putAndExpectIllegalArgumentException(dm, "b", b);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from dm to a
    putAndExpectIllegalArgumentException(dm, "a", a);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from c to b
    putAndExpectIllegalArgumentException(c, "c", c);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from c to a
    putAndExpectIllegalArgumentException(c, "a", a);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from b to b
    addAndExpectIllegalArgumentException(b, b);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from b to a
    addAndExpectIllegalArgumentException(b, a);
    assertTrue(Data.objectIsAcyclic(a));

    DataList dl = new DataList();
    b.clear();
    b.add(dl);
    c.put("d", dl);

    assertTrue(Data.objectIsAcyclic(a));
    assertTrue(Data.objectIsAcyclic(b));
    assertTrue(Data.objectIsAcyclic(c));
    assertTrue(Data.objectIsAcyclic(dl));

    dl.add(e);
    dl.add(f);

    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to e
    addAndExpectIllegalArgumentException(e, e);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to dl
    addAndExpectIllegalArgumentException(e, dl);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to c
    addAndExpectIllegalArgumentException(e, c);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to b
    addAndExpectIllegalArgumentException(e, b);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to a
    addAndExpectIllegalArgumentException(e, a);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from f to f
    putAndExpectIllegalArgumentException(f, "f", f);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from f to dl
    putAndExpectIllegalArgumentException(f, "d", dl);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to c
    putAndExpectIllegalArgumentException(f, "c", c);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to b
    putAndExpectIllegalArgumentException(f, "b", b);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from e to a
    putAndExpectIllegalArgumentException(f, "a", a);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from dl to dl
    addAndExpectIllegalArgumentException(dl, dl);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from dl to c
    addAndExpectIllegalArgumentException(dl, c);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from dl to b
    addAndExpectIllegalArgumentException(dl, b);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from dl to a
    addAndExpectIllegalArgumentException(dl, a);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from c to b
    putAndExpectIllegalArgumentException(c, "c", c);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from c to a
    putAndExpectIllegalArgumentException(c, "a", a);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from b to b
    addAndExpectIllegalArgumentException(b, b);
    assertTrue(Data.objectIsAcyclic(a));

    // loop from b to a
    addAndExpectIllegalArgumentException(b, a);
    assertTrue(Data.objectIsAcyclic(a));
  }