Est-il possible d'obtenir le nom de la méthode de la méthode à l'aide de la réflexion Java?

Si j'avais une telle classe:


public class Whatever
{
public void aMethod/int aParam/;
}


Y a-t-il un moyen de savoir que
aMethod

utilise le paramètre nommé
aParam

, C'est de type
int

?
Invité:

Christine

Confirmation de:

DANS Java 8 Vous pouvez faire ce qui suit:


import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

public final class Methods {

public static List<string> getParameterNames/Method method/ {
Parameter[] parameters = method.getParameters//;
List<string> parameterNames = new ArrayList&lt;&gt;//;

for /Parameter parameter : parameters/ {
if/!parameter.isNamePresent/// {
throw new IllegalArgumentException/"Parameter names are not present!"/;
}

String parameterName = parameter.getName//;
parameterNames.add/parameterName/;
}

return parameterNames;
}

private Methods//{}
}


Donc pour votre classe
Whatever

Nous pouvons faire un test de main:


import java.lang.reflect.Method;

public class ManualTest {
public static void main/String[] args/ {
Method[] declaredMethods = Whatever.class.getDeclaredMethods//;

for /Method declaredMethod : declaredMethods/ {
if /declaredMethod.getName//.equals/"aMethod"// {
System.out.println/Methods.getParameterNames/declaredMethod//;
break;
}
}
}
}


Qui devrait prendre
[aParam]

, Si vous avez passé
-parameters

Argument à votre compilateur Java 8.

Pour Maven Utilisateurs:


<properties>
<!-- PLUGIN VERSIONS -->
<maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
<!-- OTHER PROPERTIES -->
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-compiler-plugin</artifactid>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<!-- Original answer -->
<compilerargument>-parameters</compilerargument>
<!-- Or, if you use the plugin version >= 3.6.2 -->
<parameters>true</parameters>
<testcompilerargument>-parameters</testcompilerargument>
<source/>${java.version}
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>


Pour plus d'informations, voir les liens suivants:

http://docs.oracle.com/javase/ ... .html
http://openjdk.java.net/jeps/118
https://docs.oracle.com/javase ... .html
</string></string>

Babette

Confirmation de:

Résumer

Obtention des noms de paramètres

Il est possible que les informations de débogage soient activées pendant la compilation. Voir
https://coderoad.ru/6759880/
Pour plus de détails

Sinon, la réception de noms de paramètres est impossible

Obtenir le type de paramètre peut utiliser
method.getParameterTypes//


Afin d'écrire une fonctionnalité Autofill pour l'éditeur /Comme vous l'avez dit dans l'un des commentaires/ Il y a plusieurs options:

Utilisation
arg0

,
arg1

,
arg2

etc.

Utilisation
intParam

,
stringParam

,
objectTypeParam

etc.

Utilisez une combinaison de ce qui précède - Le premier pour les types non violents et la seconde pour les types primitifs.

Ne pas montrer les noms des arguments du tout - Seulement des types.

Giselle

Confirmation de:

Bibliothèque Paranamer Il a été créé pour résoudre le même problème.

Il tente d'identifier les noms des méthodes de différentes manières différentes. Si la classe a été compilée avec le débogage, elle peut extraire des informations en lisant le code octet de la classe.

Une autre solution consiste à entrer un élément statique fermé dans le code octet de la classe après sa compilation, mais avant qu'il ne soit placé dans jar. Ensuite, il réfléchit à l'extraction de ces informations de la classe pendant l'exécution.

https://github.com/paul-hammant/paranamer
J'ai eu des problèmes d'utilisation de cette bibliothèque, mais à la fin, j'ai réussi à le faire fonctionner. J'espère faire rapport sur les problèmes accompagnants.

Alice

Confirmation de:

Voir org.springframework.core.DefaultParameterNameDiscoverer Classer


DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer//;
String[] params = discoverer.getParameterNames/MathUtils.class.getMethod/"isPrime", Integer.class//;

Emilie

Confirmation de:

Oui.

Le code

doit être compilé par Java 8 Compilateur conforme

Avec la possibilité de stocker des noms de paramètres formels /option

-parameters

/.

