static <T> T copy(T object, DataComplexTable alreadyCopied) throws CloneNotSupportedException
  {
    if (object == null)
    {
      return null;
    }
    else if (isComplex(object))
    {
      DataComplex src = (DataComplex) object;

      @SuppressWarnings("unchecked")
      T found = (T) alreadyCopied.get(src);

      if (found != null)
      {
        return found;
      }
      else
      {
        DataComplex clone = src.clone();
        alreadyCopied.put(src, clone);

        if (clone instanceof DataMap)
        {
          ((DataMap)clone).copyReferencedObjects(alreadyCopied);
        }
        else if (clone instanceof DataList)
        {
          ((DataList)clone).copyReferencedObjects(alreadyCopied);
        }

        @SuppressWarnings("unchecked")
        T converted = (T) clone;
        return converted;
      }
    }
    else if (isPrimitive(object))
    {
      return object;
    }
    else
    {
      throw new CloneNotSupportedException("Illegal value encountered: " + object);
    }
  }
@Test
  public void testDeepCopy() throws CloneNotSupportedException
  {
    DataMap root = new DataMap();

    DataMap a = new DataMap();
    a.put("key", "a");

    DataMap b = a.copy();
    b.put("key", "b");

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

    DataMap copy = root.copy();
    assertEquals(root, copy);

    ((DataMap)copy.get("a")).put("key", "A");
    ((DataMap)copy.get("b")).put("key", "B");

    DataMap rootA = (DataMap)root.get("a");
    DataMap rootB = (DataMap)root.get("b");
    DataMap copyA = (DataMap)copy.get("a");
    DataMap copyB = (DataMap)copy.get("b");

    assertEquals(rootA.get("key"), ("a"));
    assertEquals(rootB.get("key"), ("b"));

    assertEquals(copyA.get("key"), ("A"));
    assertEquals(copyB.get("key"), ("B"));
  }