2012-05-09 3 views
6

Ich führe erfolgreich eine C++ - Anwendung aus, die eine JVM mit einer JAR-Datei als Klassenpfadargument lädt. Die Anwendung verwendet dann erfolgreich JNI-Aufrufe zum Ausführen verschiedener Funktionen, die in .class-Dateien in dieser JAR-Datei definiert sind.Dienstladeprogramm findet Dienstanbieterklasse nicht, obwohl Klasse in derselben JAR-Datei wie META-INF/services ist

In der Verzeichnisstruktur der .jar-Datei ist ein Satz von .class-Dateien von Drittanbietern enthalten, die aus jai_imageio.jar zusammengeführt wurden (diese .class-Dateien wurden mit ihrer vollständigen Verzeichnisstruktur in dieser einzelnen .jar-Datei zusammengeführt) Intellij IDEA). In der zusammengeführten .jar-Datei sind auch die Zeilen aus dem Original jai_imageio.jar's manifest.mf - insbesondere implementation-title und verwandte Zeilen enthalten. Außerdem ist der Ordner meta-inf/services vorhanden, der ebenfalls von jai_imageio.jar kopiert wurde. Die verschiedenen im Verzeichnis services aufgeführten Dienste sehen korrekt aus.

Insbesondere javax.imageio.spi.ImageOutputStreamSpi im meta-inf/services Ordner in der .jar-Datei enthält die einzige Zeile com.sun.media.imageioimpl.stream.ChannelImageOutputStreamSpi, und es gibt eine Klasse genau das Verzeichnis diesen innerhalb der .jar-Datei entspricht, die von dieser Linie indicatted: com/sun/media/imageioimpl/stream/ChannelImageOutputStreamSpi.class.

Wenn jedoch die Java-Code die folgende Zeile ausführt:

ImageIO.write(image, "tiff", file); // Assume 'image' is a BufferedImage and 'file' is a File 

... wirft es eine Ausnahme:

java.util.ServiceConfigurationError: javax.imageio.spi.ImageOutputStreamSpi: 
Provider com.sun.media.imageioimpl.stream.ChannelImageOutputStreamSpi not found 

... obwohl diese Klasse ist, die innerhalb der gleiche .jar-Datei, wie oben erwähnt.

Kann jemand bitte erklären, warum dieser Fehler passiert, und was ich tun sollte, um es zu lösen.

+0

Passiert der gleiche Fehler ohne JNI beteiligt (das heißt nur die Methode normalerweise von Java-Code aufrufen):

Dies kann wie getan werden? – artbristol

+0

Ich werde dies testen, wenn es sein muss, aber es wird ein Aufwand sein, weil viele vorherige JNI-Aufrufe (erfolgreich) führen, dass Setup durchführen. Diese verursachen keine Probleme in dem Sinne, dass die Standard-Bildtypen 'jpg',' bmp' und 'png' erfolgreich in das Dateisystem geschrieben werden (vorausgesetzt, die' jai_imageio.class'-Dateien werden nicht zusammengeführt). Wenn nötig, werde ich es einrichten und testen, wie Sie vorschlagen, obwohl ich hoffte, es zu lösen, ohne das zu tun. –

+1

Sollte nicht notwendig sein, um irgendwelche Setup zu tun - Sie können nur eine in sich geschlossene Klasse mit ImageIO.write (Bild, "TIFF", Datei) erstellen, und versuchen Sie, diese Klasse zu starten, mit Ihrem Glas in der Klassenpfad – artbristol

Antwort

2

Aus dieser Dokumentation http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html

„Wenn ein Thread an die VM angeschlossen ist, ist der Kontext-Klassenlader die Bootstraploader.“

Jeder native Thread, der über AttachCurrentThread() mit der JVM verbunden ist, ruft nur den Bootstrap-Klassenlader ab, nicht einmal den Systemklassenlader. Von ServiceLoader referenzierte Klassen sind nur verfügbar, wenn Sie den Kontextklassenlader des neuen Threads explizit reparieren.

java.lang.Thread.currentThread().setContextClassLoader(
    java.lang.ClassLoader.getSystemClassLoader() 
); 
+0

Seltsamerweise wurde dieses wichtige Detail in der aktuellen Version der JNI-Dokumentation weggelassen. – Wheezil

Verwandte Themen