I develop the Jaybird JDBC driver, and today I came across an issue (JDBC-325, How to configure Jaybird with hibernate) that is related to how Jaybird loads some of its components and how - in this case - NetBeans restricts classloading.
The issue is related to the way Jaybird loads parts of itself using entries in META-INF/services
and the that a classloader used by NetBeans for a Hibernate wizard explicitly ignores those files (see details below).
I can workaround this issue by (also) attempting to load a hardcoded list of plugins that are part of the Jaybird implementation, or by moving the definition to a different location.
However I was wondering if it is weird (or wrong) to use META-INF/services
for internal purposes like Jaybird does?
I also don't understand why would NetBeans would exclude loading of META-INF/services
? The comment by Drew seems to indicate NetBeans used it to solve errors when loading a driver (see this issue), although I would think that would be better solved by the user including all dependencies of a driver.
Details of the problem
Jaybird uses plugins for the supported protocols, for example the Type 4 protocol, a custom Type 4 Open Office protocol, the Type 2 embedded (native) protocol and the Type 2 native client protocol. I also believe a third party once used it to provide a driver that translated Oracle specific syntax to Firebird syntax.
All these plugins are listed in META-INF/services/org.firebirdsql.gds.impl.GDSFactoryPlugin
and are loaded in a way that is similar to java.util.ServiceLoader
(current 2.2.x drivers still support Java 5 so we don't actually use ServiceLoader
). For the upcoming version I was also planning to use this for the supported connection encodings and (wire) protocol definitions. This would allow for 'custom' encoding definitions (eg extend the supported encodings, or use an alternate encoding) or different protocol implementation (eg for troubleshooting, custom logging etc).
Now the actual problem is that the Netbeans wizard Hibernate Mapping Files and POJOs from Database uses a custom classloader (org.netbeans.modules.hibernate.util.CustomClassLoader
), and this classloader ignores files in META-INF/services
. Note that it is only this Wizard that has issues, Netbeans itself can use the driver without problems.
Code ignoring 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);
}
}
This results in no plugins being discovered and the driver has no protocols, which leads to a NullPointerException
inside Netbeans because no connection is created.
META-INF/services
is the standard way to do this. Also I want to switch to the standardjava.util.ServiceLoader
to load these classes instead of the own implementation Jaybird had for compatibility with Java 5 and older, andServiceLoader
only loads things fromMETA-INF/services
. For now I have simply added a fallback mechanism which loads the default list if none were loaded using the services definition. – Undergo