public void traverse(ObjectVisitor visitor, Object root) {
    Stack stack = new Stack();
    stack.put(root);
    shouldFollow(root);
    while (!stack.empty()) {
      Object obj = stack.pop();
      ClassInfo info = getClassInfo(obj);
      if (visitor.visit(info, obj)) {
        if (info.isArray) {
          int length = Array.getLength(obj);
          for (int i = 0; i < length; i++) {
            Object child = Array.get(obj, i);
            if (shouldFollow(child)) {
              stack.put(child);
            }
          }
        } else {
          for (FieldInfo f : info.fields) {
            if (!f.isPrimitive) {
              Object child = f.get(obj);
              if (shouldFollow(child)) {
                stack.put(child);
              }
            }
          }
        }
      }
    }
  }