2009-05-30 14 views
28

मुझे जावा में मेरे लिए रुचि के तरीके के लिए सभी कॉलर विधियों की एक सूची प्राप्त करने की आवश्यकता है। क्या कोई ऐसा उपकरण है जो मेरी मदद कर सकता है?जावा में दी गई विधि को कॉल करने वाली सभी विधियों को मैं कैसे ढूंढ सकता हूं?

संपादित करें: मैं यह उल्लेख करना भूल गया कि मुझे इसे किसी प्रोग्राम से करने की आवश्यकता है। मैं जावा पाथफाइंडर का उपयोग कर रहा हूं और मैं इसे उन सभी विधियों को चलाने के लिए चाहता हूं जो मेरी रुचि के तरीके को बुलाते हैं।

+3

दोस्तों मिक्लोसर ने क्यू संपादित किया और कहा कि यह रनटाइम पर होने की आवश्यकता है, वहां अनगिनत लोग दिखाई देते हैं कि यह आईडीई में कैसे किया जाए। ऊपर वोट @ चाडविक –

+1

शायद आप समझा सकते हैं कि आपको रनटाइम पर ऐसा करने की आवश्यकता क्यों है क्योंकि लोग इस आवश्यकता में नहीं आ सकते हैं। –

उत्तर

39

बाइटकोड का विश्लेषण करने के लिए, मैं ASM की अनुशंसा करता हूं। विश्लेषण करने के लिए कक्षाओं की एक सूची को देखते हुए, एक आगंतुक बनाया जा सकता है जिसमें आपको रुचि रखने वाली विधि कॉल मिलती है। एक कार्यान्वयन जो जार फ़ाइल में कक्षाओं का विश्लेषण करता है, नीचे है।

ध्यान दें कि एएसएम internalNames का उपयोग '/' के बजाय '/' के साथ करता है। एक विभाजक के रूप में। संशोधक के बिना standard declaration के रूप में लक्ष्य विधि निर्दिष्ट करें।

java -cp "classes;asm-3.1.jar;asm-commons-3.1.jar" App \ 
    c:/java/jdk/jre/lib/rt.jar \ 
    java/io/PrintStream "void println(String)" 

संपादित: स्रोत और लाइन नंबर कहा: नोट: यह है कि

उदाहरण के लिए, तरीकों कि System.out.println बुला जा सकता है ("foo") जावा रनटाइम जार में सूचीबद्ध करने के लिए केवल कॉलिंग विधि के अंतिम लक्ष्य विधि आमंत्रण को इंगित करता है - मूल क्यू केवल जानना चाहता था जो विधियां। मैं इसे पाठक के लिए कॉलिंग विधि घोषणा की लाइन संख्या दिखाने के लिए, या प्रत्येक लक्ष्य आमंत्रण की रेखा संख्या दिखाने के लिए एक अभ्यास के रूप में छोड़ देता हूं, जो वास्तव में आप वास्तव में क्या कर रहे हैं उसके आधार पर। :) में

परिणाम:

