I am successfully running a C++ application that loads a JVM with a JAR file as a classpath argument. The application then successfully uses JNI calls to execute various functions defined in .class files within this JAR file.
Included in the .jar file's directory structure is a 3rd-party set of .class files - those merged from jai_imageio.jar (these .class files, with their full directory structure, were merged into this single .jar file using Intellij IDEA). Also included in the merged .jar file are the lines from the original jai_imageio.jar's manifest.mf
- in particular implementation-title
and related lines. Also, the meta-inf/services
folder is present, also copied from jai_imageio.jar. The various services listed within the services
directory look correct.
In particular, javax.imageio.spi.ImageOutputStreamSpi
within the meta-inf/services
folder in the .jar file contains the single line com.sun.media.imageioimpl.stream.ChannelImageOutputStreamSpi
, and there is a class corresponding to this within the .jar file at exactly the directory indicatted by that line: com/sun/media/imageioimpl/stream/ChannelImageOutputStreamSpi.class
.
However, when the Java code executes the following line:
ImageIO.write(image, "tiff", file); // Assume 'image' is a BufferedImage and 'file' is a File
... it throws an exception:
java.util.ServiceConfigurationError: javax.imageio.spi.ImageOutputStreamSpi:
Provider com.sun.media.imageioimpl.stream.ChannelImageOutputStreamSpi not found
... even though this class is present within the same .jar file, as noted above.
Can somebody please explain why this error is happening, and what I should do to resolve it.
From this documentation http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html
"When a thread is attached to the VM, the context class loader is the bootstrap loader."
Any native thread attached to the JVM via AttachCurrentThread() gets only the bootstrap class loader, not even the system class loader. Classes referenced by ServiceLoader will not be available unless you explicitly fix up the new thread's context class loader.
This can be done like:
java.lang.Thread.currentThread().setContextClassLoader(
java.lang.ClassLoader.getSystemClassLoader()
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With