2011-12-01 15 views
8

में उपयोग किए जाने पर काम नहीं कर रहा है मैंने एक विशेष एनोटेशन वाले सभी वर्गों की पूछताछ के लिए Reflections लाइब्रेरी का उपयोग करके एक एप्लिकेशन विकसित किया है। सब कुछ एक आकर्षण की तरह काम कर रहा था जब तक कि मैंने अपने आवेदन से ग्रहण प्लग-इन बनाने का फैसला नहीं किया। फिर प्रतिबिंब काम करना बंद करो।प्रतिबिंब पुस्तकालय एक ग्रहण प्लग-इन

यह देखते हुए कि मेरा आवेदन ठीक से काम कर रहा है जब ग्रहण प्लग-इन का हिस्सा नहीं है, मुझे लगता है कि यह एक क्लास लोडर समस्या होनी चाहिए। इसलिए मैंने अपने Reflections में प्लग-इन एक्टिवेटर क्लास के क्लासलोडर, संदर्भ क्लास लोडर और अन्य सभी क्लास लोडर्स को बिना किसी सफलता के कल्पना की। यह मेरा कोड का एक सरलीकृत संस्करण है:

ConfigurationBuilder config = new ConfigurationBuilder(); 
config.addClassLoaders(thePluginActivatorClassLoader); 
config.addClassLoaders(ClasspathHelper.getContextClassLoader()); 
config.addClassLoaders("all the classloaders I could imagine"); 
config.filterInputsBy(new FilterBuilder().include("package I want to analyze")); 

Reflections reflections = new Reflections(config); 
Set<Class<?>> classes = reflections.getTypesAnnotatedWith(MyAnnotation.class); //this Set is empty 

मैं भी कक्षाएं मैं ConfigurationBuilder वर्ग के लिए लोड करना चाहते हैं का URL जोड़ने की कोशिश की है, लेकिन यह मदद नहीं की।

क्या कोई मुझे बता सकता है कि Reflections ईक्लीप्स प्लग-इन के हिस्से के रूप में काम करने का कोई तरीका है या नहीं, या क्या मुझे बेहतर विकल्प चाहिए? बहुत बहुत धन्यवाद, मैं वास्तव में इसके बारे में परेशान हूँ।

उत्तर

10

मुझे लगता है कि आप पहले ही जानते हैं कि बंडल कैसे बनाएं (अन्यथा, this देखें)।

