public void process() {
   for (TypeDeclaration typeDecl : env.getSpecifiedTypeDeclarations()) {
     ExtractInterface annot = typeDecl.getAnnotation(ExtractInterface.class);
     if (annot == null) break;
     for (MethodDeclaration m : typeDecl.getMethods())
       if (m.getModifiers().contains(Modifier.PUBLIC)
           && !(m.getModifiers().contains(Modifier.STATIC))) interfaceMethods.add(m);
     if (interfaceMethods.size() > 0) {
       try {
         PrintWriter writer = env.getFiler().createSourceFile(annot.value());
         writer.println("package " + typeDecl.getPackage().getQualifiedName() + ";");
         writer.println("public interface " + annot.value() + " {");
         for (MethodDeclaration m : interfaceMethods) {
           writer.print("  public ");
           writer.print(m.getReturnType() + " ");
           writer.print(m.getSimpleName() + " (");
           int i = 0;
           for (ParameterDeclaration parm : m.getParameters()) {
             writer.print(parm.getType() + " " + parm.getSimpleName());
             if (++i < m.getParameters().size()) writer.print(", ");
           }
           writer.println(");");
         }
         writer.println("}");
         writer.close();
       } catch (IOException ioe) {
         throw new RuntimeException(ioe);
       }
     }
   }
 }
 private boolean checkInheritedMethod(
     Thing data,
     String methodName,
     String returnType,
     ClassDeclaration superclass,
     boolean finalOk,
     InheritCheck inheritCheck) {
   if (inheritCheck != null) {
     if (inheritCheck.isInherited(data, superclass)) {
       return true;
     }
   }
   for (MethodDeclaration methodDeclaration : superclass.getMethods()) {
     if (methodName.equals(methodDeclaration.getSimpleName())
         && methodDeclaration.getParameters().isEmpty()
         && returnType.equals(methodDeclaration.getReturnType().toString())) {
       data.put(methodName + "Inherited", true);
       Collection<Modifier> modifiers = methodDeclaration.getModifiers();
       if ((modifiers.contains(Modifier.FINAL) || modifiers.contains(Modifier.PRIVATE))
           && !finalOk) {
         // TBD TBD TBD - ERROR!!! cannot extend class with superclass method like this - how to
         // report?
       } else if (modifiers.contains(Modifier.PROTECTED)) {
         data.put(methodName + "Modifiers", "protected");
       } else if (modifiers.contains(Modifier.PUBLIC)) {
         data.put(methodName + "Modifiers", "public");
       } else {
         data.put(methodName + "Modifiers", "");
       }
       return true;
     }
   }
   if (superclass.getSuperclass() != null) {
     if (superclass.getSuperclass().getDeclaration() != null) {
       if (checkInheritedMethod(
           data,
           methodName,
           returnType,
           superclass.getSuperclass().getDeclaration(),
           finalOk,
           inheritCheck)) {
         return true;
       }
     }
   }
   return false;
 }
  private void processDefaultMethods(Thing data, ClassDeclaration classDeclaration) {
    // find any methods that have default parameters
    boolean error = false;
    for (ConstructorDeclaration constructorDeclaration : classDeclaration.getConstructors()) {
      Collection<ParameterDeclaration> parameters = constructorDeclaration.getParameters();
      for (ParameterDeclaration parameterDeclaration : parameters) {
        Default annotation = parameterDeclaration.getAnnotation(Default.class);
        if (annotation != null) {
          error(parameterDeclaration, "@Default is not legal in constructor parameters");
          error = true;
        }
      }
    }
    if (error) {
      return;
    }

    boolean atLeastOneDefault = false;
    methods:
    for (MethodDeclaration methodDeclaration : classDeclaration.getMethods()) {
      Collection<ParameterDeclaration> parameters = methodDeclaration.getParameters();
      boolean seenDefault = false;
      String[] names = new String[parameters.size()];
      String[] types = new String[parameters.size()];
      String[] defaults = new String[parameters.size()];
      int n = 0;
      for (ParameterDeclaration parameterDeclaration : parameters) {
        Default annotation = parameterDeclaration.getAnnotation(Default.class);
        names[n] = parameterDeclaration.getSimpleName();
        types[n] = parameterDeclaration.getType().toString();
        if (annotation != null) {
          seenDefault = true;
          if ("java.lang.String".equals(types[n])) {
            defaults[n] = '"' + annotation.value() + '"';
          } else {
            defaults[n] = annotation.value();
          }
        } else if (seenDefault) {
          error(
              parameterDeclaration,
              "All parameters after a parameter annotated with @Default must be annotated with @Default");
          continue methods;
        }
        n++;
      }

      if (seenDefault) {
        atLeastOneDefault = true;
        if (methodDeclaration.getModifiers().contains(Modifier.PRIVATE)) {
          error(methodDeclaration, "Private methods cannot use @Default parameters");
        }
        if (methodDeclaration.getModifiers().contains(Modifier.STATIC)) {
          error(methodDeclaration, "Static methods cannot use @Default parameters");
        }
        String modifiers3 = "";
        if (methodDeclaration.getModifiers().contains(Modifier.PUBLIC)) {
          modifiers3 = "public ";
        } else if (methodDeclaration.getModifiers().contains(Modifier.PROTECTED)) {
          modifiers3 = "protected ";
        }
        String throwsClause = getThrowsClause(methodDeclaration);
        String returnType = methodDeclaration.getReturnType().toString();
        String methodName = methodDeclaration.getSimpleName();
        String argDecl = "";
        String callArgs = "";
        for (int i = 0; i < n; i++) {
          if (defaults[i] != null) {
            String callArgsWithDefaults = callArgs;
            for (int j = i; j < n; j++) {
              if (j > 0) {
                callArgsWithDefaults += ", ";
              }
              callArgsWithDefaults += defaults[j];
            }
            Thing method = new Thing("method");
            method.put("name", methodName);
            method.put("returnType", returnType);
            method.put("throwsClause", throwsClause);
            method.put("argDecls", argDecl);
            method.put("modifiers", modifiers3);
            method.put("args", callArgsWithDefaults);
            data.add("defaultMethods", method);
          }
          if (i > 0) {
            argDecl += ", ";
            callArgs += ", ";
          }
          argDecl += types[i] + ' ' + names[i];
          callArgs += names[i];
        }
        Thing method = new Thing("method");
        method.put("name", methodName);
        method.put("returnType", returnType);
        method.put("throwsClause", throwsClause);
        method.put("modifiers", modifiers3);
        method.put("abstract", true);
        method.put("argDecls", argDecl);
        data.add("defaultMethods", method);
      }
    }
    data.put("atLeastOneDefault", atLeastOneDefault);
    if (!atLeastOneDefault) {
      data.setEmpty("defaultMethods");
    }
  }
 private Thing setupMethod(ExecutableDeclaration declaration, boolean forceNonAbstract) {
   String name = null;
   String returnType = null;
   boolean isAbstract = false;
   String nullBody = null;
   String throwsClause = "";
   if (declaration instanceof ConstructorDeclaration) {
     name = "<init>";
   } else {
     MethodDeclaration methodDeclaration = (MethodDeclaration) declaration;
     name = methodDeclaration.getSimpleName();
     returnType = methodDeclaration.getReturnType().toString();
     if (!forceNonAbstract) {
       isAbstract = methodDeclaration.getModifiers().contains(Modifier.ABSTRACT);
     }
     if ("void".equals(returnType)) {
       nullBody = "// null object implementation; do nothing";
     } else if ("boolean".equals(returnType)) {
       nullBody = "false; // null object implementation";
     } else if ("char".equals(returnType)) {
       nullBody = "' '; // null object implementation";
     } else if (BeanAnnotationProcessor.PRIMITIVE_TYPES.contains(returnType)) {
       nullBody = "0; // null object implementation";
     } else {
       nullBody = "null; // null object implementation";
     }
   }
   Collection<ReferenceType> thrownTypes = declaration.getThrownTypes();
   if (!thrownTypes.isEmpty()) {
     throwsClause = "throws " + commaSeparate(thrownTypes);
   }
   String genericDecls = null;
   String argDecls = null;
   String args = null;
   String modifiers = "";
   Collection<ParameterDeclaration> parameters = declaration.getParameters();
   for (ParameterDeclaration parameterDeclaration : parameters) {
     argDecls =
         addWithCommasBetween(
             argDecls,
             parameterDeclaration.getType() + " " + parameterDeclaration.getSimpleName());
     args = addWithCommasBetween(args, parameterDeclaration.getSimpleName());
   }
   Collection<TypeParameterDeclaration> formalTypeParameters =
       declaration.getFormalTypeParameters();
   for (TypeParameterDeclaration typeParameterDeclaration : formalTypeParameters) {
     genericDecls = addWithCommasBetween(genericDecls, typeParameterDeclaration);
   }
   Collection<Modifier> modifiers2 = declaration.getModifiers();
   for (Modifier modifier : modifiers2) {
     if (!"abstract".equals(modifier.toString())) {
       modifiers += modifier.toString() + ' ';
     }
   }
   if (genericDecls == null) {
     genericDecls = "";
   } else {
     genericDecls = '<' + genericDecls + "> ";
   }
   Thing method = new Thing("method");
   method.put("name", name);
   method.put("returnType", returnType);
   method.put("abstract", isAbstract);
   method.put("nullBody", nullBody);
   method.put("modifiers", modifiers); // do not normalize; already "" or has ' ' at end
   method.put("argDecls", normalizeList(argDecls));
   method.put("args", normalizeList(args));
   method.put("genericDecls", genericDecls);
   method.put("throwsClause", throwsClause);
   return method;
 }