UnsatisfiedLinkError in exported (Eclipse) executable jar file - java

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:
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.
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.

The UnsatisfiedLinkError is thrown when an application attempts to load a native library like
.so in Linux,
.dll on Windows or
.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

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

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

Related

Why the exported to desktop (.exe) processing app with java classes can not run properly? My another project was exported without problems

I try to export my processing app as the "ready to use" application with exe launch file for desktop.
My code is pretty simple. Proccessing code:
//import io.itch.mgdsstudio.airfight.connecteddevices.*;
private io.itch.mgdsstudio.airfight.connecteddevices.Controller controller;
void setup(){
size(600,800, JAVA2D);
background(0);
//I think the next code line can not be launched after export. Background stays black
controller = new io.itch.mgdsstudio.airfight.connecteddevices.Controller(this);
}
void draw(){
controller.render();
}
and the java-class:
package io.itch.mgdsstudio.airfight.connecteddevices;
import processing.core.PApplet;
public class Controller {
private PApplet engine;
public Controller(PApplet engine) {
this.engine = engine;
}
public void render(){
engine.background(255,0,0);
}
}
The application runs perfect from processing ide - the screen is red. But after export it can not run properly. The screen is black. I tested processing 3 and 4. In january I exported an another application succesfully. But now I can not launch exported file. I think the trouble is in versions of the java source files.
I tried to change code so:
import io.itch.mgdsstudio.airfight.connecteddevices.Controller;
private Controller controller;
void setup(){
size(600,800, JAVA2D);
background(0);
controller = new Controller(this);
}
void draw(){
controller.render();
}
I receive the message in the console:
No library found for io.itch.mgdsstudio.airfight.connecteddevices
but it runs in the ide. But after export it can not run properly again. Maybe i need another package names?
There seems to be an issue/bug using package inside the Processing IDE.
As you hinted in your comments, if you could compile a .jar in your Java IDE of choice and use that in Processing that should work.
From a pragmatic point of view, if you don't plan on fixing the Processing IDE to handle package as expected, you can simply not use it your code:
import processing.core.PApplet;
public class Controller {
private PApplet engine;
public Controller(PApplet engine) {
this.engine = engine;
}
public void render(){
engine.background(255,0,0);
}
}
Controller controller;
void setup(){
size(600,800, JAVA2D);
background(0);
controller = new Controller(this);
}
void draw(){
controller.render();
}
This wouldn't be convenient on a larger project where you may want to write Java code in your preferred IDE but still be able to colaborate with others that use the Processing IDE alone.
Since running in the Processing IDE works (e.g. dev/testing), but can't export a .exe for easy deployment, a workaround could be using the processing-java command. (If you add your Processing installation folder to the Windows %PATH% environment variable you should be able to type processing-java in a new Command Prompt window and see the help/usage guide).
Running processing-java --sketch=path\to\YourSketchFolder --run should run the sketch the same way the Processing IDE does (without actually having the IDE open). While this implies installing Processing and adding it to %PATH% on any new machine on one hand, on the other it saves you the time of having rebuild/repackage new .exe files for every single change.

Update java desktop app

