@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 JsonType newJsonType(TypeMirror typeMirror) {
   if (isJsonPrimitive(typeMirror)) {
     return new JsonPrimitive(typeMirror.toString());
   } else if (typeMirror.getKind() == TypeKind.DECLARED) {
     // some sort of object... walk it
     DeclaredType type = (DeclaredType) typeMirror;
     return newJsonType(type, type.getTypeArguments(), new HashSet<DeclaredType>());
   } else if (typeMirror.getKind() == TypeKind.VOID) {
     return null;
   } else if (typeMirror.getKind() == TypeKind.ARRAY) {
     return newJsonType(((ArrayType) typeMirror).getComponentType());
   } else {
     throw new UnsupportedOperationException(typeMirror.toString());
   }
 }