如何使 java ServiceLoader 在 NetBeans 6.9 模块应用程序中工作
我在 NetBeans 模块应用程序中使用 java ServiceLoader 时遇到问题。这是我正在尝试做的事情(它在 Eclipse 中的普通 java 应用程序中工作):
我有一个 interface.jar,它声明了接口。我有implementations.jar,它有这个接口的几个实现,全部在spi/META-INF/services/my.package.name.MyInteface 文件中指定(这个文件位于implementations.jar 中)。
我还有一个类 ImplementHandler(在另一个 handler.jar 中),它具有以下方法来加载所有实现:
private static List<MyInterface<?>> loadAllImplementations() {
List<MyInterface<?>> foundImplementations = Lists.newArrayList();
try {
for (MyInterface implementation : ServiceLoader.load(MyInterface.class)) {
foundImplementations.add(implementation);
}
} catch (ServiceConfigurationError error) {
system.out.println("Exception happened");
}
return foundImplementations;
}
此代码返回 Eclipse 正常应用程序中的所有实现(foundImplementations.size() > 0)。
然而在NetBeans下,它找不到任何东西(foundImplementations.size() == 0)。
更多详细信息:
我有 NetBeans 模块应用程序的源代码(开源,不是我编写的),我需要使用一些 MyInterface 实现来扩展它。 interface.jar、implementations.jar 和 handler.jar 是在 Eclipse 中创建的,它们是另一个应用程序的一部分。
在 NetBeans 中,我打开了需要使用新实现的模块,并将所有 3 个 jar 添加为外部库(NetBeans 将它们复制到其 ext 文件夹中,我不想要该文件夹,但我无能为力 - 我希望它们位于另一个 myext 文件夹中,但那是另一个故事了)。然后我重建了所有内容并尝试使用我的实现之一,但没有找到它...获取实现的代码位于 ImplementHandler 类中,看起来像:
public static final <T> MyInteface<T> getByName(String name) {
for (MyInteface implementation : loadAllImplementations()) {
if (implementation.getName().equals(name)) {
return implementation;
}
}
throw new IllegalArgumentException("Unable to find MyInterface class for: " + name);
}
我得到了异常“无法找到 MyInteface 类:myImplementationName” ...
我对 NetBeans 的了解非常有限,我想知道是否还需要做一些事情才能使其正常工作?
I have troubles using the java ServiceLoader in a NetBeans module application. Here is what I'm trying to do (and it works in a normal java application in Eclipse):
I have an interface.jar, which declares the interface. And I have implementations.jar, which has several implementations of this interface, all specified in the spi/META-INF/services/my.package.name.MyInteface file (this file is in the implemenations.jar).
I also have a class ImplementationHandler (in yet another handler.jar), which has the following method to load all implementations:
private static List<MyInterface<?>> loadAllImplementations() {
List<MyInterface<?>> foundImplementations = Lists.newArrayList();
try {
for (MyInterface implementation : ServiceLoader.load(MyInterface.class)) {
foundImplementations.add(implementation);
}
} catch (ServiceConfigurationError error) {
system.out.println("Exception happened");
}
return foundImplementations;
}
This code returns all implementations in Eclipse normal application (the foundImplementations.size() > 0).
However under NetBeans, it can't find anything (foundImplementations.size() == 0).
More details:
I have the source of a NetBeans module application (open source, not written by me), which I need to extend by using some of MyInterface implementations. The interface.jar, implementations.jar and the handler.jar are created in Eclipse and they are part of another application.
In the NetBeans, I opened the module which needs to use the new impplementations and I added all my 3 jars as external libraries (NetBeans copied them into its ext folder, which I don't want but I can't do anything about - I want them in another myext folder, but that's another story). Then I rebuilt everything and tried to use one of my implementations, but it was not found... The code that gets an implementation is in the ImplementationHandler class and looks like:
public static final <T> MyInteface<T> getByName(String name) {
for (MyInteface implementation : loadAllImplementations()) {
if (implementation.getName().equals(name)) {
return implementation;
}
}
throw new IllegalArgumentException("Unable to find MyInterface class for: " + name);
}
I got my exception "Unable to find MyInteface class for: myImplementationName"...
My knowledge about NetBeans is very limited and I was wondering is there something more that I need to do in order to get this working?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我放弃了,并用 JSPF 替换了 ClassLoader。这是开箱即用的,我不需要了解作为 NetBeans 模块编写的第三方程序的内部结构以及这如何影响提供给类加载器的类路径。
I gave up, and replaced ClassLoader with JSPF. This works out of the box and I don't need to know about the internals of a third party program, written as NetBeans module and how this affects the classpath given to the class loaders.
ServiceLoader.load(Class) 使用当前线程的上下文类加载器来加载所有实现。在您的情况下,您的 jar 文件 (implementation.jar) 中的实现类可能不在该类加载器的类路径中。
您可能必须为此尝试不同的方法:
ServiceLoader.load(Class, ClassLoader)
并传递该类加载器。最有可能的是 handler.jar和implementations.jar不是由同一个类加载器加载的。另外,您可能想看看为什么您的文件会进入 ext 文件夹。
希望这有帮助。
编辑:
ServiceLoader.load(Class, null)
。类加载器可能能够在位于 ext 目录中的 jar 中找到类。The ServiceLoader.load(Class) uses the current thread's context class loader to load all the implementations. It may be that in your case your implementation classes in your jar file (implementation.jar) are not in that class loader's classpath.
You may have to try different approaches for this :
ServiceLoader.load(Class, ClassLoader)
and pass a that classloader.Most likely, the handler.jar and implementations.jar are not loaded by the same class loader. Also you may want to take a look as to why your files are getting to ext folder.
Hope this helps.
Edit:
ServiceLoader.load(Class, null)
which uses the System class loader (the one that started the application). Probably that classloader may be able to find classes in jars located in the ext directory.为了工作,您必须让 Netbeans 在 META-INF 中创建此服务子文件夹。这很容易做到,而且信息也很容易获取。
要向 META-INF 添加内容,您需要在 src/(源目录 [spi?])文件夹中创建一个同名的文件夹。在这种情况下,您还需要 services 文件夹,并在其中创建一个与服务接口具有相同完全限定名称的文本文件。最后你应该有这样的结构:src/META-INF/services/my.package.MyInterface。
最后,这个 [my.package.MyInterface] 文件的内容应该列出所有实现类(每行一个)。
通过此设置,Netbeans 将在构建应用程序时创建适当的 jar。
查看此 ServiceLoader 示例。这是一个完整的示例,尽管它没有解释我刚才描述的 Netbeans 集成。
In order to work, you have to make Netbeans create this services sub folder inside META-INF. It's very easy to do, but the information is easily accessible.
To add something to META-INF, you need to create a folder of this name in your src/ (the source directory [spi?]) folder. In this case you also need the services folder and in it, create a text file with the same fully qualified name as your service interface. In the end you should have this structure: src/META-INF/services/my.package.MyInterface.
Finally, this [my.package.MyInterface] file's content should list all the implementation classes (one per line).
With this setup, Netbeans will create the appropriate jar when building your app.
Take a look at this ServiceLoader example. It's a complete example, although it does not explain the Netbeans integration I just described.