कुछ debuging और कुछ विचार एपीआई के अन्वेषण के बाद मैंने महसूस किया है कि समस्या यह है कि कुछ विचार बस OSGi URL पढ़ने में विफल हो जाता है (bundleresource: // ...) एक अपवाद है, जिसके परिणामस्वरूप:

org.reflections.ReflectionsException: could not create Vfs.Dir from url, 
no matching UrlType was found [bundleresource://1009.fwk651584550/] 

और इस सुझाव:

either use fromURL(final URL url, final List<UrlType> urlTypes) 
or use the static setDefaultURLTypes(final List<UrlType> urlTypes) 
or addDefaultURLTypes(UrlType urlType) with your specialized UrlType. 

तो मैं OSGi के लिए एक UrlType को लागू करने का मानना ​​है (उदाहरण के लिए class BundleUrlType implements UrlType {...}) और इस तरह यह दर्ज की:

Vfs.addDefaultURLTypes(new BundleUrlType()); 

प्रतिबिंब एपीआई को बंडल के अंदर से उपयोग करने योग्य बनाना चाहिए। here वर्णित अनुसार प्रतिबिंब निर्भरता ग्रहण प्लगइन परियोजना में प्रतिबिंब निर्भरताओं को जोड़ा जाना चाहिए।

Manifest-Version: 1.0 
Bundle-ManifestVersion: 2 
Bundle-Name: ReflectivePlugin 
Bundle-SymbolicName: ReflectivePlugin 
Bundle-Version: 1.0.0.qualifier 
Bundle-Activator: reflectiveplugin.Activator 
Bundle-ActivationPolicy: lazy 
Bundle-RequiredExecutionEnvironment: JavaSE-1.6 
Import-Package: javax.annotation;version="1.0.0", 
org.osgi.framework;version="1.3.0", 
org.osgi.service.log;version="1.3", 
org.osgi.util.tracker;version="1.3.1" 
Bundle-ClassPath: ., 
lib/dom4j-1.6.1.jar, 
lib/guava-r08.jar, 
lib/javassist-3.12.1.GA.jar, 
lib/reflections-0.9.5.jar, 
lib/slf4j-api-1.6.1.jar, 
lib/xml-apis-1.0.b2.jar 
Export-Package: reflectiveplugin, 
reflectiveplugin.data 

नोट::

यह कैसे मेरे नमूना MANIFEST.MF जरूरत जार जोड़ने के बाद की तरह दिखाई देता है प्रयुक्त कुछ विचार वी 0.9.5

यहां नमूने UrlType कार्यान्वयन है:।

package reflectiveplugin; 

import java.io.IOException; 
import java.io.InputStream; 
import java.net.URL; 
import java.util.Enumeration; 
import java.util.Iterator; 

import org.osgi.framework.Bundle; 
import org.reflections.vfs.Vfs; 
import org.reflections.vfs.Vfs.Dir; 
import org.reflections.vfs.Vfs.File; 
import org.reflections.vfs.Vfs.UrlType; 

import com.google.common.collect.AbstractIterator; 

public class BundleUrlType implements UrlType { 

    public static final String BUNDLE_PROTOCOL = "bundleresource"; 

    private final Bundle bundle; 

    public BundleUrlType(Bundle bundle) { 
     this.bundle = bundle; 
    } 

    @Override 
    public boolean matches(URL url) { 
     return BUNDLE_PROTOCOL.equals(url.getProtocol()); 
    } 

    @Override 
    public Dir createDir(URL url) { 
     return new BundleDir(bundle, url); 
    } 

    public class BundleDir implements Dir { 

     private String path; 
     private final Bundle bundle; 

     public BundleDir(Bundle bundle, URL url) { 
      this(bundle, url.getPath()); 
     } 

     public BundleDir(Bundle bundle, String p) { 
      this.bundle = bundle; 
      this.path = p; 
      if (path.startsWith(BUNDLE_PROTOCOL + ":")) { 
       path = path.substring((BUNDLE_PROTOCOL + ":").length()); 
      } 
     } 

     @Override 
     public String getPath() { 
      return path; 
     } 

     @Override 
     public Iterable<File> getFiles() { 
      return new Iterable<Vfs.File>() { 
       public Iterator<Vfs.File> iterator() { 
        return new AbstractIterator<Vfs.File>() { 
         final Enumeration<URL> entries = bundle.findEntries(path, "*.class", true); 

         protected Vfs.File computeNext() { 
          return entries.hasMoreElements() ? new BundleFile(BundleDir.this, entries.nextElement()) : endOfData(); 
         } 
        }; 
       } 
      }; 
     } 

     @Override 
     public void close() { } 
    } 

    public class BundleFile implements File { 

     private final BundleDir dir; 
     private final String name; 
     private final URL url; 

     public BundleFile(BundleDir dir, URL url) { 
      this.dir = dir; 
      this.url = url; 
      String path = url.getFile(); 
      this.name = path.substring(path.lastIndexOf("/") + 1); 
     } 

     @Override 
     public String getName() { 
      return name; 
     } 

     @Override 
     public String getRelativePath() { 
      return getFullPath().substring(dir.getPath().length()); 
     } 

     @Override 
     public String getFullPath() { 
      return url.getFile(); 
     } 

     @Override 
     public InputStream openInputStream() throws IOException { 
      return url.openStream(); 
     } 
    } 
} 

और इस तरह मैं एक्टिवेटर कक्षा में प्रतिबिंब बना देता हूं:

private Reflections createReflections(Bundle bundle) { 
    Vfs.addDefaultURLTypes(new BundleUrlType(bundle)); 
    Reflections reflections = new Reflections(new Object[] { "reflectiveplugin.data" }); 
    return reflections; 
} 

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

+0

आपके लिए धन्यवाद उत्तर @Vlad। इस तरह के बंडलों को बनाने का कोई विचार नहीं है, लेकिन मैं कोशिश करूंगा (मैं अभी तक ओएसजीआई में एक विशेषज्ञ होने से दूर हूं ...)। इसलिए मुझे दो बंडलों की आवश्यकता है: 1) रिफ्लेक्शन लाइब्रेरी में "डायनामिक इंपोर्ट-पैकेज: *" प्लग-इन मैनिफ़ेस्ट पर है; 2) मेरी प्लगइन के साथ एक बंडल, जहां मुझे प्लगइन कॉन्फ़िगरेशन एडिटर के "निर्यात किए गए पैकेज" सूची में भरना होगा, सभी संकुल जो रिफ्लेक्सन बंडल तक पहुंच योग्य होना चाहिए। तो मुझे लगता है कि मुझे इन दो बंडलों को किसी अन्य में लिखना चाहिए, है ना? क्या आप कृपया अपना उत्तर थोड़ा और विस्तारित कर सकते हैं? यह सब थोड़ा जटिल लगता है! धन्यवाद – Sergio

