दिलचस्प पोस्ट
Google Maps API v3 + jQuery UI टैब्स के साथ समस्याएं पिकासो v / s Imageloader v / s फ्रेस्को वि ग्लाइड क्या मुझे रिलीज़ एप्लिकेशन से पहले NSLog को अक्षम करना होगा? .NET clr20r3 अपवाद मापदंडों P1। P10 का गूढ़ीकरण सब-वैल के द्वारा PHP बहुआयामी सरणी को क्रमबद्ध करें आईओएस स्थिति पट्टी को कैसे छिपाएंगे I कैसे RecyclerView के साथ अंतहीन सूची को लागू करने के लिए? जावास्क्रिप्ट में "|" (एकल पाइप) क्या करता है? गुणक हस्ताक्षर में सी = में असाइनमेंट = क्या है? एंड्रॉइड एम के लिए build.grade को संकलित समय निर्भरता के रूप में अपाचे HTTP एपीआई (लीगेसी) कैसे जोड़ें? आप form1 से form2 और form1 पर वापस ऑब्जेक्ट कैसे पास करते हैं? वेब टेक्स्ट को कॉपी करने के लिए अतिरिक्त जानकारी कैसे जोड़ें यूनिकोडडेकोड एर्रर: 'एएससीआई' कोडेक स्थिति 1 में बाइट 0x एफ डीकोड नहीं कर सकता पाठ-संरेखित केंद्र का उपयोग कर केंद्र छवि? आईडी के साथ json ऑब्जेक्ट से एक दृढ़ता से टाइप किया गया सी # ऑब्जेक्ट को नाम के रूप में बनाएं

मैं जावा प्रतिबिंब का उपयोग कर विधि पैरामीटर नाम प्राप्त कर सकता हूँ?

अगर मेरे पास एक ऐसा वर्ग है:

public class Whatever { public void aMethod(int aParam); } 

क्या यह जानने का कोई तरीका है कि aMethod नाम पैरामीटर का उपयोग करता है, जो कि प्रकार int ?

वेब के समाधान से एकत्रित समाधान "मैं जावा प्रतिबिंब का उपयोग कर विधि पैरामीटर नाम प्राप्त कर सकता हूँ?"

संक्षेप में:

  • पैरामीटर नाम प्राप्त करना संभव है यदि डिबग जानकारी संकलन के दौरान शामिल है। अधिक जानकारी के लिए इस उत्तर को देखें
  • अन्यथा पैरामीटर नाम प्राप्त करना संभव नहीं है
  • method.getParameterTypes() का उपयोग कर, पैरामीटर प्रकार प्राप्त करना संभव है

एक संपादक के लिए स्वत: पूर्ण कार्यक्षमता लिखने के लिए (जैसा कि आपने एक टिप्पणी में कहा था) कुछ विकल्प हैं:

  • arg0 , arg1 , arg2 आदि का उपयोग करें
  • intParam , stringParam , objectTypeParam आदि का उपयोग करें।
  • उपरोक्त के संयोजन का उपयोग करें – गैर-आदिम प्रकारों के लिए पूर्व, और आदिम प्रकारों के लिए उत्तरार्द्ध
  • तर्क नाम बिल्कुल नहीं दिखाएं – सिर्फ प्रकार

जावा 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] को प्रिंट किया जाना चाहिए यदि आप पास गए हैं – अपने जावा 8 कंपाइलर के लिए -parameters तर्क

मैवेन उपयोगकर्ताओं के लिए:

 <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> <compilerArgument>-parameters</compilerArgument> <testCompilerArgument>-parameters</testCompilerArgument> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> </plugins> </build> 

अधिक जानकारी के लिए निम्नलिखित लिंक देखें:

  1. आधिकारिक जावा ट्यूटोरियल: विधि पैरामीटर के नाम प्राप्त करना
  2. जेईपी 118: रनटाइम में पैरामीटर नाम तक पहुंच
  3. पैरामाटर क्लास के लिए जवाडोक

इस समस्या को हल करने के लिए Paranamer पुस्तकालय बनाया गया था।

यह कुछ भिन्न तरीकों से विधि नाम निर्धारित करने का प्रयास करता है अगर क्लास डिबगिंग के साथ संकलित किया गया था, तो यह कक्षा के बाइटकोड पढ़कर जानकारी निकाल सकता है।

एक अन्य तरीका यह है कि यह एक निजी स्थिर सदस्य को कक्षा के बाइटकोड में संकलित करने के बाद इंजेक्ट करने के लिए है, लेकिन इससे पहले इसे एक जार में रखा जाता है यह तब रनटाइम पर कक्षा से इस जानकारी को निकालने के लिए प्रतिबिंब का उपयोग करता है

https://github.com/paul-hammant/paranamer

मुझे इस लाइब्रेरी का उपयोग करने में समस्याएं थीं, लेकिन मैंने इसे अंत में काम किया था। मैं देखभालकर्ता को समस्याओं की रिपोर्ट करने की उम्मीद कर रहा हूं

आप प्रतिबिंब के साथ विधि पुनः प्राप्त कर सकते हैं और इसे तर्क प्रकारों का पता लगा सकते हैं। http://java.sun.com/j2se/1.4.2/docs/api/java/lang/reflect/Method.html#getParameterTypes%28%29 देखें

हालांकि, आप प्रयोग किए गए तर्क के नाम को नहीं बता सकते।

हाँ।
संहिता जावा 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()); } } 

