このようなクラスがある場合:
public class Whatever
{
public void aMethod(int aParam);
}
それを知るためにどのような方法があるaMethod
という名前のパラメータ使用するaParam
タイプのものであり、int
?
このようなクラスがある場合:
public class Whatever
{
public void aMethod(int aParam);
}
それを知るためにどのような方法があるaMethod
という名前のパラメータ使用するaParam
タイプのものであり、int
?
回答:
要約する:
method.getParameterTypes()
エディターのオートコンプリート機能を作成するために(コメントの1つで述べたように)、いくつかのオプションがあります。
arg0
、arg1
、arg2
などintParam
、stringParam
、objectTypeParam
、などJava 8では、次のことができます。
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<>();
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(){}
}
したがって、クラスでWhatever
は手動テストを実行できます。
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;
}
}
}
}
これは印刷する必要があり[aParam]
ますが、合格した場合は-parameters
、あなたのJava 8コンパイラに引数を。
Mavenユーザーの場合:
<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}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
詳細については、次のリンクを参照してください。
Paranamerライブラリは、この同じ問題を解決するために作成されました。
それはいくつかの異なる方法でメソッド名を決定しようとします。クラスがデバッグでコンパイルされている場合、クラスのバイトコードを読み取ることで情報を抽出できます。
別の方法は、クラスのコンパイル後、jarに配置される前に、クラスのバイトコードにプライベート静的メンバーを挿入することです。次に、リフレクションを使用して、実行時にクラスからこの情報を抽出します。
https://github.com/paul-hammant/paranamer
このライブラリの使用に問題がありましたが、最終的には動作しました。問題をメンテナに報告したいと思っています。
ParameterNAmesNotFoundException
org.springframework.core.DefaultParameterNameDiscovererクラスを参照してください
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
String[] params = discoverer.getParameterNames(MathUtils.class.getMethod("isPrime", Integer.class));
はい。正式なパラメーター名を保存するオプション(-parametersオプション)を使用して、
コードをJava 8準拠のコンパイラーでコンパイルする必要があります。
次に、このコードスニペットは機能するはずです。
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());
}
}
リフレクションを使用してメソッドを取得し、その引数の型を検出できます。http://java.sun.com/j2se/1.4.2/docs/api/java/lang/reflect/Method.html#getParameterTypes%28%29を確認してください
ただし、使用する引数の名前はわかりません。
それは可能であり、Spring MVC 3がそれを行いますが、正確な方法を確認するために時間をかけませんでした。
メソッドパラメータ名とURIテンプレート変数名のマッチングは、コードがデバッグを有効にしてコンパイルされている場合にのみ実行できます。デバッグを有効にしていない場合は、@ PathVariableアノテーションでURIテンプレート変数名を指定して、変数名の解決された値をメソッドパラメータにバインドする必要があります。例えば:
春のドキュメントから取得
(他の人が説明したように)不可能ですが、アノテーションを使用してパラメーター名を引き継ぎ、リフレクションを介してそれを取得できます。
最もクリーンなソリューションではありませんが、それで仕事が完了します。一部のWebサービスは、実際にパラメーター名を保持するためにこれを実行します(つまり、glassfishを使用したWSのデプロイ)。
java.beans.ConstructorPropertiesを参照してください。これは、まさにこれを行うために設計された注釈です。
だからあなたはできるはずです:
Whatever.declaredMethods
.find { it.name == 'aMethod' }
.parameters
.collect { "$it.type : $it.name" }
しかし、おそらく次のようなリストが表示されます。
["int : arg0"]
だから現在、答えは:
以下も参照してください。
すべての方法について、次のようなもの:
Whatever.declaredMethods
.findAll { !it.synthetic }
.collect { method ->
println method
method.name + " -> " + method.parameters.collect { "[$it.type : $it.name]" }.join(';')
}
.each {
println it
}
aMethod
。クラスのすべてのメソッドで取得したい。
antlr
このためのパラメーター名を取得するために使用することはできませんか?
@Bozhoが述べたように、デバッグ情報がコンパイル中に含まれている場合、それを行うことが可能です。ここに良い答えがあります...
オブジェクトのコンストラクターのパラメーター名を取得する方法(リフレクション)?@AdamPaynterより
... ASMライブラリを使用します。目標を達成する方法を示す例をまとめます。
まず最初に、これらの依存関係を持つpom.xmlから始めます。
<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>
次に、このクラスはあなたが望むことをするべきです。静的メソッドを呼び出すだけ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()) && 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 <= 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;
}
}
単体テストの例を次に示します。
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) {
}
}
}
完全な例はGitHubにあります
static
メソッドでは機能しません。これは、この場合、ASMによって返される引数の数が異なるためですが、簡単に修正できます。パラメーター名はコンパイラーにのみ役立ちます。コンパイラがクラスファイルを生成するとき、パラメータ名は含まれません-メソッドの引数リストは、引数の数と型のみで構成されます。したがって、(質問でタグ付けされているように)リフレクションを使用してパラメーター名を取得することは不可能です-それはどこにも存在しません。
ただし、リフレクションの使用が難しい要件でない場合は、この情報をソースコードから直接取得できます(ある場合)。
Parameter names are only useful to the compiler.
違う。Retrofitライブラリを見てください。動的インターフェースを使用してREST API要求を作成します。その機能の1つは、URLパスでプレースホルダー名を定義し、それらのプレースホルダーを対応するパラメーター名で置き換える機能です。
私の2セントを追加するには; javac -gを使用してソースをコンパイルすると、「デバッグ用」のクラスファイルでパラメーター情報を利用できます。また、APTで使用できますが、注釈が必要になるため、使用する必要はありません。(誰かがここで4-5年前に同様のことについて話し合った:http : //forums.java.net/jive/thread.jspa?messageID=13467&tstart=0)
概して言えば、ソースファイルを直接操作しない限り(APTがコンパイル時に実行するのと同様に)、それを取得することはできません。