Obter nomes para os parâmetros de um método

7 respostas
brunogamacatao

Pessoal, não sei se alguém já se deparou com este problema: conseguir obter os nomes dos parâmetros dos métodos de uma classe. Isso é muito utilizado quando se está desenvolvendo um editor de código, plugin, ferramenta de documentação, etc.
Eu já tinha tentado obter estes nomes via reflexão, ASM, etc. Inclusive eu cheguei a fazer um analisador sintático de Java, utilizando o ANTLR para fazer isso pra mim (imaginem a trabalheira).
Daí ontem no trabalho eu precisei fazer um esquema desse novamente, só que desta vez resolvi usar um pouco mais a cabeça e descobri que Java provê no seu pacote tools.javadoc algumas APIs que permitem percorrer código fonte Java como se fosse uma árvore de objetos. Ou seja, um analisador sintático pronto e feito pela Sun :slight_smile:
Então, eu fiz um código que utiliza essa API e me retorna os nomes dos parâmetros para um método, coloco o código aqui por que de repente pode ser útil para alguém:

import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.RootDoc;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Bruno Gama Catão
 */
public class ParameterNamesResolver {
    private static Map<MethodSignature, List<String>> paramTable;
    
    private static String targetClass;
    
    private static void setTargetClass(String _targetClass) {
        targetClass = _targetClass;
    }
    
    public static boolean start(RootDoc root) {
        paramTable = createMap();
        
        for (ClassDoc clsDoc : root.classes()) {
            if (targetClass != null && targetClass.equals(clsDoc.name())) {
                for(MethodDoc mDoc : clsDoc.methods()) {
                    List<String> paramNames = createList();

                    for (Parameter param : mDoc.parameters()) {
                        paramNames.add(param.name());
                    }
                    
                    paramTable.put(new MethodSignature(mDoc.name(), mDoc.signature()), paramNames);
                }
            }
        }
        
        return true;
    }
    
    public static ParamNamesTable processClass(Class cls, String sourceFolder) {
        String sourcePath = cls.getName().replaceAll("\\.", "/");
        String pkgName    = sourcePath.substring(0, sourcePath.lastIndexOf("/"));
        String fileName   = sourcePath.substring(sourcePath.lastIndexOf("/") + 1);
        
        ParameterNamesResolver.setTargetClass(fileName);
        
        String[] params = {
            "-doclet", ParameterNamesResolver.class.getName(),
            "-sourcepath", sourceFolder,
            pkgName
        };
        
        com.sun.tools.javadoc.Main.execute(params);
        
        return new ParamNamesTable(paramTable);
    }
    
    private static <T> List<T> createList() {
        return new ArrayList<T>();
    }
    
    private static <K, V> Map<K, V> createMap() {
        return new HashMap<K, V>();
    }
    
    private static class MethodSignature implements Comparable<MethodSignature> {
        public String method;
        public String signature;
        
        public MethodSignature(String method, String signature) {
            this.method = method;
            this.signature = signature;
        }
        
        public int compareTo(MethodSignature ms) {
            int mDif = method.compareTo(ms.method);
            if (mDif != 0) return mDif;
            return signature.compareTo(signature);
        }
        
        @Override
        public boolean equals(Object obj) {
            MethodSignature ms = MethodSignature.class.cast(obj);
            return method.equals(ms.method) && signature.equals(ms.signature);
        }
    }
    
    public static class ParamNamesTable {
        private Map<MethodSignature, List<String>> paramTable;
        
        ParamNamesTable(Map<MethodSignature, List<String>> paramTable) {
            this.paramTable = paramTable;
        }
        
        public List<String> getParameterNames(String method, String signature) {
            return paramTable.get(new MethodSignature(method, signature));
        }

        public List<String> getParameterNames(String method) {
            for (MethodSignature ms : paramTable.keySet()) {
                if (ms.method.equals(method)) {
                    return paramTable.get(ms);
                }
            }

            return null;
        }
    }
}

Para utilizar você pode fazer:

ParameterNamesResolver.ParamNamesTable paramTable = ParameterNamesResolver.processClass(classe, "src");
List<String> names = paramTable.getParameterNames(methodName);

System.out.println("Parameters of method: " + methodName);
for (String name : names) {
    System.out.println(name);
}

7 Respostas

felipedamiani

Legal sua iniciativa, o forum não é só para perguntar mas tbm para compartilhar. :smiley:

B

Show de bola, eu ja fiz bastante coisa usando reflection, que é runtime… mas assim não… em cima do codigo. show.

C

Muito bom, parabéns.

J

Sou iniciante com java e como eu faço para adiconar ao projeto a biblioteca com.sun.javadoc.*? no NetBeans e Eclipse?

E

Ela fica em tools.jar. Ache esse arquivo dentro da sua instalação do JDK.

J

Obrigado! consegui achar aqui, porém não consegui executar o exemplo:

ParameterNamesResolver.ParamNamesTable paramTable = ParameterNamesResolver.processClass(classe, "src");   
List<String> names = paramTable.getParameterNames(methodName);   
  
System.out.println("Parameters of method: " + methodName);   
for (String name : names) {   
    System.out.println(name);   
}

a variavel “classe” passa no parametro da função como devo atribuir essa variavel?

danielfigueiredoc

Realmente, valeu cara, vou precisar usar isso!

Criado 11 de março de 2008
Ultima resposta 23 de nov. de 2009
Respostas 7
Participantes 7