/** {@inheritDoc} */ public void inherit(DocFinder.Input input, DocFinder.Output output) { if (input.tagId == null) { input.isTypeVariableParamTag = ((ParamTag) input.tag).isTypeParameter(); Object[] parameters = input.isTypeVariableParamTag ? (Object[]) ((MethodDoc) input.tag.holder()).typeParameters() : (Object[]) ((MethodDoc) input.tag.holder()).parameters(); String target = ((ParamTag) input.tag).parameterName(); int i; for (i = 0; i < parameters.length; i++) { String name = parameters[i] instanceof Parameter ? ((Parameter) parameters[i]).name() : ((TypeVariable) parameters[i]).typeName(); if (name.equals(target)) { input.tagId = String.valueOf(i); break; } } if (i == parameters.length) { // Someone used {@inheritDoc} on an invalid @param tag. // We don't know where to inherit from. // XXX: in the future when Configuration is available here, // print a warning for this mistake. return; } } ParamTag[] tags = input.isTypeVariableParamTag ? input.method.typeParamTags() : input.method.paramTags(); Map rankMap = getRankMap( input.isTypeVariableParamTag ? (Object[]) input.method.typeParameters() : (Object[]) input.method.parameters()); for (int i = 0; i < tags.length; i++) { if (rankMap.containsKey(tags[i].parameterName()) && rankMap.get(tags[i].parameterName()).equals((input.tagId))) { output.holder = input.method; output.holderTag = tags[i]; output.inlineTags = input.isFirstSentence ? tags[i].firstSentenceTags() : tags[i].inlineTags(); return; } } }
/** * Given an array of <code>Tag</code>s representing this custom tag, return its string * representation. Print a warning for param tags that do not map to parameters. Print a warning * for param tags that are duplicated. * * @param paramTags the array of <code>ParamTag</code>s to convert. * @param writer the TagletWriter that will write this tag. * @param alreadyDocumented the set of exceptions that have already been documented. * @param rankMap a {@link java.util.Map} which holds ordering information about the parameters. * @param nameMap a {@link java.util.Map} which holds a mapping of a rank of a parameter to its * name. This is used to ensure that the right name is used when parameter documentation is * inherited. * @return the TagletOutput representation of this <code>Tag</code>. */ private TagletOutput processParamTags( boolean isNonTypeParams, ParamTag[] paramTags, Map rankMap, TagletWriter writer, Set alreadyDocumented) { TagletOutput result = writer.getOutputInstance(); if (paramTags.length > 0) { for (int i = 0; i < paramTags.length; ++i) { ParamTag pt = paramTags[i]; String paramName = isNonTypeParams ? pt.parameterName() : "<" + pt.parameterName() + ">"; if (!rankMap.containsKey(pt.parameterName())) { writer .getMsgRetriever() .warning( pt.position(), isNonTypeParams ? "doclet.Parameters_warn" : "doclet.Type_Parameters_warn", paramName); } String rank = (String) rankMap.get(pt.parameterName()); if (rank != null && alreadyDocumented.contains(rank)) { writer .getMsgRetriever() .warning( pt.position(), isNonTypeParams ? "doclet.Parameters_dup_warn" : "doclet.Type_Parameters_dup_warn", paramName); } result.appendOutput( processParamTag( isNonTypeParams, writer, pt, pt.parameterName(), alreadyDocumented.size() == 0)); alreadyDocumented.add(rank); } } return result; }
/** * The entry point into the Parser class. * * @param root A RootDoc intstance obtained via the doclet API * @return A XML (XStream) serializable element, containing everything parsed from javadoc doclet */ public static Root ParseRoot(RootDoc root) { processingStorage = new HashMap<PackageDoc, ParserMediary>(); try { md5 = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { log.error("unable to acquire MD5 algorithm", e); return null; } rootXml = new Root(); ClassDoc[] allClasses = root.classes(); for (ClassDoc classDoc : allClasses) { PackageDoc doc = classDoc.containingPackage(); ParserMediary mediary = null; // the age old 'if I have it pull out existing, if I don't make a new one' if (processingStorage.containsKey(doc)) { mediary = processingStorage.get(doc); } else { mediary = new ParserMediary( doc.name(), doc.commentText(), ParseAnnotationInstances(doc.annotations(), doc.name())); processingStorage.put(doc, mediary); } if (classDoc.isIncluded()) { // dev comment--why do enums show up as ordinary class? if (classDoc.isOrdinaryClass() || classDoc.isException() || classDoc.isError()) { mediary.addClass(ParseClass(classDoc)); } else if (classDoc.isEnum()) { mediary.addEnum(ParseEnum(classDoc)); } else if (isAnnotation(classDoc)) { mediary.addAnnotation(ParseAnnotation(classDoc)); } else if (classDoc.isInterface()) { mediary.addInterface(ParseInterface(classDoc)); } } else { log.debug("Skipping not-included class " + classDoc.qualifiedName()); } } if (processingStorage.size() > 0) { List list = new ArrayList<Package>(); for (ParserMediary mediary : processingStorage.values()) { list.add(mediary.wrapup()); } rootXml.packages = (Package[]) list.toArray(new Package[] {}); } else { log.warn("No packages found!"); } return rootXml; }
/** * Process each package and the classes/interfaces within it. * * @param pd an array of PackageDoc objects */ public void processPackages(RootDoc root) { PackageDoc[] specified_pd = root.specifiedPackages(); Map pdl = new TreeMap(); for (int i = 0; specified_pd != null && i < specified_pd.length; i++) { pdl.put(specified_pd[i].name(), specified_pd[i]); } // Classes may be specified separately, so merge their packages into the // list of specified packages. ClassDoc[] cd = root.specifiedClasses(); // This is lists of the specific classes to document Map classesToUse = new HashMap(); for (int i = 0; cd != null && i < cd.length; i++) { PackageDoc cpd = cd[i].containingPackage(); if (cpd == null && !packagesOnly) { // If the RootDoc object has been created from a jar file // this duplicates classes, so we have to be able to disable it. // TODO this is still null? cpd = root.packageNamed("anonymous"); } String pkgName = cpd.name(); String className = cd[i].name(); if (trace) System.out.println("Found package " + pkgName + " for class " + className); if (!pdl.containsKey(pkgName)) { if (trace) System.out.println("Adding new package " + pkgName); pdl.put(pkgName, cpd); } // Keep track of the specific classes to be used for this package List classes; if (classesToUse.containsKey(pkgName)) { classes = (ArrayList) classesToUse.get(pkgName); } else { classes = new ArrayList(); } classes.add(cd[i]); classesToUse.put(pkgName, classes); } PackageDoc[] pd = (PackageDoc[]) pdl.values().toArray(new PackageDoc[0]); for (int i = 0; pd != null && i < pd.length; i++) { String pkgName = pd[i].name(); // Check for an exclude tag in the package doc block, but not // in the package.htm[l] file. if (!shownElement(pd[i], null)) continue; if (trace) System.out.println("PROCESSING PACKAGE: " + pkgName); outputFile.println("<package name=\"" + pkgName + "\">"); int tagCount = pd[i].tags().length; if (trace) System.out.println("#tags: " + tagCount); List classList; if (classesToUse.containsKey(pkgName)) { // Use only the specified classes in the package System.out.println("Using the specified classes"); classList = (ArrayList) classesToUse.get(pkgName); } else { // Use all classes in the package classList = new LinkedList(Arrays.asList(pd[i].allClasses())); } Collections.sort(classList); ClassDoc[] classes = new ClassDoc[classList.size()]; classes = (ClassDoc[]) classList.toArray(classes); processClasses(classes, pkgName); addPkgDocumentation(root, pd[i], 2); outputFile.println("</package>"); } } // processPackages