+0

@ सर्जीओ, मैंने अपने निष्कर्षों के साथ जवाब अपडेट किया है (पिछला जवाब समाधान प्रदान नहीं किया था)। दुर्भाग्यवश, यह बहुत कम सीधे आगे हुआ। उम्मीद है, यह मदद करेगा। – Vlad

+0

आपका उत्तर @Vlad का विस्तार करने के लिए बहुत बहुत धन्यवाद। मैंने अब तक सफलता के बिना इसे लागू करने की कोशिश की है। अगर मैं आपके नए उत्तर से सही ढंग से समझ गया, तो मुझे अपने बंडल क्लासपाथ में केवल प्लगइन बंडल और रिफ्लेक्सन जार की आवश्यकता है (जैसा कि मैंने मूल रूप से किया था)। तो मैं एक अलग बंडल में रिफ्लेक्सियंस डालने के बारे में पिछले जवाब को अनदेखा कर रहा हूं, क्या यह सही है? आपकी मेनिफेस्ट फ़ाइल के बारे में: आपका 'बंडल-क्लासपाथ' मेरे जैसा दिखता है, मेरे 'निर्यात-पैकेज' में मेरे पास '.डेटा' फ़ाइल नहीं है, और 'आयात-पैकेज' में मुझे निर्भरता दिखाई नहीं देती है आपके पास है, क्या रिफ्लेक्सन के लिए काम करना महत्वपूर्ण है? – Sergio

1

ग्रहण ओएसजीआई के शीर्ष पर बनाया गया है और आप ओएसजीआई कक्षा लोडिंग के खिलाफ हैं ... और यह जीतने के लिए एक आसान लड़ाई नहीं है।

नील बार्टलेट के इस आलेख पर एक नज़र डालें: OSGi Readiness — Loading Classes। इसके अलावा आप "ओएसजीआई दोस्त नीति" के लिए Google भी कर सकते हैं।

+0

