Ich entwickle den Jaybird-JDBC-Treiber, und heute stieß ich auf ein Problem ( JDBC-325 , Konfigurieren von Jaybird mit Hibernate ), das damit zusammenhängt, wie Jaybird einige seiner Komponenten lädt und wie - in diesem Fall - beschränkt NetBeans Classloading.
Das Problem hängt mit der Art und Weise zusammen, wie Jaybird Teile von sich selbst lädt, indem Einträge in META-INF/services
verwendet werden und ein von NetBeans für einen Hibernate-Assistenten verwendeter Klassenlader diese Dateien explizit ignoriert (siehe Details unten).
Ich kann dieses Problem umgehen, indem ich (auch) versuche, eine fest codierte Liste von Plugins zu laden, die Teil der Jaybird-Implementierung sind, oder indem ich die Definition an einen anderen Ort verschiebe.
Allerdings habe ich mich gefragt, ob es seltsam (oder falsch) ist, META-INF/services
für interne Zwecke wie Jaybird zu verwenden?
Ich verstehe auch nicht, warum NetBeans das Laden von META-INF/services
ausschließen würde? Der Kommentar von Drew scheint darauf hinzudeuten, dass NetBeans ihn verwendet hat, um Fehler beim Laden eines Treibers zu beheben (siehe Dieses Problem ), obwohl ich denken würde, dass das vom Benutzer besser gelöst werden würde, einschließlich aller Abhängigkeiten eines Treibers.
Jaybird verwendet Plugins für die unterstützten Protokolle, z. B. das Type 4-Protokoll, ein benutzerdefiniertes Open-Office-Protokoll vom Typ 4, das eingebettete (native) Typ 2-Protokoll und das native Typ-2-Clientprotokoll. Ich glaube auch, dass eine dritte Partei es einmal verwendet hat, um einen Treiber bereitzustellen, der Oracle-spezifische Syntax in Firebird-Syntax übersetzt.
Alle diese Plugins sind in META-INF/services/org.firebirdsql.gds.impl.GDSFactoryPlugin
aufgelistet und werden ähnlich wie java.util.ServiceLoader
(die aktuellen 2.2.x-Treiber unterstützen immer noch Java 5, daher verwenden wir nicht ServiceLoader
). Für die kommende Version plante ich, dies für die unterstützten Verbindungscodierungen und (Draht-) Protokolldefinitionen zu verwenden. Dies würde "benutzerdefinierte" Codierungsdefinitionen ermöglichen (z. B. die unterstützten Codierungen erweitern oder eine alternative Codierung verwenden) oder eine andere Protokollimplementierung (z. B. zur Fehlerbehebung, benutzerdefinierte Protokollierung usw.).
Nun besteht das eigentliche Problem darin, dass der Netbeans-Assistent Hibernate Mapping von Dateien und POJOs aus der Datenbank einen benutzerdefinierten Classloader ( org.netbeans.modules.hibernate.util.CustomClassLoader
) verwendet und dieser Classloader Dateien in META-INF/services
ignoriert. Beachten Sie, dass nur dieser Assistent Probleme hat, Netbeans selbst kann den Treiber ohne Probleme verwenden.
Code ignoriert META-INF/services
:
Dies führt dazu, dass keine Plugins entdeckt werden und der Treiber keine Protokolle hat, was zu einem NullPointerException
in Netbeans führt, da keine Verbindung erstellt wird.
Ich denke, dass das Netbeans-Team Fehler behoben hat. Das Ignorieren von Dateien in einem bestimmten Verzeichnis ohne besonderen Grund ist schrecklich. Hauptsächlich in einem so wichtigen Verzeichnis wie META-INF / services. Es ist kein Sicherheitsproblem oder ähnliches. Sie schützen sie nur vor schlecht geschriebenen Codes anderer Leute. Sie sollten einen anderen Weg nehmen, um das zu tun. Ich kann mir nur vorstellen, wie lange jemand wie du gebraucht hat, um die Ursache für dieses Problem zu finden!
Die Service Provider-API ist aus einem einzigen Grund öffentlich: Jeder sollte sie verwenden! Es ist eine gute Möglichkeit, Ihren Code weniger gekoppelt zu machen und es funktioniert großartig! Ich benutze es jedes Mal, wenn ich kann und schlage jedem vor, es zu benutzen.
Und die Java-API unterstützt eindeutig das Hinzufügen von JDBC-Treibern mithilfe des Service Provider-Mechanismus:
Die DriverManager-Methoden getConnection und getDrivers wurden erweitert, um den Service Provider-Mechanismus von Java Standard Edition zu unterstützen. JDBC 4.0 Treiber müssen die Datei META-INF / services / java.sql.Driver enthalten.
Das besagt auch, dass Treiber, die nach JDBC 4.0 (2007) erstellt wurden, erwartet sind, um einen Zugang durch diesen Mechanismus zu ermöglichen.
Es besagt jedoch nicht, dass Sie einen Fallback bereitstellen sollten / können. Andere Treiber müssen das tun, sonst hätten sie das gleiche Problem. Aber das tun sie wahrscheinlich aus anderen Gründen (unterstützt ältere Versionen der JDBC-API).
Sie machen also das Richtige, und wenn Sie diesen speziellen Anwendungsfall so wichtig für Sie unterstützen möchten, müssen Sie diesen Code als Fallback beibehalten. Andernfalls entfernen Sie den Code und fügen Sie einige Dokumentation hinzu, damit die Leute umgehen können.