Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UnsatisfiedLinkError in exported (Eclipse) executable jar file

The code works fine when executing from Eclipse. I'm using OpenCV 2.4.11 and JavaFX for UI. When I export an Executable Jar from Eclipse and run it from cmd I get the following exception:

enter image description here

I followed many post here on SO and OpenCV forum(1, 2, 3, 4) but, none of the answers seems to help me.

I have added the OpenCV jar as library and Native Library is linked to /build/java/x64 as suggested in SO answers.

Java Build path

The exception occurs at the System.loadLibrary(Core.Native_Library_Name), I checked the Native_Library_Name and the OpenCV version is same as the one I imported in my project.

public class CustomFrame extends Application{

    @Override
    public void start(Stage primaryStage){
        Group root = new Group();
        Canvas canvas = new Canvas(1440, 840);

        ImageView imageView = new ImageView();
        imageView.setFitHeight(canvas.getHeight());
        imageView.setFitWidth(canvas.getWidth());
        new FrameController().startCamera(imageView);

        root.getChildren().addAll(imageView, canvas);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    public static void main(String[] args)
    {
        // load the native OpenCV library
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        launch(args);
    }
}

If anybody thinks that I have missed something please do let me know.

like image 362
Vivekanand Avatar asked Apr 21 '16 20:04

Vivekanand


3 Answers

The UnsatisfiedLinkError is thrown when an application attempts to load a native library like

  1. .so in Linux,
  2. .dll on Windows or
  3. .dylib in Mac

and that library does not exist.

Specifically, in order to find the required native library, the JVM looks in both the PATH environment variable and the java.library.path system property.

Sometimes if the native library was already loaded by an application and the same application tries to load it again, this can cause this error also.


How to deal with the UnsatisfiedLinkError?

First of all we must verify that the parameter passed in the System.loadLibrary method is correct and that the library actually exists. Notice that the extension of the library is not required. Thus, if your library is named SampleLibrary.dll, you must pass the SampleLibrary value as a parameter.

Moreover, in case the library is already loaded by your application and the application tries to load it again, the UnsatisfiedLinkError will be thrown by the JVM. Also, you must verify that the native library is present either in the java.library.path or in the PATH environment library of your application. If the library still cannot be found, try to provide an absolute path to the System.loadLibrary method.

In order to execute your application, use the -Djava.library.path argument, to explicitly specify the native library. For example, using the terminal (Linux or Mac) or the command prompt (Windows), execute your application by issuing the following command:

java -Djava.library.path= "<path_of_your_application>" –jar <ApplicationJAR.jar>

You have missed the actual command. Use the following

java -Djava.library.path="C:\Opencv2.1.11\opencv\build\java\x64" -jar BlurDetector.jar

or

java -Djava.library.path="C:\Opencv2.1.11\opencv\build\java" -jar BlurDetector.jar

instead of your command

java -Djava.library.path="C:\Users\vivek_elango\Desktop" -jar BlurDetector.jar // you have given wrong path of your application
like image 195
SkyWalker Avatar answered Oct 16 '22 20:10

SkyWalker


It looks like you need to add the path containing the opencv-2411 native libraries to the -Djava.library.path when running from the command prompt.

So something like this:

java -Djava.library.path="C:\Opencv2.1.11\opencv\build\java\x64" -jar BlurDetector.jar
like image 40
Boo Radley Avatar answered Oct 16 '22 22:10

Boo Radley


In opposite to the other answers, I rather suggest you never use absolute paths, instead use relative ones. When you give your software to another user, the user most certainly won't have the libraries in the same path as you do. By using relative paths in regards to your application you guarantee that the software runs on other users systems as well, without them having to set path variables, jvm directives and what not. They don't even have to have OpenCV installed if you give them the library dll this way.

Here's code to load the libraries in a relative way:

public static void initOpenCv() {

    setLibraryPath();

    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

    System.out.println("OpenCV loaded. Version: " + Core.VERSION);

}

private static void setLibraryPath() {

    try {

        System.setProperty("java.library.path", "lib/x64");

        Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
        fieldSysPath.setAccessible(true);
        fieldSysPath.set(null, null);

    } catch (Exception ex) {
        ex.printStackTrace();
        throw new RuntimeException(ex);
    }

}

All you have to do is to

  • put the libraries into a lib/x64 folder relative to your jar file
  • in your application you have to invoke initOpenCv() at the start of your program

That's it. This way you can develop as before and maintain a distributable application.


Here's the full version:

import java.lang.reflect.Field;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

import org.opencv.core.Core;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {

        initOpenCv();

        HBox root = new HBox();

        Label infoLabel = new Label();
        infoLabel.setText("OpenCV loaded. Version: " + Core.VERSION);

        root.getChildren().add(infoLabel);

        Scene scene = new Scene(root, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void initOpenCv() {

        setLibraryPath();

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        System.out.println("OpenCV loaded. Version: " + Core.VERSION);

    }

    private static void setLibraryPath() {

        try {

            System.setProperty("java.library.path", "lib/x64");

            Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
            fieldSysPath.setAccessible(true);
            fieldSysPath.set(null, null);

        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }

    }

    public static void main(String[] args) {
        launch(args);
    }
}

With a folder structure like this:

.\application.jar
.\lib\x64\*.dll

Hint: I packaged the opencv jar into the application.jar

like image 27
Roland Avatar answered Oct 16 '22 21:10

Roland