Exemple #1
0
  /**
   * Adds a syntax to the syntaxsection
   *
   * @param doc, doc item that has to be add to the syntax section
   */
  void addSyntax(Doc doc) {
    if (doc.isConstructor() || doc.isMethod()) {
      StringBuffer syntaxBuffer = new StringBuffer();
      for (Parameter parameter : ((ExecutableMemberDoc) doc).parameters()) {
        syntaxBuffer.append(parameter.typeName() + " " + parameter.name());
        syntaxBuffer.append(", ");
      }
      if (syntaxBuffer.length() > 2) {
        syntaxBuffer.delete(syntaxBuffer.length() - 2, syntaxBuffer.length());
      }

      String returnType = "";

      if (doc.isMethod()) {
        MethodDoc methodDoc = (MethodDoc) doc;
        returnType = methodDoc.returnType().toString();
        int lastDot = returnType.lastIndexOf('.');
        if (lastDot != -1) {
          returnType = returnType.substring(lastDot + 1);
        }
        returnType += " ";
      }

      if (doc.isConstructor()) {
        addSyntax("<em>" + doc.commentText() + "</em>");
      }

      addSyntax(returnType + doc.name() + "(" + syntaxBuffer.toString() + ")");
    } else if (doc.isField()) {
      FieldDoc fieldDoc = (FieldDoc) doc;
      addSyntax(fieldDoc.type().typeName() + " " + doc.name());
    }
  }
  /**
   * Prints dependencies recovered from the methods of a class. A dependency is inferred only if
   * another relation between the two classes is not already in the graph.
   *
   * @param classes
   */
  public void printInferredDependencies(ClassDoc c) {
    Options opt = optionProvider.getOptionsFor(c);

    String sourceName = c.toString();
    if (hidden(c)) return;

    Set<Type> types = new HashSet<Type>();
    // harvest method return and parameter types
    for (MethodDoc method : filterByVisibility(c.methods(false), opt.inferDependencyVisibility)) {
      types.add(method.returnType());
      for (Parameter parameter : method.parameters()) {
        types.add(parameter.type());
      }
    }
    // and the field types
    if (!opt.inferRelationships) {
      for (FieldDoc field : filterByVisibility(c.fields(false), opt.inferDependencyVisibility)) {
        types.add(field.type());
      }
    }
    // see if there are some type parameters
    if (c.asParameterizedType() != null) {
      ParameterizedType pt = c.asParameterizedType();
      types.addAll(Arrays.asList(pt.typeArguments()));
    }
    // see if type parameters extend something
    for (TypeVariable tv : c.typeParameters()) {
      if (tv.bounds().length > 0) types.addAll(Arrays.asList(tv.bounds()));
    }

    // and finally check for explicitly imported classes (this
    // assumes there are no unused imports...)
    if (opt.useImports) types.addAll(Arrays.asList(c.importedClasses()));

    // compute dependencies
    for (Type type : types) {
      // skip primitives and type variables, as well as dependencies
      // on the source class
      if (type.isPrimitive()
          || type instanceof WildcardType
          || type instanceof TypeVariable
          || c.toString().equals(type.asClassDoc().toString())) continue;

      // check if the destination is excluded from inference
      ClassDoc fc = type.asClassDoc();
      if (hidden(fc)) continue;

      // check if source and destination are in the same package and if we are allowed
      // to infer dependencies between classes in the same package
      if (!opt.inferDepInPackage && c.containingPackage().equals(fc.containingPackage())) continue;

      // if source and dest are not already linked, add a dependency
      RelationPattern rp = getClassInfo(sourceName).getRelation(fc.toString());
      if (rp == null || rp.matchesOne(new RelationPattern(RelationDirection.OUT))) {
        relation(opt, RelationType.DEPEND, c, fc, "", "", "");
      }
    }
  }
  /**
   * Parses an enum type definition
   *
   * @param docField
   * @return
   */
  protected static EnumField ParseEnumField(FieldDoc docField) {
    assert (docField != null);

    EnumField xmlEnumField = new EnumField();

    xmlEnumField.name = docField.name();
    xmlEnumField.comment = docField.commentText();

    return xmlEnumField;
  }
 /** Print the class's attributes fd */
 private void attributes(Options opt, FieldDoc fd[]) {
   for (FieldDoc f : fd) {
     if (hidden(f)) continue;
     String att = "";
     stereotype(opt, f, Align.LEFT);
     att = visibility(opt, f) + f.name();
     if (opt.showType) att += typeAnnotation(opt, f.type());
     tableLine(Align.LEFT, att);
     tagvalue(opt, f);
   }
 }
 /**
  * Build the field sub header.
  *
  * @param node the XML element that specifies which components to document
  * @param fieldsContentTree content tree to which the documentation will be added
  */
 public void buildFieldSubHeader(XMLNode node, Content fieldsContentTree) {
   if (!currentClass.definesSerializableFields()) {
     FieldDoc field = (FieldDoc) currentMember;
     fieldWriter.addMemberHeader(
         field.type().asClassDoc(),
         field.type().typeName(),
         field.type().dimension(),
         field.name(),
         fieldsContentTree);
   }
 }
  /* OVERRIDE: This method handles instance fields */
  protected String addStructMember(FieldDoc member, String cname, boolean padWord)
      throws ClassNotFoundException {
    String res = null;

    if (member.isStatic()) {
      res = addStaticStructMember(member, cname);
      //   if (res == null) /* JNI didn't handle it, print comment. */
      //  res = "    /* Inaccessible static: " + member + " */" + lineSep;
    } else {
      if (padWord) res = "    java_int padWord" + padFieldNum++ + ";" + lineSep;
      res = "    " + llniType(member.type(), false, false) + " " + llniFieldName(member);
      if (isLongOrDouble(member.type())) res = res + "[2]";
      res = res + ";" + lineSep;
    }
    return res;
  }
  private int doTwoWordFields(
      FieldDefsRes res, ClassDoc clazz, int offset, String cname, boolean padWord)
      throws ClassNotFoundException {
    boolean first = true;
    FieldDoc[] fields = clazz.fields();

    for (int i = 0; i < fields.length; i++) {
      FieldDoc field = fields[i];
      String tc = field.type().typeName();
      boolean twoWords = (tc.equals("long") || tc.equals("double"));
      if (twoWords && doField(res, field, cname, first && padWord)) {
        offset += 8;
        first = false;
      }
    }
    return offset;
  }
  protected FieldDefsRes fieldDefs(ClassDoc clazz, String cname, boolean bottomMost)
      throws ClassNotFoundException {
    FieldDefsRes res;
    int offset;
    boolean didTwoWordFields = false;
    ClassDoc superclazz = clazz.superclass();

    if (superclazz != null) {
      String supername = superclazz.qualifiedName();
      res = new FieldDefsRes(clazz, fieldDefs(superclazz, cname, false), bottomMost);
      offset = res.parent.byteSize;
    } else {
      res = new FieldDefsRes(clazz, null, bottomMost);
      offset = 0;
    }

    FieldDoc[] fields = clazz.fields();

    for (int i = 0; i < fields.length; i++) {
      FieldDoc field = fields[i];

      if (doubleAlign && !didTwoWordFields && (offset % 8) == 0) {
        offset = doTwoWordFields(res, clazz, offset, cname, false);
        didTwoWordFields = true;
      }

      String tc = field.type().typeName();
      boolean twoWords = (tc.equals("long") || tc.equals("double"));

      if (!doubleAlign || !twoWords) {
        if (doField(res, field, cname, false)) offset += 4;
      }
    }

    if (doubleAlign && !didTwoWordFields) {
      if ((offset % 8) != 0) offset += 4;
      offset = doTwoWordFields(res, clazz, offset, cname, true);
    }

    res.byteSize = offset;
    return res;
  }
  protected void forwardDecls(PrintWriter pw, ClassDoc clazz) throws ClassNotFoundException {
    ClassDoc clazzfield = null;

    if (clazz.qualifiedName().equals("java.lang.Object")) return;
    genHandleType(pw, clazz.qualifiedName());
    ClassDoc superClass = clazz.superclass();

    if (superClass != null) {
      String superClassName = superClass.qualifiedName();
      forwardDecls(pw, superClass);
    }

    for (int i = 0; i < fields.length; i++) {
      FieldDoc field = (FieldDoc) fields[i];

      if (!field.isStatic()) {
        Type t = field.type();
        String tname = t.qualifiedTypeName();
        TypeSignature newTypeSig = new TypeSignature(root);
        String sig = newTypeSig.getTypeSignature(tname);

        if (sig.charAt(0) != '[') forwardDeclsFromSig(pw, sig);
      }
    }

    for (int i = 0; i < methods.length; i++) {
      MethodDoc method = (MethodDoc) methods[i];

      if (method.isNative()) {
        Type retType = method.returnType();
        String typesig = method.signature();
        TypeSignature newTypeSig = new TypeSignature(root);
        String sig = newTypeSig.getTypeSignature(typesig, retType);

        if (sig.charAt(0) != '[') forwardDeclsFromSig(pw, sig);
      }
    }
  }
  /**
   * Prints associations recovered from the fields of a class. An association is inferred only if
   * another relation between the two classes is not already in the graph.
   *
   * @param classes
   */
  public void printInferredRelations(ClassDoc c) {
    Options opt = optionProvider.getOptionsFor(c);

    // check if the source is excluded from inference
    if (hidden(c)) return;

    for (FieldDoc field : c.fields(false)) {
      if (hidden(field)) continue;

      // skip statics
      if (field.isStatic()) continue;

      // skip primitives
      FieldRelationInfo fri = getFieldRelationInfo(field);
      if (fri == null) continue;

      // check if the destination is excluded from inference
      if (hidden(fri.cd)) continue;

      String destAdornment = fri.multiple ? "*" : "";
      relation(opt, opt.inferRelationshipType, c, fri.cd, "", "", destAdornment);
    }
  }
 /**
  * Build the serial field tags information.
  *
  * @param serializableFieldsTree content tree to which the documentation will be added
  */
 public void buildSerialFieldTagsInfo(Content serializableFieldsTree) {
   if (configuration.nocomment) {
     return;
   }
   FieldDoc field = (FieldDoc) currentMember;
   // Process Serializable Fields specified as array of
   // ObjectStreamFields. Print a member for each serialField tag.
   // (There should be one serialField tag per ObjectStreamField
   // element.)
   SerialFieldTag[] tags = field.serialFieldTags();
   Arrays.sort(tags);
   int tagsLength = tags.length;
   for (int i = 0; i < tagsLength; i++) {
     if (tags[i].fieldName() == null
         || tags[i].fieldType() == null) // ignore malformed @serialField tags
     continue;
     Content fieldsContentTree = fieldWriter.getFieldsContentHeader((i == tagsLength - 1));
     fieldWriter.addMemberHeader(
         tags[i].fieldTypeDoc(), tags[i].fieldType(), "", tags[i].fieldName(), fieldsContentTree);
     fieldWriter.addMemberDescription(tags[i], fieldsContentTree);
     serializableFieldsTree.addContent(fieldsContentTree);
   }
 }
 /**
  * Build the field information.
  *
  * @param node the XML element that specifies which components to document
  * @param fieldsContentTree content tree to which the documentation will be added
  */
 public void buildFieldInfo(XMLNode node, Content fieldsContentTree) {
   if (configuration.nocomment) {
     return;
   }
   FieldDoc field = (FieldDoc) currentMember;
   ClassDoc cd = field.containingClass();
   // Process default Serializable field.
   if ((field.tags("serial").length == 0) && !field.isSynthetic() && configuration.serialwarn) {
     configuration.message.warning(
         field.position(), "doclet.MissingSerialTag", cd.qualifiedName(), field.name());
   }
   fieldWriter.addMemberDescription(field, fieldsContentTree);
   fieldWriter.addMemberTags(field, fieldsContentTree);
 }