LogSupport.java:44 com/sun/activation/registries/LogSupport log (Ljava/lang/String;)V 
LogSupport.java:50 com/sun/activation/registries/LogSupport log (Ljava/lang/String;Ljava/lang/Throwable;)V 
... 
Throwable.java:498 java/lang/Throwable printStackTraceAsCause (Ljava/io/PrintStream;[Ljava/lang/StackTraceElement;)V 
-- 
885 methods invoke java/io/PrintStream println (Ljava/lang/String;)V 

स्रोत:

public class App { 
    private String targetClass; 
    private Method targetMethod; 

    private AppClassVisitor cv; 

    private ArrayList<Callee> callees = new ArrayList<Callee>(); 

    private static class Callee { 
     String className; 
     String methodName; 
     String methodDesc; 
     String source; 
     int line; 

     public Callee(String cName, String mName, String mDesc, String src, int ln) { 
      className = cName; methodName = mName; methodDesc = mDesc; source = src; line = ln; 
     } 
    } 

    private class AppMethodVisitor extends MethodAdapter { 

     boolean callsTarget; 
     int line; 

     public AppMethodVisitor() { super(new EmptyVisitor()); } 

     public void visitMethodInsn(int opcode, String owner, String name, String desc) { 
      if (owner.equals(targetClass) 
        && name.equals(targetMethod.getName()) 
        && desc.equals(targetMethod.getDescriptor())) { 
       callsTarget = true; 
      } 
     } 

     public void visitCode() { 
      callsTarget = false; 
     } 

     public void visitLineNumber(int line, Label start) { 
      this.line = line; 
     } 

     public void visitEnd() { 
      if (callsTarget) 
       callees.add(new Callee(cv.className, cv.methodName, cv.methodDesc, 
         cv.source, line)); 
     } 
    } 

    private class AppClassVisitor extends ClassAdapter { 

     private AppMethodVisitor mv = new AppMethodVisitor(); 

     public String source; 
     public String className; 
     public String methodName; 
     public String methodDesc; 

     public AppClassVisitor() { super(new EmptyVisitor()); } 

     public void visit(int version, int access, String name, 
          String signature, String superName, String[] interfaces) { 
      className = name; 
     } 

     public void visitSource(String source, String debug) { 
      this.source = source; 
     } 

     public MethodVisitor visitMethod(int access, String name, 
             String desc, String signature, 
             String[] exceptions) { 
      methodName = name; 
      methodDesc = desc; 

      return mv; 
     } 
    } 


    public void findCallingMethodsInJar(String jarPath, String targetClass, 
             String targetMethodDeclaration) throws Exception { 

     this.targetClass = targetClass; 
     this.targetMethod = Method.getMethod(targetMethodDeclaration); 

     this.cv = new AppClassVisitor(); 

     JarFile jarFile = new JarFile(jarPath); 
     Enumeration<JarEntry> entries = jarFile.entries(); 

     while (entries.hasMoreElements()) { 
      JarEntry entry = entries.nextElement(); 

      if (entry.getName().endsWith(".class")) { 
       InputStream stream = new BufferedInputStream(jarFile.getInputStream(entry), 1024); 
       ClassReader reader = new ClassReader(stream); 

       reader.accept(cv, 0); 

       stream.close(); 
      } 
     } 
    } 


    public static void main(String[] args) { 
     try { 
      App app = new App(); 

      app.findCallingMethodsInJar(args[0], args[1], args[2]); 

      for (Callee c : app.callees) { 
       System.out.println(c.source+":"+c.line+" "+c.className+" "+c.methodName+" "+c.methodDesc); 
      } 

      System.out.println("--\n"+app.callees.size()+" methods invoke "+ 
        app.targetClass+" "+ 
        app.targetMethod.getName()+" "+app.targetMethod.getDescriptor()); 
     } catch(Exception x) { 
      x.printStackTrace(); 
     } 
    } 

} 
+1

यह वही है जो मैं ढूंढ रहा हूं। क्या विधियों की स्रोत रेखा को खोजने का कोई तरीका है? – arthur

+0

जार में डीबग जानकारी के साथ, आप विज़िटसोर्स और विज़िटलाइनइन विधियों को देखेंगे (सुनिश्चित करें कि स्वीकृति कॉल में DEBUG जानकारी को अक्षम न करें, जैसा कि मैंने मूल रूप से किया था)। निश्चित नहीं है कि स्रोत का पूरा पथ क्यों गुम है, यह एक कंपाइलर समस्या हो सकती है, या शायद इसके लिए एक टिप्पणी हो सकती है। ध्यान दें कि यह केवल प्रति विधि अंतिम लक्ष्य विधि आमंत्रण दिखाता है - आपका मूल क्यू केवल जानना चाहता था कि कौन सी विधियां जानी चाहिए। मामूली प्रयास विधि घोषणा की लाइन संख्या दिखाएगा यदि आप इसके बाद क्या कर रहे हैं। – Chadwick

+0

यह कोड केवल प्रत्येक कॉलिंग विधि के लिए एक कॉल देता है; यह शायद मूल रूप से इरादा था, लेकिन लाइन संख्याओं के अतिरिक्त, यह अब एक बग की तरह दिखता है ... – daphshez

11

संपादित करें: मूल प्रश्न को रनटाइम समाधान की आवश्यकता के संकेत के लिए संपादित किया गया था - यह उत्तर उस संपादन से पहले दिया गया था और केवल यह दर्शाता है कि विकास के दौरान इसे कैसे किया जाए।

यदि आप ग्रहण का उपयोग कर रहे हैं तो आप विधि को राइट क्लिक कर सकते हैं और इस जानकारी को प्राप्त करने के लिए "ओपन कॉल पदानुक्रम" चुन सकते हैं।

टिप्पणियों को पढ़ने के बाद अपडेट किया गया: अन्य IDEs इसी तरह से इस समर्थन के रूप में अच्छी तरह से (कम से कम Netbeans और इंटेलीजे पर करते हैं)

+0

मुझे सही नाम याद नहीं है, लेकिन नेटबीन में यह काफी वही बात है। –

+0

अधिकांश आईडीई इसका समर्थन करते हैं। IntelliJ भी इसका समर्थन करता है। –

+0

धन्यवाद, मैं अपना जवाब अपडेट करूंगा। –

1

हाँ, सबसे आधुनिक आईडीई: रों आप एक विधि या चर के उपयोगों के लिए खोज या तो दूँगी । वैकल्पिक रूप से, आप एक डीबगर का उपयोग कर सकते हैं और विधि प्रविष्टि पर एक ट्रेस पॉइंट सेट कर सकते हैं, एक स्टैक ट्रेस प्रिंट कर सकते हैं या जब भी विधि लागू की जाती है। अंत में, आप कुछ सरल खोल util सिर्फ ग्रेप को विधि के लिए, इस तरह के रूप

find . -name '*.java' -exec grep -H methodName {} ; 

एकमात्र तरीका है कि आप कुछ प्रतिबिंब विधि के माध्यम से किया invokations खोजने के दूँगी कि इस्तेमाल कर सकते हैं, हालांकि, डिबगर का उपयोग कर किया जाएगा।

+0

मैं ऐसे * ढूंढ * का उपयोग करता हूं, इसलिए अक्सर मुझे * fij * ("जावा में ढूंढें) और * फिक्स * (एक्सएमएल में खोजें) और * फिक्स * (टेक्स्ट फाइलों में ढूंढें) आदि उपनाम हैं ...ऐसा एक * ढूंढ * एक आईडीई के समान काम नहीं कर रहा है: यह आपको उस स्ट्रिंग और अन्य पैकेजों के तरीकों का उपयोग करके टिप्पणियां भी दिखाएगा जो समान नाम वाले होते हैं, जो एक प्रमुख पिटा है। तो जितना मैं इसे एक बार में उपयोग करता हूं, यह कहीं भी उतना अच्छा नहीं है जितना आईडीई करता है। – SyntaxT3rr0r

0

सबसे नज़दीक जो मुझे मिल सकता था वह था चयनित स्टैक ओवरव्लो प्रश्नों में वर्णित विधि। check this out

-1

आप इसे अपने आईडीई में कुछ कर सकते हैं जैसे "उपयोग ढूंढें" (जिसे नेटबीन्स और जेड डेवलपर में कहा जाता है)। कुछ चीजों को ध्यान में रखना:

  1. यदि आपकी विधि किसी इंटरफ़ेस या बेस क्लास से कोई विधि लागू करती है, तो आप केवल यह जान सकते हैं कि आपकी विधि को संभवतः बुलाया गया है।
  2. बहुत सारे जावा फ्रेमवर्क आपकी विधि (आईई स्प्रिंग, हाइबरनेट, जेएसएफ, आदि) को कॉल करने के लिए प्रतिबिंब का उपयोग करते हैं, इसलिए इसके बारे में सावधान रहें।
  3. उसी नोट पर, आपकी पद्धति को कुछ ढांचे द्वारा प्रतिबिंबित किया जा सकता है, प्रतिबिंबित या नहीं, तो फिर सावधान रहें।
2

जावा प्रतिबिंब पुस्तकालयों के माध्यम से ऐसा करने (प्रोग्रामेटिक रूप से) करने का कोई तरीका नहीं है - आप java.lang.reflect.Method से पूछ नहीं सकते "आप किस तरीके से कॉल करते हैं?"

कि दो अन्य विकल्प मैं के बारे में सोच सकते हैं छोड़ देता है:

  1. स्रोत कोड के स्टेटिक विश्लेषण। मुझे यकीन है कि ग्रहण जावा टूलसेट यह है - आप जेडीटी के पीछे ग्रहण स्रोत को देख सकते हैं, और जब आप ग्रहण से किसी विधि को "संदर्भ खोजें" से पूछते हैं तो यह क्या होता है।

  2. बाइटकोड विश्लेषण। आप विधि के लिए कॉल के लिए बाइटकोड का निरीक्षण कर सकते हैं। मुझे यकीन नहीं है कि इसमें मदद करने के लिए पुस्तकालय या उदाहरण क्या हैं - लेकिन मैं कल्पना नहीं कर सकता कि कुछ अस्तित्व में नहीं है।

4

एन्नोटेट @Deprecated साथ विधि (या @deprecated के साथ टैग), प्रतिवाद चेतावनी पर बारी अपने संकलन चलाने के लिए और देखने के जो चेतावनी शुरू हो जाते हैं।

Java 6 compiler API का उपयोग करके बाहरी संकलन प्रक्रिया या को आमंत्रित करके अपने संकलन बिट को चलाया जा सकता है।

3

ग्रहण में, विधि नाम उजागर और फिर Ctrl + Shift + जी

5
  1. सही पर क्लिक करें विधि
  2. संदर्भों पर जाएं डी (आपकी आवश्यकता के आधार पर)
    वर्कस्पेस/प्रोजेक्ट/पदानुक्रम चुनें।

यह एक पैनल पॉप अप करता है जो इस कार्यों के सभी संदर्भ दिखाता है। ग्रहण एफटीडब्ल्यू!

0

मैंने @ चाडविक के एक का उपयोग करके एक छोटा सा उदाहरण बनाया। यह एक परीक्षण है जो मूल्यांकन करता है कि क्याडेटाइंजिन() प्राप्त करने के लिए कॉल @Transaction को लागू करने वाले तरीकों से किए जाते हैं।

/** 
* Ensures that methods that call {@link DatabaseProvider#getDatabaseEngine()} 
* implement the {@link @Transaction} annotation. 
* 
* @throws Exception If something occurs while testing. 
*/ 
@Test 
public void ensure() throws Exception { 
    final Method method = Method.getMethod(
      DatabaseEngine.class.getCanonicalName() + " getDatabaseEngine()"); 

    final ArrayList<java.lang.reflect.Method> faultyMethods = Lists.newArrayList(); 

    for (Path p : getAllClasses()) { 
     try (InputStream stream = new BufferedInputStream(Files.newInputStream(p))) { 
      ClassReader reader = new ClassReader(stream); 


      reader.accept(new ClassAdapter(new EmptyVisitor()) { 
       @Override 
       public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) { 

        return new MethodAdapter(new EmptyVisitor()) { 
         @Override 
         public void visitMethodInsn(int opcode, String owner, String nameCode, String descCode) { 
          try { 
           final Class<?> klass = Class.forName(Type.getObjectType(owner).getClassName()); 
           if (DatabaseProvider.class.isAssignableFrom(klass) && 
             nameCode.equals(method.getName()) && 
             descCode.equals(method.getDescriptor())) { 

            final java.lang.reflect.Method method = klass.getDeclaredMethod(name, 
              getParameters(desc).toArray(new Class[]{})); 

            for (Annotation annotation : method.getDeclaredAnnotations()) { 
             if (annotation.annotationType().equals(Transaction.class)) { 
              return; 
             } 
            } 

            faultyMethods.add(method); 

           } 
          } catch (Exception e) { 
           Throwables.propagate(e); 
          } 
         } 
        }; 
       } 
      }, 0); 

     } 
    } 

    if (!faultyMethods.isEmpty()) { 
     fail("\n\nThe following methods must implement @Transaction because they're calling getDatabaseEngine().\n\n" + Joiner.on("\n").join 
       (faultyMethods) + "\n\n"); 
    } 

} 

/** 
* Gets all the classes from target. 
* 
* @return The list of classes. 
* @throws IOException If something occurs while collecting those classes. 
*/ 
private List<Path> getAllClasses() throws IOException { 
    final ImmutableList.Builder<Path> builder = new ImmutableList.Builder<>(); 
    Files.walkFileTree(Paths.get("target", "classes"), new SimpleFileVisitor<Path>() { 
     @Override 
     public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { 
      if (file.getFileName().toString().endsWith(".class")) { 
       builder.add(file); 
      } 
      return FileVisitResult.CONTINUE; 
     } 
    }); 

    return builder.build(); 
} 

/** 
* Gets the list of parameters given the description. 
* 
* @param desc The method description. 
* @return The list of parameters. 
* @throws Exception If something occurs getting the parameters. 
*/ 
private List<Class<?>> getParameters(String desc) throws Exception { 
    ImmutableList.Builder<Class<?>> obj = new ImmutableList.Builder<>(); 

    for (Type type : Type.getArgumentTypes(desc)) { 
     obj.add(ClassUtils.getClass(type.getClassName())); 
    } 

    return obj.build(); 
} 
1

1) ग्रहण यह है -> सही विधि पर क्लिक करें और ओपन कॉल पदानुक्रम या CLT+ALT+H

2) का चयन JDeveloper यह है -> सही विधि पर क्लिक करें और कॉल या ALT+SHIFT+H

चयन
संबंधित मुद्दे

 संबंधित मुद्दे