Ensuite, ce fragment de code doit fonctionner:


Class<string> clz = String.class;
for /Method m : clz.getDeclaredMethods/// {
System.err.println/m.getName///;
for /Parameter p : m.getParameters/// {
System.err.println/" " + p.getName///;
}
}


</string>

Catherine

Confirmation de:

Vous pouvez obtenir une méthode de réflexion et déterminer ses types d'arguments. Vérifier
http://java.sun.com/j2se/1.4.2 ... %2529
Cependant, vous ne pouvez pas dire le nom de l'argument utilisé.

Agathe

Confirmation de:

C'est possible par I. Spring MVC 3 Est-ce que, mais je n'ai pas trouvé le temps de voir comment exactement.

Coïncidence des noms de paramètres de méthode
à URI Les noms du modèle de variable peuvent
Cela ne peut être fait que si votre code est compilé
Avec le débogage inclus. si tu as
Si le débogage n'est pas inclus, vous devez
Spécifiez le nom du modèle URI
Nom variable sur le terrain @PathVariable
Annotations afin de crier
Valeur variable autorisée name to
Paramètre de méthode. Par exemple:

Pris à partir de
http://static.springsource.org ... pping

Agathe

Confirmation de:

Bien que ce soit impossible /Comme d'autres exemples ont montré/, tu

Tu peux

Utilisez Annotation pour transférer le nom du paramètre et obtenez-le à travers la réflexion.

Pas la décision la plus pure, mais cela fait son travail. Certains services Web le font vraiment enregistrer les noms des paramètres. /I.e.: Déploiement WSs de glassfish/.

Giselle

Confirmation de:

Voir
http://docs.oracle.com/javase/ ... .html
, Ceci est un résumé conçu pour cela.

Hannah

Confirmation de:

Donc, vous devriez être capable de faire:


Whatever.declaredMethods
.find { it.name == 'aMethod' }
.parameters
.collect { "$it.type : $it.name" }


Mais vous obtenez probablement une telle liste:


["int : arg0"]


https://issues.apache.org/jira/browse/GROOVY-7423
Par conséquent, la réponse est actuellement ::

Si c'est une classe Groovy, Ce n'est pas le cas, vous ne pouvez pas obtenir de nom, mais vous devez être capable de le faire à l'avenir.

Si c'est une classe Java, compilé sous Java 8, Vous devez être capable de le faire.

Voir également:

http://openjdk.java.net/jeps/118
https://docs.oracle.com/javase ... .html

Pour chaque méthode, quelque chose comme:


Whatever.declaredMethods
.findAll { !it.synthetic }
.collect { method ->
println method
method.name + " -> " + method.parameters.collect { "[$it.type : $it.name]" }.join/';'/
}
.each {
println it
}

Emilie

Confirmation de:

Si vous utilisez eclipse, Voir l'image ci-dessous pour que le compilateur puisse stocker des informations sur les paramètres de la méthode.

https://i.stack.imgur.com/RSLra.png

Emilie

Confirmation de:

Comme indiqué dans @Bozho, Cela peut être fait si les informations de débogage sont activées pendant la compilation.
Il y a une bonne réponse ici ...

https://coderoad.ru/2729580/
près
@AdamPaynter
..

.

Utilisation de la bibliothèque ASM. J'ai apporté un exemple montrant comment vous pouvez atteindre votre objectif.

Tout d'abord, commencez par pom.xml Avec ces dépendances.


<dependency>
<groupid>org.ow2.asm</groupid>
<artifactid>asm-all</artifactid>
<version>5.2</version>
</dependency>
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>4.12</version>
<scope>test</scope>
</dependency>


Ensuite, cette classe devrait faire ce que vous voulez. Appelez simplement la méthode statique
getParameterNames//

.


import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodNode;

