Using "META-INF / services" for the driver’s internal plumbing

I am developing a Jaybird JDBC driver, and today I ran into a problem ( JDBC-325 , How to configure Jaybird with hibernate ), due to the way Jaybird loads some of its components and how - in this case - NetBeans restricts class loading.

The problem is how Jaybird loads parts of itself using entries in META-INF/services and the class loader used by NetBeans for the Hibernate wizard explicitly ignores these files (see details below).

I can get around this problem (also) by trying to download a hard list of plugins that are part of the Jaybird implementation, or by moving the definition to another location.

However, I was wondering if it is weird (or wrong) to use META-INF/services for internal purposes like Jaybird?

I also don't understand why NetBeans will exclude META-INF/services loading? Drew's comment seems to indicate that NetBeans used it to fix driver loading errors (see this question ), although I would have thought it would be better for the user to solve this, including all the driver dependencies.

Problem details

Jaybird uses plugins for supported protocols, such as Type 4 protocol, custom open type 4 protocol, built-in (native) Type 2 protocol and native Type 2 client protocol. I also believe that a third party once used it to provide a driver that Translated Oracle syntax to Firebird syntax.

All of 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 actually don’t use ServiceLoader ). For the upcoming version, I also planned to use this for supported encodings of connections and (wired) protocols. This will allow the use of “custom” encoding definitions (for example, expanding supported encodings or using an alternative encoding) or another protocol implementation (for example, for troubleshooting, user protocols, etc.).

Now the actual problem is that the Netbeans Hibernate Mapping Files and POJO wizard from the database uses a custom classloader ( org.netbeans.modules.hibernate.util.CustomClassLoader ), and this classloader ignores the files in META-INF/services . Please note that only this wizard has problems, Netbeans itself can use the driver without problems.

The code is ignored by 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 causes the plugins to not be detected, and the driver has no protocols, which leads to a NullPointerException inside Netbeans, since the connection is not created.

+8
java jdbc netbeans jaybird meta-inf
source share
1 answer

I think the Netbeans team fixed the error was incorrect. Ignoring files in a particular directory for no particular reason is terrible. Mostly in such an important directory as META-INF / services. This is not a security issue or anything like that. They only protect them from other people, poorly written code. They should use a different way to do this. I can only imagine how long someone like you took to find the cause of this problem!

The service provider's API is publicly available for one reason: everyone should use it! This is a great way to make your code less connected and it works great! I use it every time I can, and I suggest everyone use it.

And the Java API explicitly supports adding JDBC drivers using the service provider mechanism:

The DriverManager methods getConnection and getDrivers have been extended to support the Java Standard Edition service provider mechanism. JDBC 4.0 drivers must include the META-INF / services / java.sql.Driver file.

It also indicates that drivers created after JDBC 4.0 (2007) are expected to provide entry through this mechanism.

He does not claim that you should / cannot provide a backup. Other drivers must do this, otherwise they will have the same problem. But they probably do this for other reasons (supporting older versions of the JDBC API).

So, you are doing the right thing, and if supporting this particular use case is important to you, then you will need to save this code as a reserve. Otherwise, remove the code and add some documentation so people can get around it.

+3
source share

All Articles