java - 在 Eclipse 插件中使用时反射库不起作用

标签 java eclipse reflection eclipse-plugin classloader

我已经使用 Reflections 开发了一个应用程序用于查询具有特定注释的所有类的库。在我决定从我的应用程序中创建一个 Eclipse 插件之前,一切都非常顺利。然后反射停止工作。

鉴于我的应用程序在不属于 Eclipse 插件的情况下工作正常,我认为这应该是类加载器问题。 因此,我向我的 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

我还尝试将要加载的类的 URL 添加到 ConfigurationBuilder 类中,但没有帮助。

有人能告诉我是否有办法让 Reflections 作为 Eclipse 插件的一部分工作?还是我应该寻找另一种选择?。非常感谢,我真的很困惑。

最佳答案

我假设您已经知道如何创建 bundle (否则,检查 this )。

在对 Reflections API 进行一些调试和探索之后,我意识到问题在于 Reflections 根本无法读取 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());

应该使 Reflections API 可以在包内使用。应将反射依赖项添加到 Eclipse 插件项目中,如所述 here .

这是我的示例 MANIFEST.MF 在添加所需的 jars 后的样子:

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

注意:使用 Reflections v. 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();
        }
    }
}

这就是我在 Activator 类中创建反射的方式:

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

最后一点非常令人困惑,但仍然很重要:如果你在 Eclipse 中运行你的插件(Run As/OSGi Framework),你还必须将你的类输出目录添加到 Reflections 路径模式(即“bin”或“目标/类”)。虽然,发布的插件不需要它(构建插件/ bundle 执行“导出”->“可部署的插件和片段”)。

关于java - 在 Eclipse 插件中使用时反射库不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8339845/

相关文章:

c# - Reflection.Emit 和 Parallel.ForEach

java - 如何在静态方法中实例化非静态内部类?

java - 如何遍历成对的数组列表以检索指定键的值?

java - 添加 tabitem 到 Eclipse RCP 的搜索对话框

java - 如果用户向左或向右按​​太多,则应用程序为 FC

c# - 从 C# 程序集或项目生成类图或方法表的免费工具?

java - 验证 Java 中反射方法的返回类型和参数

java - 创建可执行 jar 文件

java - 访问 WEB-INF 文件夹中子文件夹中的 JSP?

android - Android XML 编辑器和 Eclipse 的问题...难以手动编辑 XML