मैं देख रहा हूँ :(@Tonny, आप इस प्रकार की जानकारी क्वेरी करने के लिए एक और पुस्तकालय जानते हैं आवेदन देने से भाग में एक विशेष टिप्पणी के साथ -कक्षाएं और इतने ऑन एक ग्रहण प्लग-इन का? जहां तक ​​मुझे पता है कि वसंत भी इसी तरह के सवालों का जवाब दे सकता है, लेकिन मैंने पहले यह कोशिश नहीं की है, और कोई विचार नहीं है कि ग्रहण प्लग-इन का हिस्सा बनाते समय यह ठीक काम करेगा या यदि यह उपस्थित होगा मेरे पास वर्तमान में वही समस्याएं हैं। आपकी प्रतिक्रिया के लिए धन्यवाद! – Sergio

+0

आप प्रतिबिंब पुस्तकालय को ओएसजीआई बंडल में बना सकते हैं और फिर 'डायनेमिक आयात-पैकेज: *' को manifest.mf पर शीर्षक जोड़ सकते हैं। आप प्रारंभिक बंडल को मौजूदा से बना सकते हैं "नई परियोजना" -> "मौजूदा जेएआर पुरालेख से प्लग-इन" विज़ार्ड का उपयोग कर जार फ़ाइल ... शुभकामनाएं। –

3

किसी और के पास एक ही समस्या होने पर रिकॉर्ड के लिए बस। प्रतिबिंब पथ पैटर्न में आउटपुट निर्देशिका जोड़ने से बचने के लिए Vlad के उत्तर में एक छोटा सा संशोधन। अंतर केवल बंडलडियर कक्षा में है। यह मेरी सभी परीक्षणों में अच्छा काम करने लगता है:।

public class BundleUrlType implements UrlType { 

public static final String BUNDLE_PROTOCOL = "bundleresource"; 

private final Bundle bundle; 

public BundleUrlType(Bundle bundle) { 
    this.bundle = bundle; 
} 

@Override 
public Dir createDir(URL url) { 
    return new BundleDir(bundle, url); 
} 

@Override 
public boolean matches(URL url) { 
    return BUNDLE_PROTOCOL.equals(url.getProtocol()); 
} 


public static class BundleDir implements Dir { 

    private String path; 
    private final Bundle bundle; 

    private static String urlPath(Bundle bundle, URL url) { 
     try { 
      URL resolvedURL = FileLocator.resolve(url); 
      String resolvedURLAsfile = resolvedURL.getFile(); 

      URL bundleRootURL = bundle.getEntry("/"); 
      URL resolvedBundleRootURL = FileLocator.resolve(bundleRootURL); 
      String resolvedBundleRootURLAsfile = resolvedBundleRootURL.getFile(); 
      return("/"+resolvedURLAsfile.substring(resolvedBundleRootURLAsfile.length())); 
     } catch (IOException e) { 
      throw new RuntimeException(e); 
     } 
    } 

    public BundleDir(Bundle bundle, URL url) { 
     //this(bundle, url.getPath()); 
     this(bundle, urlPath(bundle,url)); 
    } 

    public BundleDir(Bundle bundle, String p) { 
     this.bundle = bundle; 
     this.path = p; 
     if (path.startsWith(BUNDLE_PROTOCOL + ":")) { 
      path = path.substring((BUNDLE_PROTOCOL + ":").length()); 
     } 
    } 

    @Override 
    public String getPath() { 
     return path; 
    } 

    @Override 
    public Iterable<File> getFiles() { 
     return new Iterable<Vfs.File>() { 
      public Iterator<Vfs.File> iterator() { 
       return new AbstractIterator<Vfs.File>() { 
        final Enumeration<URL> entries = bundle.findEntries(path, "*.class", true); 

        protected Vfs.File computeNext() { 
         return entries.hasMoreElements() ? new BundleFile(BundleDir.this, entries.nextElement()) : endOfData(); 
        } 
       }; 
      } 
     }; 
    } 

    @Override 
    public void close() { } 
} 


public static class BundleFile implements File { 

    private final BundleDir dir; 
    private final String name; 
    private final URL url; 

    public BundleFile(BundleDir dir, URL url) { 
     this.dir = dir; 
     this.url = url; 
     String path = url.getFile(); 
     this.name = path.substring(path.lastIndexOf("/") + 1); 
    } 

    @Override 
    public String getName() { 
     return name; 
    } 

    @Override 
    public String getRelativePath() { 
     return getFullPath().substring(dir.getPath().length()); 
    } 

    @Override 
    public String getFullPath() { 
     return url.getFile(); 
    } 

    @Override 
    public InputStream openInputStream() throws IOException { 
     return url.openStream(); 
    } 
} 
} 
+0

मुझे आज यह सटीक मुद्दा है, मैंने पहले कभी बंडल नहीं बनाया है लेकिन इसके लिए प्रयास किया है। मुझे समझ में नहीं आता कि बंडल ऑब्जेक्ट को इस कन्स्ट्रक्टर में पास करने के लिए कहां से प्राप्त किया जाए, क्या आप मदद कर सकते हैं? – Link19