8

我开发了 Jaybird JDBC 驱动程序,今天我遇到了一个问题(JDBC-325如何使用休眠配置 Jaybird),该问题与 Jaybird 如何加载其某些组件以及如何(在这种情况下)NetBeans 限制类加载有关。

该问题与 Jaybird 使用条目加载自身部分的方式META-INF/services以及 NetBeans 用于 Hibernate 向导的类加载器显式忽略这些文件有关(请参阅下面的详细信息)。

我可以通过(也)尝试加载作为 Jaybird 实现的一部分的插件的硬编码列表,或者通过将定义移动到不同的位置来解决这个问题。

但是我想知道像 Jaybird 那样用于内部目的是否很奇怪(或错误)META-INF/services

我也不明白为什么 NetBeans 会排除加载META-INF/services? Drew的评论似乎表明 NetBeans 在加载驱动程序时使用它来解决错误(请参阅此问题),尽管我认为用户会更好地解决包括驱动程序的所有依赖项在内的问题。

问题详情

Jaybird 为支持的协议使用插件,例如 Type 4 协议、自定义 Type 4 Open Office 协议、Type 2 嵌入式(本机)协议和 Type 2 本机客户端协议。我还相信第三方曾经使用它来提供将 Oracle 特定语法转换为 Firebird 语法的驱动程序。

所有这些插件都在中列出META-INF/services/org.firebirdsql.gds.impl.GDSFactoryPlugin并以类似于java.util.ServiceLoader(当前 2.2.x 驱动程序仍支持 Java 5,因此我们实际上不使用ServiceLoader)的方式加载。对于即将发布的版本,我还计划将其用于支持的连接编码和(有线)协议定义。这将允许“自定义”编码定义(例如扩展支持的编码,或使用替代编码)或不同的协议实现(例如,用于故障排除、自定义日志记录等)。

现在实际的问题是 Netbeans 向导Hibernate 映射文件和来自数据库的 POJO使用自定义类加载器(org.netbeans.modules.hibernate.util.CustomClassLoader),并且这个类加载器忽略META-INF/services. 请注意,只有这个向导有问题,Netbeans 本身可以毫无问题地使用驱动程序。

代码忽略META-INF/services

@Override
public URL findResource(String name) {
    return name.startsWith("META-INF/services") ? null : super.findResource(name); //NOI18N
}

@Override
public Enumeration<URL> findResources(String name) throws IOException {
    if (name.startsWith("META-INF/services")) { //NOI18N
        return Collections.enumeration(Collections.<URL>emptyList());
    } else {
        return super.findResources(name);
    }
}

这导致没有插件被发现并且驱动程序没有协议,这导致NullPointerException内部 Netbeans,因为没有创建连接。

4

1 回答 1

3

我认为 Netbeans 团队修复该错误是错误的。无缘无故忽略特定目录中的文件是很糟糕的。主要在 META-INF/services 这样一个重要的目录下。这不是安全问题或类似问题。他们只是保护他们免受其他人糟糕的书面代码的影响。他们应该使用其他方式来做到这一点。我只能想象像你这样的人花了多长时间才找到这个问题的原因!

Service Provider API 是公开的,原因之一是:每个人都应该使用它!这是减少代码耦合的好方法,而且效果很好!我每次可以使用它,并建议每个人都使用它。

Java API 显然支持使用 Service Provider 机制添加 JDBC 驱动程序:

DriverManager 方法 getConnection 和 getDrivers 已得到增强,以支持 Java 标准版服务提供者机制。JDBC 4.0 驱动程序必须包含文件 META-INF/services/java.sql.Driver。

这还表明,在 JDBC 4.0 (2007) 之后创建的驱动程序有望通过该机制提供入口。

它没有说明您应该/不能提供后备。其他司机必须这样做,否则他们会遇到同样的问题。但他们这样做可能是出于其他原因(支持旧版本的 JDBC API)。

因此,您正在做正确的事情,如果支持该特定用例对您来说如此重要,那么您将需要将该代码作为后备代码进行维护。否则,删除代码并添加一些文档,以便人们可以解决它。

于 2013-12-24T00:23:20.470 回答