Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doclet- Get generics of a list

I am writing a doclet extending com.sun.javadoc.Doclet.

When i want want to document an ArrayList as a field of a method i want to get the type of the generic (e.g. when documenting an ArrayList<String> I want to get the information that this is a list containing Strings).

I am only able to get the information, that this is a ArrayList. Even when calling

ParameterizedType paramType = fieldType.asParameterizedType();

I am only getting java.util.ArrayList and not the type of the generic.

Does someone know how to get the generic type of the list?

Here is the example code:

FieldDoc[] fields = classDoc.fields();
for (int k = 0; k < fields.length; k++) {
    Type fieldType = fields[k].type();
    if (fieldType.asParameterizedType() != null) {
        ParameterizedType paramType = fieldType.asParameterizedType();
        String qualiName = paramType.qualifiedTypeName(); // this equals "java.util.ArrayList"
        fieldType.asParameterizedType().toString(); // this equals "java.util.ArrayList"
        fieldType.asParameterizedType().typeName(); // this equals "ArrayList"
    }
}
like image 919
rch Avatar asked Apr 20 '11 14:04

rch


3 Answers

I was running into generics being lost on types while writing a custom doclet under Java 1.6. I was able to fix it by adding the method below to my doclet.


   /**
    * NOTE: Without this method present and returning LanguageVersion.JAVA_1_5,
    *       Javadoc will not process generics because it assumes LanguageVersion.JAVA_1_1
    * @return language version (hard coded to LanguageVersion.JAVA_1_5)
    */
   public static LanguageVersion languageVersion() {
      return LanguageVersion.JAVA_1_5;
   }
like image 86
Trex Avatar answered Nov 08 '22 23:11

Trex


Could it be that the output is java.util.ArrayList<String> and you don't see the <String> part since your browser interprets it as an unknown HTML tag?

You will have to escape the < for HTML output.

If this is not the problem, show enough code so we can reproduce the problem.


After seeing your example, I could reproduce it with this doclet:

package de.fencing_game.paul.examples.doclet;

import com.sun.javadoc.*;
import java.util.ArrayList;

/**
 * A test doclet to see how generic fields work.
 *
 * Inspired by the question <a href="http://stackoverflow.com/q/5731619/600500">Doclet- Get generics of a list</a> on Stackoverflow.
 */
public class GenericTestDoclet<Y> extends Doclet {

    public ArrayList<? extends Y> stringList;

    /**
     * Erstellt ein(e(n)) neu(e(n)) <code>GenericTestDoclet</code>.
     *
     */
    public GenericTestDoclet() {

    }


    public ArrayList<? extends Y> getList() {
        return stringList;
    }

    public void printType(Type fieldType, DocErrorReporter err) {
        err.printNotice("type: " + fieldType);
        if (fieldType.asParameterizedType() != null) {
            ParameterizedType paramType = fieldType.asParameterizedType();
            err.printNotice("paramType:" + paramType);
            String qualiName = paramType.qualifiedTypeName();
            err.printNotice("qualiName: " + qualiName);

            String typeName = fieldType.asParameterizedType().typeName();
            err.printNotice("typeName: " + typeName);

            Type[] parameters = paramType.typeArguments();
            err.printNotice("parameters.length: " + parameters.length);
            for(Type p : parameters) {
                err.printNotice("param: " + p);
            }
        }
        err.printNotice("");
    }


    public void listFields(ClassDoc classDoc, DocErrorReporter err) {
        FieldDoc[] fields = classDoc.fields();
        for (int k = 0; k < fields.length; k++) {
            err.printNotice("field: " + fields[k]);
            Type fieldType = fields[k].type();
            printType(fieldType, err);
        }
    }


    public void listMethods(ClassDoc classDoc, DocErrorReporter err) {
        MethodDoc[] methods = classDoc.methods();
        for (int k = 0; k < methods.length; k++) {
            err.printNotice("method: " + methods[k]);
            Type returnType = methods[k].returnType();
            printType(returnType, err);
        }
    }



    /**
     * The entry point of the doclet.
     * @return true if all the included elements have enough documentation,
     *   false if some documentation is missing.
     */
    public static boolean start(RootDoc root) {
        GenericTestDoclet<?> d = new GenericTestDoclet<Integer>();
        for(ClassDoc clazz : root.classes()) {
            d.listFields(clazz, root);
            d.listMethods(clazz, root);
        }
        return true;
    }

}

The output, if applied on itself:

field: de.fencing_game.paul.examples.doclet.GenericTestDoclet.stringList
type: java.util.ArrayList
paramType:java.util.ArrayList
qualiName: java.util.ArrayList
typeName: ArrayList
parameters.length: 0

method: de.fencing_game.paul.examples.doclet.GenericTestDoclet.getList()
type: java.util.ArrayList
paramType:java.util.ArrayList
qualiName: java.util.ArrayList
typeName: ArrayList
parameters.length: 0

[more methods omitted]

It shows that also return types seem to be parameterless here.

I wanted to say that I already used this method to print recursively a type name, but it shows that my LaTeX-Doclet actually is not even using the recursive method I created (instead the types are printed from the compiler tree of the type).

But somehow this has to be possible, since somehow the Standard Doclet manges to create the right output.

like image 29
Paŭlo Ebermann Avatar answered Nov 09 '22 00:11

Paŭlo Ebermann


After enabling Java 1.5 mode with Trex's answer, you can access the generic types of fieldType using

Type[] typeArguments = fieldType.asParameterizedType().typeArguments()
like image 32
Ben Hutchison Avatar answered Nov 08 '22 23:11

Ben Hutchison