@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 buildRequestBodies(
      ExecutableElement executableElement, RestDocumentation.Resource.Method doc) {
    List<VariableElement> requestBodies = new ArrayList<VariableElement>();
    for (VariableElement var : executableElement.getParameters()) {
      if (var.getAnnotation(org.springframework.web.bind.annotation.RequestBody.class) != null) {
        requestBodies.add(var);
      }
    }

    if (requestBodies.size() > 1) {
      throw new IllegalStateException(
          String.format(
              "Method %s in class %s has multiple @RequestBody params",
              executableElement.getSimpleName(), executableElement.getEnclosingElement()));
    }

    if (requestBodies.size() == 1) {
      buildRequestBody(requestBodies.get(0), doc);
    }
  }
    private void addFieldFromBeanMethod(JsonObject o, ExecutableElement executableElement) {
      if (!isJsonBeanGetter(executableElement)) {
        return;
      }

      TypeMirror type = executableElement.getReturnType();
      String methodName = executableElement.getSimpleName().toString();
      int trimLength = methodName.startsWith("is") ? 2 : 3;
      String beanName = methodName.substring(trimLength + 1, methodName.length());
      beanName = methodName.substring(trimLength, trimLength + 1).toLowerCase() + beanName;

      // loop over the element's generic types, and build a concrete list from the owning context
      List<DeclaredType> concreteTypes = new ArrayList();

      // replace variables with the current concrete manifestation
      if (type instanceof TypeVariable) {
        type = getDeclaredTypeForTypeVariable((TypeVariable) type);
        if (type == null) {
          return; // couldn't find a replacement -- must be a generics-capable type with no generics
                  // info
        }
      }

      String docComment = processingEnv.getElementUtils().getDocComment(executableElement);
      if (type instanceof DeclaredType) {
        TypeElement element = (TypeElement) ((DeclaredType) type).asElement();
        for (TypeParameterElement generic : element.getTypeParameters()) {
          concreteTypes.add(_typeArguments.get(generic.getSimpleName()));
        }
        Collection<DeclaredType> types = new HashSet<DeclaredType>(_typeRecursionGuard);
        types.add(_type);
        o.addField(beanName, newJsonType((DeclaredType) type, concreteTypes, types))
            .setCommentText(docComment);
      } else {
        o.addField(beanName, newJsonType(type)).setCommentText(docComment);
      }
    }
    public TypeVisitorImpl(
        DeclaredType type,
        List<? extends TypeMirror> typeArguments,
        Collection<DeclaredType> typeRecursionGuard) {

      TypeElement elem = (TypeElement) type.asElement();
      _typeRecursionGuard = typeRecursionGuard;
      _type = type;
      List<? extends TypeParameterElement> generics = elem.getTypeParameters();
      for (int i = 0; i < generics.size(); i++) {
        DeclaredType value =
            (typeArguments.isEmpty() || !(typeArguments.get(i) instanceof DeclaredType))
                ? null
                : (DeclaredType) typeArguments.get(i);
        _typeArguments.put(generics.get(i).getSimpleName(), value);
      }
    }