2010-10-02 10 views
5

मैं रनटाइम पर उपलब्ध कक्षाओं की एक सूची प्राप्त करना चाहता हूं और यह एक साधारण नाम से मेल खाता है।एक साधारण नाम से पूरी तरह से योग्य नामों की सूची प्राप्त करना

उदाहरण के लिए:

public List<String> getFQNs(String simpleName) { 
    ... 
} 

// Would return ["java.awt.List","java.util.List"] 
List<String> fqns = getFQNs("List") 

वहाँ एक पुस्तकालय है कि इस कुशलता से करना होगा, या मैं मैन्युअल रूप से प्रत्येक classloader में सभी वर्गों के माध्यम से जाने की क्या ज़रूरत है है? ऐसा करने का सही तरीका क्या होगा?

धन्यवाद!

अद्यतन

एक प्रत्युत्तर मुझसे पूछा क्यों मैं यह कर देना चाहता था। अनिवार्य रूप से, मैं एक ऐसी सुविधा को कार्यान्वित करना चाहता हूं जो "आयात आयात/ऑटो आयात" के समान है, लेकिन रनटाइम पर उपलब्ध है। मुझे कोई फर्क नहीं पड़ता कि समाधान अपेक्षाकृत धीमा है (विशेष रूप से यदि मैं कैश बना सकता हूं तो बाद के प्रश्न तेजी से हो जाते हैं) और यदि यह केवल सर्वोत्तम प्रयास है। उदाहरण के लिए, मुझे कोई फर्क नहीं पड़ता कि मुझे गतिशील रूप से जेनरेट की गई कक्षाएं नहीं मिलती हैं।

अद्यतन 2

मैं अपने खुद के समाधान (नीचे देखें) तैयार करने के लिए किया था: यह अन्य प्रतिसाददाताओं द्वारा प्रदान की कुछ संकेत का उपयोग करता है, लेकिन मुझे लगता है कि यह विभिन्न वातावरण को संभालने के लिए विस्तृत होने की जरूरत है साकार करने के लिए आया था। रनटाइम पर सभी क्लासलोडर्स को स्वचालित रूप से पार करना संभव नहीं है, इसलिए आपको कक्षाओं की उपयोगी सूची प्राप्त करने के लिए सामान्य और डोमेन-विशिष्ट रणनीतियों पर भरोसा करना होगा।

+0

मैं भी यकीन है कि आप कर सकते हैं कि नहीं कर रहा हूँ एक वर्ग लोडर से लोड कक्षाओं की सूची। यह आपकी मदद कर सकता है http://media.techtarget.com/tss/static/articles/content/dm_loadedClasses/executing.pdf –

+1

@ कोलिन: फिर भी, यह आपको कक्षाओं को लोड करने देगा जो क्लास लोडर द्वारा पहले ही लोड हो चुके हैं, लेकिन कक्षाएं नहीं जो "रनटाइम पर उपलब्ध हैं"। AFAIK को यह जानने का कोई तरीका नहीं है कि किसी दिए गए वर्ग को लोड करने का प्रयास किए बिना उपलब्ध है या नहीं। – Grodriguez

+0

@ ग्रोड्रिगेज: आप सही हैं कि जानने का कोई तरीका नहीं है। क्लास लोडर पर विचार करें जो रनटाइम पर बाइटकोड ऑन-द-फ्लाई उत्पन्न करते हैं। –

उत्तर

4

मैंने @Grodriguez और @bemace के उत्तरों को मिश्रित किया और एक सर्वोत्तम प्रयास समाधान के साथ आने के लिए अपनी रणनीति को जोड़ा। यह समाधान संकलन समय पर ऑटो-आयात सुविधा उपलब्ध रनटाइम पर अनुकरण करता है।

my solution is here का पूरा कोड। एक साधारण नाम दिया गया है, मुख्य चरण हैं:

  1. वर्तमान क्लासलोडर से सुलभ पैकेजों की एक सूची प्राप्त करें।
  2. प्रत्येक पैकेज के लिए, पैकेज + सरल नाम से प्राप्त पूर्णतः योग्य नाम लोड करने का प्रयास करें।

चरण 2 आसान है:

public List<String> getFQNs(String simpleName) { 
    if (this.packages == null) { 
     this.packages = getPackages(); 
    } 

    List<String> fqns = new ArrayList<String>(); 
    for (String aPackage : packages) { 
     try { 
      String fqn = aPackage + "." + simpleName; 
      Class.forName(fqn); 
      fqns.add(fqn); 
     } catch (Exception e) { 
      // Ignore 
     } 
    } 
    return fqns; 
} 

चरण 1 कठिन है और आपके आवेदन/पर्यावरण पर निर्भर है तो मैं संकुल की अलग-अलग सूचियां प्राप्त करने के लिए विभिन्न रणनीतियों को लागू करने।

वर्तमान classloader (गतिक रूप से उत्पन्न वर्गों का पता लगाने के उपयोगी हो सकता)