हालांकि यह संभव नहीं है (जैसा कि दूसरों को सचित्र है), आप पैरामीटर नाम को जारी रखने के लिए एक एनोटेशन का उपयोग कर सकते हैं, और प्राप्त करते हैं कि हालांकि प्रतिबिंब

साफ समाधान नहीं, लेकिन यह काम पूरा हो गया। कुछ webservices वास्तव में पैरामीटर नाम रखने के लिए ऐसा करते हैं (यानी: ग्लासफ़िश के साथ WSs की तैनाती)

यह संभव है और स्प्रिंग एमवीसी 3 ऐसा करता है, लेकिन मैंने समय लेने के लिए वास्तव में यह नहीं देखा कि कैसे।

यूआरआई टेम्पलेट वैरिएबल नामों के लिए पैरामीटर नामों का मिलान केवल तभी किया जा सकता है यदि आपका कोड डीबगिंग सक्षम है। यदि आपने डीबगिंग सक्षम नहीं किया है, तो आपको विधि नाम पैरामीटर में वैरिएबल नाम के हल किए गए मान को बाइंड करने के लिए @ पाथवर्वणीय एनोटेशन में यूआरआई टेम्पलेट चर नाम का नाम निर्दिष्ट करना होगा। उदाहरण के लिए:

वसंत दस्तावेज़ों से लिया गया

Java.beans.ConstructorProperties देखें, यह वास्तव में ऐसा करने के लिए डिज़ाइन किया गया एक एनोटेशन है।

तो आपको ऐसा करने में सक्षम होना चाहिए:

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

लेकिन आपको संभवतः एक सूची मिल जाएगी:

 ["int : arg0"] 

मेरा मानना ​​है कि यह Groovy 2.5+ में तय हो जाएगा

इसलिए वर्तमान में, इसका जवाब है:

  • अगर यह ग्रूवी वर्ग है, तो नहीं, आप नाम नहीं पा सकते हैं, लेकिन आप भविष्य में सक्षम होना चाहिए।
  • यदि यह जावा 8 के तहत संकलित एक जावा वर्ग है, तो आप को सक्षम होना चाहिए।

यह भी देखें:


हर विधि के लिए, फिर कुछ ऐसा:

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

org.springframework.core.DefaultParameterNameDiscoverer वर्ग देखें

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

पैरामीटर नाम केवल कंपाइलर के लिए उपयोगी हैं जब कंपाइलर एक क्लास फ़ाइल उत्पन्न करता है, पैरामीटर नाम शामिल नहीं होते हैं – एक विधि की तर्क सूची में केवल उसके तर्कों की संख्या और प्रकार होते हैं। तो प्रतिबिंब का उपयोग करके पैरामीटर नाम को प्राप्त करना असंभव होगा (जैसा कि आपके प्रश्न में टैग किया गया है) – यह कहीं भी मौजूद नहीं है

हालांकि, यदि प्रतिबिंब का उपयोग करना कठोर आवश्यकता नहीं है, तो आप इस जानकारी को सीधे स्रोत कोड से प्राप्त कर सकते हैं (यह मानते हुए कि यह आपके पास है)।

मेरे 2 सेंट जोड़ने के लिए; पैरामीटर जानकारी "डीबगिंग के लिए" क्लास फ़ाइल में उपलब्ध है जब आप स्रोत को संकलित करने के लिए javac -g का उपयोग करते हैं। और यह एपीटी के लिए उपलब्ध है, लेकिन आपको एक एनोटेशन की आवश्यकता होगी ताकि आपको कोई फायदा न हो। (किसी ने कुछ इसी तरह 4-5 साल पहले यहां चर्चा की थी: http://forums.java.net/jive/thread.jspa?messageID=13467&tstart=0 )

समग्र रूप से कम-से-कम आप इसे प्राप्त नहीं कर सकते जब तक कि आप सीधे स्रोत फ़ाइलों पर काम न करें (समान समय पर एपीटी क्या करता है)।

यदि आप ग्रहण का उपयोग करते हैं, तो क्रॉलर को विधि पैरामीटर के बारे में जानकारी संग्रहीत करने की अनुमति देने के लिए छवि को देखें

यहां छवि विवरण दर्ज करें

@ बोजो के अनुसार, संकलन के दौरान डिबग की जानकारी शामिल होने पर ऐसा करना संभव है। यहां एक अच्छा जवाब है …

ऑब्जेक्ट के कन्स्ट्रक्टर (प्रतिबिंब) के पैरामीटर नाम कैसे प्राप्त करें? @ एडमपेनटर द्वारा

… एएसएम पुस्तकालय का उपयोग करना मैंने एक उदाहरण दिखाया है कि आप अपने लक्ष्य को कैसे हासिल कर सकते हैं।

सबसे पहले, इन निर्भरताओं के साथ एक 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 पर पूर्ण उदाहरण पा सकते हैं

चेतावनियां

  • मैंने विधि से काम करने के लिए इसे @AdamPaynter से मूल समाधान को थोड़ा बदल दिया। अगर मैं ठीक से समझता हूं, उनका समाधान केवल कन्स्ट्रक्टर के साथ काम करता है
  • यह समाधान static तरीकों के साथ काम नहीं करता है यह इस मामले में क्योंकि एएसएम द्वारा दिए गए तर्कों की संख्या अलग है, लेकिन ऐसा कुछ जो आसानी से तय किया जा सकता है।