अगर मेरे पास इस तरह एक वर्ग है:
public class Whatever
{
public void aMethod(int aParam);
}
क्या यह जानने का कोई तरीका है कि aMethod
नामित पैरामीटर का उपयोग किया aParam
जाता है, जो कि प्रकार का है int
?
अगर मेरे पास इस तरह एक वर्ग है:
public class Whatever
{
public void aMethod(int aParam);
}
क्या यह जानने का कोई तरीका है कि aMethod
नामित पैरामीटर का उपयोग किया aParam
जाता है, जो कि प्रकार का है int
?
जवाबों:
संक्षेप में:
method.getParameterTypes()
एक संपादक के लिए स्वत: पूर्ण कार्यक्षमता लिखने के लिए (जैसा कि आप टिप्पणियों में से एक में कहा गया है) कुछ विकल्प हैं:
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
अपने जावा 8 कंपाइलर से तर्क पारित करना है तो प्रिंट करना चाहिए ।
मावेन उपयोगकर्ताओं के लिए:
<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>
अधिक जानकारी के लिए निम्न लिंक देखें:
इसी समस्या के समाधान के लिए परनामी पुस्तकालय बनाया गया।
यह कुछ अलग तरीकों से विधि के नाम निर्धारित करने की कोशिश करता है। यदि कक्षा को डिबगिंग के साथ संकलित किया गया था तो यह कक्षा के बायोटेक को पढ़कर जानकारी निकाल सकता है।
एक और तरीका यह है कि इसे संकलित किए जाने के बाद एक निजी स्थिर सदस्य को कक्षा के बाइटकोड में इंजेक्ट किया जाए, लेकिन इससे पहले कि इसे जार में रखा जाए। यह तब रनटाइम पर कक्षा से इस जानकारी को निकालने के लिए प्रतिबिंब का उपयोग करता है।
https://github.com/paul-hammant/paranamer
मुझे इस लाइब्रेरी का उपयोग करने में समस्या थी, लेकिन मैंने इसे अंत में काम कर लिया। मैं अनुचर को समस्याओं की रिपोर्ट करने की उम्मीद कर रहा हूं।
ParameterNAmesNotFoundException
org.springframework.core.efaultParameterNameDiscoverer वर्ग देखें
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
String[] params = discoverer.getParameterNames(MathUtils.class.getMethod("isPrime", Integer.class));
हाँ।
कोड को औपचारिक पैरामीटर नामों को चालू करने के लिए विकल्प ( -पारमेटर्स विकल्प) के साथ जावा 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
हालाँकि, आप उपयोग किए गए तर्क का नाम नहीं बता सकते।
यह संभव है और स्प्रिंग एमवीसी 3 इसे करता है, लेकिन मैंने यह देखने के लिए समय नहीं लिया कि कैसे।
URI टेम्प्लेट चर नामों के लिए विधि पैरामीटर नामों का मिलान केवल तभी किया जा सकता है जब आपका कोड डीबगिंग सक्षम हो। यदि आपके पास डिबगिंग सक्षम नहीं है, तो आपको @PathVariable एनोटेशन में URI टेम्प्लेट चर नाम का नाम निर्दिष्ट करना होगा ताकि वैरिएबल पैरामीटर के लिए वैरिएबल मान को एक विधि पैरामीटर में बाँध सकें। उदाहरण के लिए:
वसंत प्रलेखन से लिया गया
हालांकि यह संभव नहीं है (जैसा कि दूसरों ने सचित्र किया है), आप कर सकते थे पैरामीटर नाम पर ले जाने के लिए एक एनोटेशन का उपयोग हैं, और उस प्रतिबिंब को प्राप्त कर सकते हैं।
सबसे साफ समाधान नहीं है, लेकिन यह काम हो जाता है। कुछ webservices वास्तव में पैरामीटर नाम रखने के लिए ऐसा करते हैं (जैसे: ग्लासफिश के साथ WSs को तैनात करना)।
Java.beans.ConstructorProperties देखें , यह वास्तव में ऐसा करने के लिए डिज़ाइन किया गया एक एनोटेशन है।
तो आपको ऐसा करने में सक्षम होना चाहिए:
Whatever.declaredMethods
.find { it.name == 'aMethod' }
.parameters
.collect { "$it.type : $it.name" }
लेकिन आपको शायद एक सूची मिल जाएगी जैसे:
["int : arg0"]
मेरा मानना है कि यह ग्रूवी 2.5+ में तय किया जाएगा
तो वर्तमान में, उत्तर है:
यह सभी देखें:
हर विधि के लिए, फिर कुछ इस तरह:
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.
गलत। रेट्रोफिट लाइब्रेरी देखें। यह REST API अनुरोध बनाने के लिए डायनेमिक इंटरफेस का उपयोग करता है। इसकी एक विशेषता URL पथों में प्लेसहोल्डर नामों को परिभाषित करने और उन प्लेसहोल्डर्स को उनके संबंधित पैरामीटर नामों के साथ बदलने की क्षमता है।
मेरे 2 सेंट जोड़ने के लिए; जब आप स्रोत को संकलित करने के लिए javac -g का उपयोग करते हैं तो पैरामीटर जानकारी "डिबगिंग के लिए" एक वर्ग फ़ाइल में उपलब्ध है। और यह एपीटी के लिए उपलब्ध है, लेकिन आपको एनोटेशन की आवश्यकता होगी ताकि आपको कोई फायदा न हो। (किसी ने 4-5 साल पहले कुछ इसी तरह की चर्चा की थी: http://forums.java.net/jive/thread.jspa?messageID=13467&tstart=0 )
जब तक आप सीधे स्रोत फ़ाइलों पर काम नहीं करते हैं, कुल मिलाकर इन-शॉर्ट आपको नहीं मिल सकता है (एपीटी संकलन के समय जैसा होता है)।