public Collection<String> getPackages() { 
    Set<String> packages = new HashSet<String>(); 
    for (Package aPackage : Package.getPackages()) { 
     packages.add(aPackage.getName()); 
    } 
    return packages; 
} 

क्लासपाथ (आवेदन कि पूरी तरह से लोड किए गए हैं classpath के लिए काफी अच्छा। ग्रहण की तरह जटिल अनुप्रयोगों के लिए अच्छा नहीं)

public Collection<String> getPackages() { 
    String classpath = System.getProperty("java.class.path"); 
    return getPackageFromClassPath(classpath); 
} 

public static Set<String> getPackageFromClassPath(String classpath) { 
    Set<String> packages = new HashSet<String>(); 
    String[] paths = classpath.split(File.pathSeparator); 
    for (String path : paths) { 
     if (path.trim().length() == 0) { 
      continue; 
     } else { 
      File file = new File(path); 
      if (file.exists()) { 
       String childPath = file.getAbsolutePath(); 
       if (childPath.endsWith(".jar")) { 
        packages.addAll(ClasspathPackageProvider 
          .readZipFile(childPath)); 
       } else { 
        packages.addAll(ClasspathPackageProvider 
          .readDirectory(childPath)); 
       } 
      } 
     } 

    } 
    return packages; 
} 

बूटस्ट्रैप classpath (जैसे, java.lang)

public Collection<String> getPackages() { 
    // Even IBM JDKs seem to use this property... 
    String classpath = System.getProperty("sun.boot.class.path"); 
    return ClasspathPackageProvider.getPackageFromClassPath(classpath); 
} 

ग्रहण बंडलों (डोमेन-विशिष्ट पैकेज प्रदाता)

// Don't forget to add "Eclipse-BuddyPolicy: global" to MANIFEST.MF 
public Collection<String> getPackages() { 
    Set<String> packages = new HashSet<String>(); 
    BundleContext context = Activator.getDefault().getBundle() 
      .getBundleContext(); 
    Bundle[] bundles = context.getBundles(); 
    PackageAdmin pAdmin = getPackageAdmin(context); 

    for (Bundle bundle : bundles) { 
     ExportedPackage[] ePackages = pAdmin.getExportedPackages(bundle); 
     if (ePackages != null) { 
      for (ExportedPackage ePackage : ePackages) { 
       packages.add(ePackage.getName()); 
      } 
     } 
    } 

    return packages; 
} 

public PackageAdmin getPackageAdmin(BundleContext context) { 
    ServiceTracker bundleTracker = null; 
    bundleTracker = new ServiceTracker(context, 
      PackageAdmin.class.getName(), null); 
    bundleTracker.open(); 
    return (PackageAdmin) bundleTracker.getService(); 
} 

प्रश्नों और मेरी ग्रहण वातावरण में जवाब के उदाहरण:

  1. फ़ाइल: [java.io.File, org.eclipse.core.internal.resources.File]
  2. सूची: [java.awt.List, org.eclipse.swt.widgets.List, com.sun.xml.internal.bind.v2.schemage n.xmlschema.List, java.util.List, org.hibernate.mapping.List]
  3. IResource: [org.eclipse.core.resources.IResource]
1

आप शायद यह बिल्कुल नहीं कर सकते हैं। JVM को यह जानने का कोई तरीका नहीं है कि कक्षा List एक मनमाने ढंग से नामित पैकेज a.b.c.d में a.b.c.d.List लोड करने का प्रयास किए बिना उपलब्ध है या नहीं। आपको सभी संभावित पैकेज नामों के लिए परीक्षण करने की आवश्यकता होगी।

1

उन्हें लोड के बिना तुम सब classpath संपत्ति मिल सकता है

String class_path = System.getProperty("java.class.path"); 

और फिर आप उन स्थानों में कक्षाओं के लिए फाइल सिस्टम खोज करने के लिए एक समारोह बना सकते हैं। और आपको इसे जार फ़ाइलों के अंदर भी खोजने के लिए कोड करना होगा, और कुछ कक्षाएं वास्तव में असंगतताओं के कारण उपलब्ध हो सकती हैं जो केवल उन्हें लोड होने पर ही प्रकट की जाएंगी। लेकिन अगर आप बस उपलब्ध होने का सबसे अच्छा अनुमान चाहते हैं, तो यह व्यवहार्य हो सकता है। शायद आपको हमें क्यों कहना चाहिए आप ऐसा करना चाहते हैं ताकि आप कुछ वैकल्पिक सुझाव प्राप्त कर सकें?

संपादित करें: ठीक है, लगता है कि आप इस सूत्र और उस में जुड़े हुए लोगों की जांच करनी चाहिए: How do I read all classes from a Java package in the classpath? विशेष रूप से यह वसंत ढांचे प्रकट होता है कुछ इसी तरह, हो सकता है आपको लगता है कि कोड देख सकते हैं: http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/core/io/support/PathMatchingResourcePatternResolver.html