public class ArgumentReflection {
/**
* Returns a list containing one parameter name for each argument accepted
* by the given constructor. If the class was compiled with debugging
* symbols, the parameter names will match those provided in the Java source
* code. Otherwise, a generic "arg" parameter name is generated /"arg0" for
* the first argument, "arg1" for the second.../.
*
* This method relies on the constructor's class loader to locate the
* bytecode resource that defined its class.
*
* @param theMethod
* @return
* @throws IOException
*/
public static List<string> getParameterNames/Method theMethod/ throws IOException {
Class<? > declaringClass = theMethod.getDeclaringClass//;
ClassLoader declaringClassLoader = declaringClass.getClassLoader//;

Type declaringType = Type.getType/declaringClass/;
String constructorDescriptor = Type.getMethodDescriptor/theMethod/;
String url = declaringType.getInternalName// + ".class";

InputStream classFileInputStream = declaringClassLoader.getResourceAsStream/url/;
if /classFileInputStream == null/ {
throw new IllegalArgumentException/
"The constructor's class loader cannot find the bytecode that defined the constructor's class /URL: "
+ url + "/"/;
}

ClassNode classNode;
try {
classNode = new ClassNode//;
ClassReader classReader = new ClassReader/classFileInputStream/;
classReader.accept/classNode, 0/;
} finally {
classFileInputStream.close//;
}

@SuppressWarnings/"unchecked"/
List<methodnode> methods = classNode.methods;
for /MethodNode method : methods/ {
if /method.name.equals/theMethod.getName/// &amp;&amp; method.desc.equals/constructorDescriptor// {
Type[] argumentTypes = Type.getArgumentTypes/method.desc/;
List<string> parameterNames = new ArrayList<string>/argumentTypes.length/;

@SuppressWarnings/"unchecked"/
List<localvariablenode> localVariables = method.localVariables;
for /int i = 1; i &lt;= argumentTypes.length; i++/ {
// The first local variable actually represents the "this"
// object if the method is not static!
parameterNames.add/localVariables.get/i/.name/;
}

return parameterNames;
}
}

return null;
}
}


Voici un exemple avec un test modulaire.


public class ArgumentReflectionTest {

@Test
public void shouldExtractTheNamesOfTheParameters3// throws NoSuchMethodException, SecurityException, IOException {

List<string> parameterNames = ArgumentReflection
.getParameterNames/Clazz.class.getMethod/"callMe", String.class, String.class//;
assertEquals/"firstName", parameterNames.get/0//;
assertEquals/"lastName", parameterNames.get/1//;
assertEquals/2, parameterNames.size///;

}

public static final class Clazz {

public void callMe/String firstName, String lastName/ {
}

}
}


Vous pouvez trouver un exemple complet sur
https://github.com/danidemi/po ... d-asm
Précautions

J'ai changé une petite solution source avec @AdamPaynter, Pour le faire fonctionner pour des méthodes. Si je comprenais correctement, sa solution ne fonctionne qu'avec des concepteurs.

Cette solution ne fonctionne pas avec des méthodes
static

. Cela est dû au fait que dans ce cas, le nombre d'arguments renvoyés ASM, Diffère, mais c'est ce qui peut être facilement corrigé.
</string></localvariablenode></string></string></methodnode></string>

Agathe

Confirmation de:

Ajouter le mien 2 cents; Les informations de paramètre sont disponibles dans le fichier de classe. "for debugging", Quand vous utilisez javac-g Compiler la source. Et il est disponible pour APT, Mais vous aurez besoin de résumé, de sorte que vous n'en avez pas besoin. /Quelqu'un a discuté quelque chose de similaire 4-5 Il y a des années ici:
http://forums.java.net/jive/th ... t%3D0
/

En bref, vous ne pouvez pas l'obtenir si vous ne travaillez pas directement avec les fichiers source /Comme ce qui fait APT Pendant la compilation/.

Giselle

Confirmation de:

Les noms de paramètres sont utiles uniquement pour le compilateur. Lorsque le compilateur crée un fichier de classe, les noms de paramètres ne sont pas inclus - La liste des arguments de la méthode ne comprend que parmi les types de ses arguments. Ainsi, il serait impossible d'obtenir le nom du paramètre par réflexion /Comme indiqué dans votre question/ - Cela n'existe nulle part.

Toutefois, si l'utilisation de la réflexion n'est pas une exigence stricte, vous pouvez obtenir ces informations directement à partir du code source. /À condition que vous ayez/.

Pour répondre aux questions, connectez-vous ou registre