/** INTERNAL: Visit an executable and create a MetadataMethod object. */
  @Override
  public MetadataMethod visitExecutable(
      ExecutableElement executableElement, MetadataClass metadataClass) {
    MetadataMethod method = new MetadataMethod(metadataClass.getMetadataFactory(), metadataClass);

    // Set the name.
    method.setName(executableElement.getSimpleName().toString());

    // Set the attribute name.
    method.setAttributeName(Helper.getAttributeNameFromMethodName(method.getName()));

    // Set the modifiers.
    method.setModifiers(getModifiers(executableElement.getModifiers()));

    // Visit executable element for the parameters, return type and generic type.
    executableElement.asType().accept(typeVisitor, method);

    // Set the annotations.
    buildMetadataAnnotations(method, executableElement.getAnnotationMirrors());

    // Handle multiple methods with the same name.
    MetadataMethod existing = metadataClass.getMethods().get(method.getName());
    if (existing == null) {
      metadataClass.addMethod(method);
    } else {
      while (existing.getNext() != null) {
        existing = existing.getNext();
      }
      existing.setNext(method);
    }

    return method;
  }
  /** INTERNAL: */
  @Override
  public MetadataClass visitType(TypeElement typeElement, MetadataClass metadataClass) {
    // processingEnv.getMessager().printMessage(Kind.NOTE, "Visiting class: " + typeElement);
    MetadataMirrorFactory factory = ((MetadataMirrorFactory) metadataClass.getMetadataFactory());

    // Set the qualified name.
    metadataClass.setName(typeElement.getQualifiedName().toString());

    // By default, set the type to be the same as the name, which in most
    // cases is correct. For non JDK elements we'll visit the typeElement
    // further (see below). This will further process any generic types,
    // e.g. Employee<Integer>. For the most part I don't think we need to
    // care, certainly not with JDK classes but for round elements we'll
    // set them anyway.
    metadataClass.setType(metadataClass.getName());

    // Add the interfaces.
    for (TypeMirror interfaceCls : typeElement.getInterfaces()) {
      metadataClass.addInterface(factory.getMetadataClass(interfaceCls).getName());
    }

    // Set the superclass name (if there is one)
    TypeMirror superclass = typeElement.getSuperclass();
    if (superclass != null) {
      metadataClass.setSuperclassName(factory.getMetadataClass(superclass).getName());
    }

    // As a performance gain, limit what is visited by JDK elements.
    if (!metadataClass.isJDK()) {
      // Set the modifiers.
      metadataClass.setModifiers(getModifiers(typeElement.getModifiers()));

      // Visit the type element for type and generic type.
      typeElement.asType().accept(typeVisitor, metadataClass);

      // Visit the enclosed elements.
      for (Element enclosedElement : typeElement.getEnclosedElements()) {
        if (enclosedElement.getKind().isClass()) {
          metadataClass.addEnclosedClass(factory.getMetadataClass(enclosedElement));
        } else {
          enclosedElement.accept(this, metadataClass);
        }
      }

      // Visit the annotations only if it is a round element.
      buildMetadataAnnotations(metadataClass, typeElement.getAnnotationMirrors());
    }

    return metadataClass;
  }