@Override
    public JsonType visitDeclared(DeclaredType declaredType, Void o) {
      if (isJsonPrimitive(declaredType)) {
        // 'primitive'-ish things
        return new JsonPrimitive(declaredType.toString());

      } else if (isInstanceOf(declaredType, Collection.class)) {

        if (declaredType.getTypeArguments().size() == 0) {
          return new JsonArray(new JsonPrimitive(Object.class.getName()));
        } else {
          TypeMirror elem = declaredType.getTypeArguments().get(0);
          return new JsonArray(elem.accept(this, o));
        }

      } else if (isInstanceOf(declaredType, Map.class)) {

        if (declaredType.getTypeArguments().size() == 0) {
          return new JsonDict(
              new JsonPrimitive(Object.class.getName()), new JsonPrimitive(Object.class.getName()));
        } else {
          TypeMirror key = declaredType.getTypeArguments().get(0);
          TypeMirror val = declaredType.getTypeArguments().get(1);
          return new JsonDict(key.accept(this, o), val.accept(this, o));
        }

      } else {
        TypeElement element = (TypeElement) declaredType.asElement();
        if (element.getKind() == ElementKind.ENUM) {
          List<String> enumConstants = new ArrayList();
          for (Element e : element.getEnclosedElements()) {
            if (e.getKind() == ElementKind.ENUM_CONSTANT) {
              enumConstants.add(e.toString());
            }
          }
          JsonPrimitive primitive =
              new JsonPrimitive(String.class.getName()); // TODO is this always a string?
          primitive.setRestrictions(enumConstants);
          return primitive;
        } else {
          return buildType(declaredType, element);
        }
      }
    }
    private void buildTypeContents(JsonObject o, TypeElement element) {
      if ("org.springframework.web.servlet.ModelAndView"
          .equals(element.getQualifiedName().toString())) {
        return;
      }
      if (element.getSuperclass().getKind() != TypeKind.NONE) {
        // an interface's superclass is TypeKind.NONE

        DeclaredType sup = (DeclaredType) element.getSuperclass();
        if (!isJsonPrimitive(sup)) {
          buildTypeContents(o, (TypeElement) sup.asElement());
        }
      }

      for (Element e : element.getEnclosedElements()) {
        if (e instanceof ExecutableElement) {
          addFieldFromBeanMethod(o, (ExecutableElement) e);
        }
      }
    }