I am trying to develop a module that can update my running Java Desktop App.
The problem is that I have to replace the actual running jar with another jar, all the while displaying an image and a progress bar with the remaining time of the update process.
One solution I thought about is that I can put a jar in my main jar, and when launching the update process, to extract that second jar which will display the image and the progess bar, and also which will replace the old main jar with a new main jar.
My question is if this is possible and how can I do it.
I do not have a lot of experience with java and java packaging so if you have any examples or links, it would be of great help for me.
Thank you very much.
R.
Run this code when press UPDATE button ..
if(Desktop.isDesktopSupported()){
try {
Desktop.getDesktop().open(new File("update.jar"));
System.exit(0);
} catch (IOException ex) {
}
}
This will open update.jar and close main.jar. Now run this code from main class of update.jar
//wait sometime for terminate main.jar
try{
Thread.sleep(5000);
} catch(Exception e){
e.printStackTrace();
}
if(isUpdateVersionAvailable()) { //first check update from database
if(copyMainJarFileFromServer()){ //copy newMain.jar from server and paste
new File("main.jar").delete(); //delete main.jar
rename(new File("newMain.jar")); //rename newMain.jar to main.jar
}
}
boolean isUpdateVersionAvailable() {
//todo
}
boolean copyMainJarFileFromServer() {
//todo
}
void rename(File file){
file.renameTo(new File("main.jar"));
}
You can have a starter jar that checks for updates and launches the app from the main jar.
It will show start logo, an image, that standard java can display at start-up.
The start0er could also be used to restart the app in another interface language.
package starter;
...
public class StarterApp {
public static void main(String[] args) {
String workDir = System.getProperty("user.dir");
Path mainJar = Paths.get(workDir + "...");
Path nextMainJar = Paths.get(workDir + "...");
if (Files.exists(nextMainJar)) {
Files.copy(nextMainJar, mainJar, StandardCopyAction.REPLACE_EXISTING);
}
URLClassLoader classLoader = new URLClassLoader(new URL[] {mainJar.toURL()});
Class<?> appClass = classLoader.find("mainjar.MainApp");
... instantiate the app
}
As you see the main jar must not be loaded from too early, maybe not be on the class path entirely, and hence the use of a separate ClassLoader. The same might probably be done with the main jar on the class path of the starter app, and using Class.forName("mainjar.MainApp"). The Class-Path can be specified in META-INF/MANIFEST.MF.
The secundary jars may reside in a lib/ directory.
For those readers wanting more modular, service oriented, updateable apps, one could make an OSGi application, a container for bundles (=jars), that provide exchangable services and life-time control.

Unable to load library 'gsdll32'

I am running following code to create bmp image from pdf using Ghost4j
i have a commad which is executed by GhostScript generator to generate Bmp image of a page from pdf.
Code is:
package ghost;
import net.sf.ghost4j.Ghostscript;
import net.sf.ghost4j.GhostscriptException;
public class GhostDemo {
public static void main(String[] a){
Ghostscript gs = Ghostscript.getInstance(); //create gs instance
String[] gsArgs = new String[10];/*command string array*/
gsArgs[0] = "-dUseCropBox";/*use crop box*/
gsArgs[1] = "-dNOPAUSE";
gsArgs[2] = "-dBATCH";
gsArgs[3] = "-dSAFER";
gsArgs[3] = "-r300";
gsArgs[4] = "-sDEVICE=bmp16m";
gsArgs[6] = "-dTextAlphaBits=4";
gsArgs[5] = "-sOutputFile=C:/PagesWorkspace/1/masterData/1.bmp";/*bmp file location with name*/
gsArgs[6] = "C:/MasterWorkspace/pipeline.pdf";/*pdf location with name*/
try {
gs.initialize(gsArgs); /*initialise ghost interpreter*/
gs.exit();
} catch (GhostscriptException e) {
e.printStackTrace();
}
}
}
i am getting Exception
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'gsdll32': The specified module could not be found.
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:145)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:188)
at com.sun.jna.Library$Handler.<init>(Library.java:123)
at com.sun.jna.Native.loadLibrary(Native.java:255)
at com.sun.jna.Native.loadLibrary(Native.java:241)
at net.sf.ghost4j.GhostscriptLibraryLoader.loadLibrary(GhostscriptLibraryLoader.java:36)
at net.sf.ghost4j.GhostscriptLibrary.<clinit>(GhostscriptLibrary.java:32)
at net.sf.ghost4j.Ghostscript.initialize(Ghostscript.java:292)
at ghost.GhostDemo.main(GhostDemo.java:22)
Can any one tell me why i am getting this exception?
Do you have Ghostscript installed at all?
If yes, which version?
If yes, in which location?
Does it include a file gsdll32.dll?
If not, download the Ghostscript installer for Win32 and run it. After the installation, there should be a file gsdll32.dll in directory %your_install_dir%\gs\gs9.05\bin\
Pasting dll file in eclipse project made my program work!
For the SO community, another thing to check with this error is that you are using 32-bit Java. If your instance of Java is 64-bit, you will get the exact same message:
Unable to load library 'gsdll32': The specified module could not be found.
without any further explanation even if you are pointing to the correct dll.