Exemple #13
0
  /**
   * Writes out the JML specs about the field.
   *
   * @param field the field to describe
   */
  public void writeJmlSpecs(@NonNull FieldDoc field) {
    Context context = org.jmlspecs.openjml.jmldoc.Main.jmlContext;
    Name newFieldName = Names.instance(context).fromString(field.name());
    VarSymbol newField = (VarSymbol) currentClassSym.members().lookup(newFieldName).sym;
    // System.out.println("Sym " + newField + " for " + newFieldName + " in " + currentClassSym);
    if (newField == null) return; // Inherited Java fxields?

    JmlSpecs.FieldSpecs fspecs = JmlSpecs.instance(context).getSpecs(newField);
    // FIXME - if the only specs are represent clauses, this won't print them
    String s = Utils.jmlAnnotations(newField);
    if (fspecs != null
        && (!fspecs.list.isEmpty()
            || s.length() != 0)) { // FIXME - what if there are JML annotations but no clauses
      strong("JML Specifications: ");
      writer.print(s);
      writer.dl();
      writer.preNoNewLine();
      for (JmlTree.JmlTypeClause clause : fspecs.list) {
        writer.print("    ");
        writer.print(clause);
        writer.println();
      }
      if (isModel) {
        TypeSpecs tspecs = JmlSpecs.instance(context).get(currentClassSym);
        for (JmlTypeClause t : tspecs.clauses) {
          if (!(t instanceof JmlTypeClauseRepresents)) continue;
          JmlTypeClauseRepresents tr = (JmlTypeClauseRepresents) t;
          if (!(tr.ident instanceof JCTree.JCIdent)) continue;
          Name n = ((JCTree.JCIdent) (tr.ident)).name;
          if (n == newFieldName) {
            writer.print("    ");
            writer.print(JmlPretty.write(t, false));
            writer.println();
          }
        }
      }

      writer.preEnd();
      writer.dlEnd();
    }
  }
  private FieldRelationInfo getFieldRelationInfo(FieldDoc field) {
    Type type = field.type();
    if (type.isPrimitive() || type instanceof WildcardType || type instanceof TypeVariable)
      return null;

    if (type.dimension().endsWith("[]")) {
      return new FieldRelationInfo(type.asClassDoc(), true);
    }

    Options opt = optionProvider.getOptionsFor(type.asClassDoc());
    if (opt.matchesCollPackageExpression(type.qualifiedTypeName())) {
      Type[] argTypes = getInterfaceTypeArguments(collectionClassDoc, type);
      if (argTypes != null && argTypes.length == 1 && !argTypes[0].isPrimitive())
        return new FieldRelationInfo(argTypes[0].asClassDoc(), true);

      argTypes = getInterfaceTypeArguments(mapClassDoc, type);
      if (argTypes != null && argTypes.length == 2 && !argTypes[1].isPrimitive())
        return new FieldRelationInfo(argTypes[1].asClassDoc(), true);
    }

    return new FieldRelationInfo(type.asClassDoc(), false);
  }
 public static boolean start(RootDoc root) {
   ClassDoc cd = root.classes()[0];
   FieldDoc fd = cd.fields()[0];
   fd.firstSentenceTags();
   return true;
 }
 @Override
 public DocReferenceable getFieldDocRef(FieldDoc fieldDoc) {
   return new UnknownApiRef(fieldDoc.name());
 }
  /**
   * Prints the class if needed.
   *
   * <p>A class is a rootClass if it's included among the classes returned by RootDoc.classes(),
   * this information is used to properly compute relative links in diagrams for UMLDoc
   */
  public String printClass(ClassDoc c, boolean rootClass) {
    ClassInfo ci;
    boolean toPrint;
    Options opt = optionProvider.getOptionsFor(c);

    String className = c.toString();
    if ((ci = getClassInfo(className)) != null) toPrint = !ci.nodePrinted;
    else {
      toPrint = true;
      ci = newClassInfo(className, true, hidden(c));
    }
    if (toPrint && !hidden(c) && (!c.isEnum() || opt.showEnumerations)) {
      // Associate classname's alias
      String r = className;
      w.println("\t// " + r);
      // Create label
      w.print("\t" + ci.name + " [label=");

      boolean showMembers =
          (opt.showAttributes && c.fields().length > 0)
              || (c.isEnum() && opt.showEnumConstants && c.enumConstants().length > 0)
              || (opt.showOperations && c.methods().length > 0)
              || (opt.showConstructors && c.constructors().length > 0);

      externalTableStart(opt, c.qualifiedName(), classToUrl(c, rootClass));

      // Calculate the number of innerTable rows we will emmit
      int nRows = 1;
      if (showMembers) {
        if (opt.showAttributes) nRows++;
        else if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) nRows++;
        if (c.isEnum() && opt.showEnumConstants) nRows++;
        if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) nRows++;
      }

      firstInnerTableStart(opt, nRows);
      if (c.isInterface()) tableLine(Align.CENTER, guilWrap(opt, "interface"));
      if (c.isEnum()) tableLine(Align.CENTER, guilWrap(opt, "enumeration"));
      stereotype(opt, c, Align.CENTER);
      Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT : Font.CLASS;
      String qualifiedName = qualifiedName(opt, r);
      int startTemplate = qualifiedName.indexOf('<');
      int idx = 0;
      if (startTemplate < 0) idx = qualifiedName.lastIndexOf('.');
      else idx = qualifiedName.lastIndexOf('.', startTemplate);
      if (opt.showComment)
        tableLine(Align.LEFT, htmlNewline(escape(c.commentText())), opt, Font.CLASS);
      else if (opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) {
        String packageName = qualifiedName.substring(0, idx);
        String cn = className.substring(idx + 1);
        tableLine(Align.CENTER, escape(cn), opt, font);
        tableLine(Align.CENTER, packageName, opt, Font.PACKAGE);
      } else {
        tableLine(Align.CENTER, escape(qualifiedName), opt, font);
      }
      tagvalue(opt, c);
      firstInnerTableEnd(opt, nRows);

      /*
       * Warning: The boolean expressions guarding innerTableStart()
       * in this block, should match those in the code block above
       * marked: "Calculate the number of innerTable rows we will emmit"
       */
      if (showMembers) {
        if (opt.showAttributes) {
          innerTableStart();
          FieldDoc[] fields = c.fields();
          // if there are no fields, print an empty line to generate proper HTML
          if (fields.length == 0) tableLine(Align.LEFT, "");
          else attributes(opt, c.fields());
          innerTableEnd();
        } else if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) {
          // show an emtpy box if we don't show attributes but
          // we show operations
          innerTableStart();
          tableLine(Align.LEFT, "");
          innerTableEnd();
        }
        if (c.isEnum() && opt.showEnumConstants) {
          innerTableStart();
          FieldDoc[] ecs = c.enumConstants();
          // if there are no constants, print an empty line to generate proper HTML
          if (ecs.length == 0) {
            tableLine(Align.LEFT, "");
          } else {
            for (FieldDoc fd : c.enumConstants()) {
              tableLine(Align.LEFT, fd.name());
            }
          }
          innerTableEnd();
        }
        if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) {
          innerTableStart();
          boolean printedLines = false;
          if (opt.showConstructors) printedLines |= operations(opt, c.constructors());
          if (opt.showOperations) printedLines |= operations(opt, c.methods());

          if (!printedLines)
            // if there are no operations nor constructors,
            // print an empty line to generate proper HTML
            tableLine(Align.LEFT, "");

          innerTableEnd();
        }
      }
      externalTableEnd();
      w.print(", URL=\"" + classToUrl(c, rootClass) + "\"");
      nodeProperties(opt);

      // If needed, add a note for this node
      int ni = 0;
      for (Tag t : c.tags("note")) {
        String noteName = "n" + ni + "c" + ci.name;
        w.print("\t// Note annotation\n");
        w.print("\t" + noteName + " [label=");
        externalTableStart(
            UmlGraph.getCommentOptions(), c.qualifiedName(), classToUrl(c, rootClass));
        innerTableStart();
        tableLine(
            Align.LEFT, htmlNewline(escape(t.text())), UmlGraph.getCommentOptions(), Font.CLASS);
        innerTableEnd();
        externalTableEnd();
        nodeProperties(UmlGraph.getCommentOptions());
        w.print("\t" + noteName + " -> " + relationNode(c) + "[arrowhead=none];\n");
        ni++;
      }
      ci.nodePrinted = true;
    }
    return ci.name;
  }
  /**
   * Parses a field type definition
   *
   * @param docField
   * @return
   */
  protected static Field ParseField(FieldDoc docField) {
    assert (docField != null);

    Field xmlField = new Field();

    xmlField.name = docField.name();
    xmlField.comment = docField.commentText();
    xmlField.type = ParseType(docField.type());
    xmlField.isFinal = docField.isFinal();
    if (xmlField.isFinal) {
      xmlField.finalExpression = docField.constantValueExpression();
    } else if (docField.constantValueExpression() != null) {
      // how would a non-final field have a constant value expression?
      // my understanding is that this field is only != null when is not final
      assert (false);
    }
    xmlField.isStatic = docField.isStatic();
    xmlField.isVolatile = docField.isVolatile();
    xmlField.isTransient = docField.isTransient();
    xmlField.scope = DetermineScope(docField);

    // parse annotations from the field
    xmlField.annotationInstances =
        ParseAnnotationInstances(docField.annotations(), docField.qualifiedName());

    return xmlField;
  }
  /**
   * Parses annotation instances from the javadoc annotation instance type
   *
   * @param annotationDocs Annotations decorated on some type
   * @return Serializable representation of annotations
   */
  protected static AnnotationInstance[] ParseAnnotationInstances(
      AnnotationDesc[] annotationDocs, String origin) {
    AnnotationInstance[] annotations = null;

    if (annotationDocs != null && annotationDocs.length > 0) {
      ArrayList<AnnotationInstance> list = new ArrayList<AnnotationInstance>();

      for (AnnotationDesc annot : annotationDocs) {
        AnnotationInstance instance = new AnnotationInstance();

        AnnotationTypeDoc annotTypeInfo = null;
        try {
          annotTypeInfo = annot.annotationType();
          instance.name = annot.annotationType().name();
          instance.qualifiedName = annot.annotationType().qualifiedTypeName();

        } catch (ClassCastException castException) {
          log.error("Unable to obtain type data about an annotation found on: " + origin);
          log.error("Add to the -cp parameter the class/jar that defines this annotation.");
          instance.name = null;
          instance.qualifiedName = null;
        }

        AnnotationDesc.ElementValuePair[] arguments = annot.elementValues();
        if (arguments != null && arguments.length > 0) {
          ArrayList<AnnotationArgument> argumentList = new ArrayList<AnnotationArgument>();

          for (AnnotationDesc.ElementValuePair pair : arguments) {
            AnnotationArgument annotationArgument = new AnnotationArgument();
            annotationArgument.name = pair.element().name();

            Type annotationArgumentType = pair.element().returnType();
            annotationArgument.type = annotationArgumentType.qualifiedTypeName();
            annotationArgument.isPrimitive = annotationArgumentType.isPrimitive();
            annotationArgument.isArray = annotationArgumentType.dimension().length() > 0;

            Object objValue = pair.value().value();
            if (objValue instanceof AnnotationValue[]) {
              AnnotationValue[] realValues = (AnnotationValue[]) objValue;
              String[] values = new String[realValues.length];

              for (int i = 0; i < realValues.length; i++) {
                values[i] = realValues[i].value().toString();
              }
              annotationArgument.value = values;
            } else if (objValue instanceof Number) {
              Number number = (Number) objValue;
              annotationArgument.value = new String[] {number.toString()};
            } else if (objValue instanceof Character) {
              Character character = (Character) objValue;
              annotationArgument.value = new String[] {character.toString()};
            } else if (objValue instanceof Boolean) {
              Boolean booleanValue = (Boolean) objValue;
              annotationArgument.value = new String[] {booleanValue.toString()};
            } else if (objValue instanceof String) {
              String stringValue = (String) objValue;
              annotationArgument.value = new String[] {stringValue};
            } else if (objValue instanceof FieldDoc) {
              FieldDoc field = (FieldDoc) objValue;
              annotationArgument.value = new String[] {field.name()};
            } else if (objValue instanceof ClassDoc) {
              ClassDoc classDoc = (ClassDoc) objValue;
              annotationArgument.value = new String[] {classDoc.qualifiedTypeName()};
            }
            argumentList.add(annotationArgument);
          }

          instance.arguments = argumentList.toArray(new AnnotationArgument[] {});
        }

        list.add(instance);
      }

      annotations = list.toArray(new AnnotationInstance[] {});
    }

    return annotations;
  }
  private void walkFormParameter(ClassDoc formDoc) {
    // walk all fields
    for (FieldDoc field : formDoc.fields(false)) {
      final AnnotationDesc pathParamAnnotation = Utils.findAnnotation(field, PathParam.class);
      if (pathParamAnnotation != null) {
        String name = (String) Utils.getAnnotationValue(pathParamAnnotation);
        pathParameters.add(
            new FormFieldParameter(field, pathParamAnnotation, MethodParameterType.Path));
        continue;
      }
      final AnnotationDesc matrixParamAnnotation = Utils.findAnnotation(field, MatrixParam.class);
      if (matrixParamAnnotation != null) {
        matrixParameters.add(
            new FormFieldParameter(field, matrixParamAnnotation, MethodParameterType.Matrix));
        continue;
      }
      final AnnotationDesc queryParamAnnotation = Utils.findAnnotation(field, QueryParam.class);
      if (queryParamAnnotation != null) {
        String name = (String) Utils.getAnnotationValue(queryParamAnnotation);
        queryParameters.add(
            new FormFieldParameter(field, queryParamAnnotation, MethodParameterType.Query));
        continue;
      }
      final AnnotationDesc headerParamAnnotation = Utils.findAnnotation(field, HeaderParam.class);
      if (headerParamAnnotation != null) {
        String name = (String) Utils.getAnnotationValue(headerParamAnnotation);
        headerParameters.add(
            new FormFieldParameter(field, headerParamAnnotation, MethodParameterType.Header));
        continue;
      }
      final AnnotationDesc cookieParamAnnotation = Utils.findAnnotation(field, CookieParam.class);
      if (cookieParamAnnotation != null) {
        String name = (String) Utils.getAnnotationValue(cookieParamAnnotation);
        cookieParameters.add(
            new FormFieldParameter(field, cookieParamAnnotation, MethodParameterType.Cookie));
        continue;
      }
      final AnnotationDesc formParamAnnotation = Utils.findAnnotation(field, FormParam.class);
      if (formParamAnnotation != null) {
        formParameters.add(
            new FormFieldParameter(field, formParamAnnotation, MethodParameterType.Form));
        continue;
      }
      // Recurse into the embedded @Form field
      if (formClass != null) {
        final AnnotationDesc formAnnotation = Utils.findAnnotation(field, formClass);
        if (formAnnotation != null) {
          walkFormParameter(field.type().asClassDoc());
          continue;
        }
      }

      final AnnotationDesc contextAnnotation = Utils.findAnnotation(field, Context.class);
      if (contextAnnotation == null) {
        this.inputParameter = new FormFieldParameter(field, null, MethodParameterType.Input);
        continue;
      }
    }
    // and methods
    for (MethodDoc method : formDoc.methods(false)) {
      if (!method.returnType().qualifiedTypeName().equals("void")
          || method.parameters().length != 1
          || !method.name().startsWith("set")) continue;
      Parameter parameter = method.parameters()[0];
      final AnnotationDesc pathParamAnnotation =
          Utils.findParameterAnnotation(method, parameter, 0, PathParam.class);
      if (pathParamAnnotation != null) {
        String name = (String) Utils.getAnnotationValue(pathParamAnnotation);
        pathParameters.add(
            new FormMethodParameter(method, pathParamAnnotation, MethodParameterType.Path));
        continue;
      }
      final AnnotationDesc matrixParamAnnotation =
          Utils.findParameterAnnotation(method, parameter, 0, MatrixParam.class);
      if (matrixParamAnnotation != null) {
        String name = (String) Utils.getAnnotationValue(matrixParamAnnotation);
        matrixParameters.add(
            new FormMethodParameter(method, matrixParamAnnotation, MethodParameterType.Matrix));
        continue;
      }
      final AnnotationDesc queryParamAnnotation =
          Utils.findParameterAnnotation(method, parameter, 0, QueryParam.class);
      if (queryParamAnnotation != null) {
        String name = (String) Utils.getAnnotationValue(queryParamAnnotation);
        queryParameters.add(
            new FormMethodParameter(method, queryParamAnnotation, MethodParameterType.Query));
        continue;
      }
      final AnnotationDesc headerParamAnnotation =
          Utils.findParameterAnnotation(method, parameter, 0, HeaderParam.class);
      if (headerParamAnnotation != null) {
        String name = (String) Utils.getAnnotationValue(headerParamAnnotation);
        headerParameters.add(
            new FormMethodParameter(method, headerParamAnnotation, MethodParameterType.Header));
        continue;
      }
      final AnnotationDesc cookieParamAnnotation =
          Utils.findParameterAnnotation(method, parameter, 0, CookieParam.class);
      if (cookieParamAnnotation != null) {
        String name = (String) Utils.getAnnotationValue(cookieParamAnnotation);
        cookieParameters.add(
            new FormMethodParameter(method, cookieParamAnnotation, MethodParameterType.Cookie));
        continue;
      }
      final AnnotationDesc formParamAnnotation =
          Utils.findParameterAnnotation(method, parameter, 0, FormParam.class);
      if (formParamAnnotation != null) {
        String name = (String) Utils.getAnnotationValue(formParamAnnotation);
        formParameters.add(
            new FormMethodParameter(method, formParamAnnotation, MethodParameterType.Form));
        continue;
      }
      // I'm not sure if @Form can be used on setter methods on an @Form field, but just in case...
      if (formClass != null) {
        // recurse into @Form parameters
        final AnnotationDesc formAnnotation =
            Utils.findParameterAnnotation(method, parameter, 0, formClass);
        if (formAnnotation != null) {
          walkFormParameter(parameter.type().asClassDoc());
          continue;
        }
      }
      final AnnotationDesc contextAnnotation =
          Utils.findParameterAnnotation(method, parameter, 0, Context.class);
      if (contextAnnotation == null) {
        this.inputParameter = new FormMethodParameter(method, null, MethodParameterType.Input);
      }
    }
  }
  /*
   * This method only handles static final fields.
   */
  protected String addStaticStructMember(FieldDoc field, String cname)
      throws ClassNotFoundException {
    String res = null;
    Object exp = null;

    if (!field.isStatic()) return res;
    if (!field.isFinal()) return res;

    exp = field.constantValue();

    if (exp != null) {
      /* Constant. */

      String cn = cname + "_" + field.name();
      String suffix = null;
      long val = 0;
      /* Can only handle int, long, float, and double fields. */
      if (exp instanceof Integer) {
        suffix = "L";
        val = ((Integer) exp).intValue();
      }
      if (exp instanceof Long) {
        // Visual C++ supports the i64 suffix, not LL
        suffix = isWindows ? "i64" : "LL";
        val = ((Long) exp).longValue();
      }
      if (exp instanceof Float) suffix = "f";
      if (exp instanceof Double) suffix = "";
      if (suffix != null) {
        // Some compilers will generate a spurious warning
        // for the integer constants for Integer.MIN_VALUE
        // and Long.MIN_VALUE so we handle them specially.
        if ((suffix.equals("L") && (val == Integer.MIN_VALUE))
            || (suffix.equals("LL") && (val == Long.MIN_VALUE))) {
          res =
              "    #undef  "
                  + cn
                  + lineSep
                  + "    #define "
                  + cn
                  + " ("
                  + (val + 1)
                  + suffix
                  + "-1)"
                  + lineSep;
        } else {
          res =
              "    #undef  "
                  + cn
                  + lineSep
                  + "    #define "
                  + cn
                  + " "
                  + exp.toString()
                  + suffix
                  + lineSep;
        }
      }
    }
    return res;
  }