2011-12-01 80 views
8

Tôi đã phát triển một ứng dụng bằng cách sử dụng thư viện Reflections để truy vấn tất cả các lớp có chú thích cụ thể. Mọi thứ đã hoạt động như một nét duyên dáng cho đến khi tôi quyết định tạo một trình cắm thêm Eclipse từ ứng dụng của mình. Sau đó, Reflections ngừng hoạt động.Thư viện phản chiếu không hoạt động khi được sử dụng trong trình cắm thêm Eclipse

Do ứng dụng của tôi hoạt động tốt khi không phải là một phần của trình cắm thêm Eclipse, tôi nghĩ rằng đó phải là một vấn đề của trình tải lớp. Vì vậy, tôi đã thêm vào lớp Reflections lớp trình nạp lớp của trình kích hoạt trình cắm thêm, trình nạp lớp ngữ cảnh và tất cả các trình nạp lớp khác mà tôi có thể tưởng tượng, mà không thành công. Đây là một phiên bản đơn giản của mã của tôi:

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 

Tôi cũng đã cố gắng thêm URL của các lớp tôi muốn tải đến lớp ConfigurationBuilder, nhưng nó đã không giúp đỡ.

Ai đó có thể cho tôi biết nếu có cách nào để làm cho Reflections hoạt động như một phần của trình cắm thêm Eclipse? Hay tôi nên tìm một giải pháp thay thế khác? Cảm ơn rất nhiều, tôi thực sự bối rối về điều đó.

Trả lời

10

Tôi cho rằng bạn đã biết cách tạo nhóm (nếu không, hãy kiểm tra this).

Sau một debuging và thăm dò của Reflections API tôi đã nhận ra rằng vấn đề là Reflections chỉ đơn giản là không đọc OSGi URL (bundleresource: // ...) dẫn đến một ngoại lệ:

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

và điều này gợi ý:

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. 

vì vậy, tôi tin rằng thực hiện một UrlType cho OSGi (ví dụ class BundleUrlType implements UrlType {...}) và đăng ký nó như thế này:

Vfs.addDefaultURLTypes(new BundleUrlType()); 

nên làm cho API phản xạ có thể sử dụng được từ bên trong một gói. Các phụ thuộc phản chiếu nên được thêm vào dự án Plugin Eclipse như được mô tả here.

Đây là cách MANIFEST.MF mẫu của tôi trông giống như sau khi thêm lọ cần thiết:

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 

Lưu ý: Dùng Reflections v 0.9.5

Dưới đây là một việc thực hiện mẫu 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(); 
     } 
    } 
} 

Và đây là cách tôi tạo phản xạ trong lớp Activator:

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

Bit cuối cùng rất khó hiểu, nhưng vẫn quan trọng: nếu bạn chạy plugin bên trong Eclipse (Chạy như/OSGi Framework), bạn phải thêm thư mục đầu ra của lớp vào các mẫu đường dẫn Reflections (tức là "bin" hoặc "target/classes").Mặc dù, nó không cần thiết cho một plugin được phát hành (để xây dựng một plugin/gói làm "Export" -> "Deployable plug-in and fragments").

+0

Cảm ơn bạn đã trả lời @Vlad. Không có ý tưởng làm thế nào để tạo ra bó như vậy nhưng tôi sẽ cố gắng (Tôi xa là một chuyên gia trong OSGi được nêu ra ...). Vì vậy, tôi cần hai bó: 1) thư viện Reflections có "DynamicImport-Package: *" tại MANIFEST Plug-in của nó; 2) một gói với plugin của tôi, nơi tôi phải điền vào danh sách "Gói đã xuất" của trình chỉnh sửa cấu hình plugin, tất cả các gói có thể truy cập được vào Gói phản xạ. Sau đó, tôi đoán tôi nên soạn hai bó này thành một nhóm khác, đúng không? Bạn có thể vui lòng xây dựng thêm một chút câu trả lời của bạn? tất cả điều này có vẻ hơi phức tạp. Cảm ơn – Sergio

+0

@Sergio, tôi đã cập nhật câu trả lời với những phát hiện của tôi (câu trả lời trước đó không cung cấp giải pháp). Thật không may, nó đã xảy ra được ít hơn nhiều về phía trước. Hy vọng, nó sẽ giúp. – Vlad

+0

Cảm ơn bạn rất nhiều vì đã mở rộng câu trả lời của bạn @Vlad. Tôi đã cố gắng thực hiện nó mà không thành công cho đến bây giờ. Nếu tôi hiểu chính xác từ câu trả lời mới của bạn, tôi chỉ cần gói plugin và lọ Reflexions trong classpath nhóm của nó (như tôi ban đầu đã có nó). Vì vậy, tôi bỏ qua câu trả lời trước đây về việc đưa phản xạ vào một gói riêng biệt, điều này có đúng không? Về tệp kê khai của bạn: 'Bundle-ClassPath' của bạn trông giống như của tôi, trong 'Gói xuất của tôi' tôi không có tệp '.data' như bạn và trong 'Gói nhập' tôi không thấy phụ thuộc bạn có, điều quan trọng là Reflexions có hoạt động không? – Sergio

1

Eclipse được xây dựng trên đỉnh OSGi và bạn đang chống lại việc tải lớp OSGi ... và đó không phải là một trận chiến dễ dàng để giành chiến thắng.

Hãy xem bài viết này của Neil Bartlett: OSGi Readiness — Loading Classes. Ngoài ra, bạn có thể google cho "chính sách bạn thân OSGi".

+0

Tôi thấy :(.Tonny, Bạn có biết một thư viện khác để truy vấn loại thông tin này bằng chú thích cụ thể và như vậy trong một phần ứng dụng Theo như tôi biết Spring cũng có thể trả lời các câu hỏi tương tự, nhưng tôi chưa thử nó trước đây, và không biết nó có hoạt động tốt khi làm một phần của một trình cắm thêm của Eclipse hay nó sẽ hiện diện – Sergio

+0

Bạn có thể làm cho thư viện Reflections thành một gói OSGi và sau đó thêm tiêu đề 'DynamicImport-Package: *' vào tệp manifest.mf. Bạn có thể tạo gói ban đầu từ hiện tại tập tin jar bằng cách sử dụng "Dự án mới" -> "Trình cắm thêm từ trình lưu trữ JAR hiện có" ... Chúc may mắn. –

3

Chỉ dành cho các hồ sơ trong trường hợp người khác có cùng vấn đề. Đây là một sửa đổi nhỏ cho câu trả lời của Vlad để tránh phải thêm thư mục đầu ra vào các mẫu đường dẫn Reflections. Sự khác biệt chỉ ở trong lớp BundleDir. Dường như hoạt động tốt trong tất cả các thử nghiệm của tôi:

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

Hôm nay tôi có vấn đề chính xác này, tôi chưa bao giờ tạo nhóm trước đây nhưng đã cố gắng cho việc này. Tôi không hiểu nơi để có được các Bundle Object từ để vượt qua để xây dựng này, bạn có thể giúp đỡ? – Link19

Các vấn đề liên quan