How to launch a resource jar from inside another java app - with Solution

EDITED with solution (below...)
I have a Splash screen that is packaged into it's own jar. It works.
I can call the Splash.jar from inside another java app by:
Desktop.getDesktop().open(new File("/Applications/Eclipse/Splash.jar"));
and it works just fine. But, that's pretty limited. So, I created a res folder in the new app and dragged the Splash.jar into it.
Now, how do I call it/run it from the main class of the new app??
I looked at all the related posts and see no clear approach...
Thanks
SOLUTION:
I found the solution - so simple. First, the credit to avjava.com for their clear and excellent tutorial on doing this ( Run Another Jar from a Jar ). So, now I can run the Splash (or other .jar) just as hoped for.
The answer is here - posted in the form of complete code:
package test;
import java.io.IOException;
public class RuntimeExecTest1 {
public static void main(String[] args) {
try {
System.out.println("TextEdit I hope");
Runtime runTime = Runtime.getRuntime();
Process process = runTime.exec(
"java -jar /your directory/your app.jar");
try {
Thread.sleep(5000); // keep in open 5000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Closing TextEdit, I hope");
process.destroy(); // kill the process of running the .jar
} catch (IOException e) {
e.printStackTrace();
}
}
}
We don't know how your existing Splash Screen works...
Java AWT support for Splash Screen:
If you are using the Java built-in support for splash screens (as specified in SplashScreen Javadoc) then you need to use a command line switch, or better yet, modify your MANIFEST file in order to reference your Splash Screen:
Manifest-Version: 1.0
Main-Class: Test
SplashScreen-Image: filename.gif
I don't know if, for this particular case, you can reference files in a different JAR. In the worst case, you can unpack the existing JAR (they are just ZIP files) and get the image file in order to include it in your own main jar.
Possibly custom Splash:
If your Splash is created using custom code, then you need the documentation about how to load it. At least, you'd need to add Splash.jar to the classpath of your application and, from your app, call the necessary method or load the appropriate resource.
All the resources and classes contained in .jar files that are added to the classpath are available from your app.
You could create a new URLClassLoader with the Splash.jar and then use reflections to execute the main method.
URL[] urls = new URL[] { new URL("res/Splash.jar") };
ClassLoader cl = new URLClassLoader(urls);
Class<?> clazz = cl.loadClass("splash.Main");
Method method = clazz.getMethod("main", String[].class);
method.invoke(null, new String[0]);
add the resource path to your CLASSPATH envoirment variable and you can use it without modifying your existing code
if your running linux
export CLASSPATH=yourpath;
and if your running windows:
from My Computer right click > properties
OR
if you dont want to add it to CLASSPATH ENV variable,
then
java -classpath="your path to jar" yourclass
Why not define Splash.jar as an external jar and go about using all its routines. Much like JDBC.

Embedding a Java (.jar) file within a Mac Application

I need to have a .jar file run within my main NSWindow, how can I do this?
I have been looking at Apple's example for "JavaFrameEmbedding", and seem to be able to run it without any Java exceptions (previously I had exceptions), however I cannot see the applet. They use the JavaFrameView which is part of the JavaFrameEmbedding framework, although I can't find any documentation about this at all. This is using Lion (I have also tried on Snow Leopard without success).
Download this puppy and dig through it.
If you want to make the NSWindow in java and have the program run from there try something like this:
import com.apple.cocoa.application.*;
import com.apple.cocoa.foundation.*;
public class Test {
public static void main (String [] args) {
NSApplication nsapp = NSApplication.sharedApplication();
NSRect rect = new NSRect(500, 500, 500, 500);
NSWindow.MiniaturizableWindowMask;;
NSWindow window = new NSWindow(rect, style, NSWindow.Buffered,
false);
window.makeKeyAndOrderFront(window);
nsapp.run();
}
}

Categories