java.lang.UnsatisfiedLinkError: Native Library XXX.so already loaded in another classloader
The problem is with how OpenCV handles the initialization of the native library.
Usually a class that uses a native library will have a static initializer that loads the library. This way the class and the native library will always be loaded in the same class loader. With OpenCV the application code loads the native library.
Now there's the restriction that a native library can only be loaded in one class loader. Web applications use their own class loader so if one web application has loaded a native library, another web application cannot do the same. Therefore code loading native libraries cannot be put in a webapp directory but must be put in the container's (Tomcat) shared directory. When you have a class written with the usual pattern above (loadLibrary
in static initializer of using class) it's enough to put the jar containing the class in the shared directory. With OpenCV and the loadLibrary
call in the web application code however, the native library will still be loaded in the "wrong" class loader and you will get the UnsatisfiedLinkError
.
To make the "right" class loader load the native library you could create a tiny class with a single static method doing only the loadLibrary
. Put this class in an extra jar and put this jar in the shared Tomcat directory. Then in the web applications replace the call to System.loadLibrary
with a call to your new static method. This way the class loaders for the OpenCV classes and their native library will match and the native methods can be initialized.
Edit: example as requested by a commenter
instead of
public class WebApplicationClass {
static {
System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
}
}
use
public class ToolClassInSeparateJarInSharedDirectory {
public static void loadNativeLibrary() {
System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
}
}
public class WebApplicationClass {
static {
ToolClassInSeparateJarInSharedDirectory.loadNativeLibrary();
}
}