I thought which title to choose for 30 minutes, because my problem is rather strange.
Suppose we have a C++ native dll (C.dll). I want to load this dll with the help of JNA into my java project. Now what's important: in C.dll there is widely used a file path, from where this dll was called. And there is literally an if-statement like this:
if (filepath[2] != _T('\\'))
{
//throw an arror and close dll loading
}
If I try to load this dll via JNA, it throws an internal dll error with the following message: "There is missing a certain sign '\' in: "C:/Program Files/AdoptOpenJDK/jdk-14.0.0.36-hotspot/bin/client" on position: 3"
I know the nature of that error and I also understand, that this if-statement is really silly, because it is absolutely anti-crossplatform, but I couldn't change C.dll, because it has come from 3rd party, well, you know that story.
What is also problematic - I couldn't just replace this file path parameter somewhere (f.e. via some other wrapper.dll or so), call then this wrapper via JNA and be happy, because all that file path checking inside C.dll is harcoded with the help of multiple macros and it is implied, that all the routines of receiveing and checking this file path are occured fully automatically (this is actually provided by other dlls, which C.dll have to use, and for which I don't have a source code, yes, it is that bad). So it is not so easy to find a concrete value which I could directly replace.
So, my question is: is it somehow possible to replace those (/) to double (\) backslashes in file path of jvm.dll in runtime or so? Is it possible to write a wrapper.dll, that will do it for my C.dll, either in C++ or java? I need to run this finally in JNA, that's actually why the file path is exactly JAVA_HOME or so - because as far as I understood java virtual machine is exactly the process, who loads C.dll in that situation, that's why I got the path to jvm.dll as a wrong file path. AFAIK all the java paths are harcoded with (/) in JDK, so from the JNA's side it is not directly possible in my opinion. But is it possible generally without changing original .dll? Maybe there exist something like path-replacers tools for java in Windows or so?
Related
I am writing an interface in Java which uses underneath library in "C".
Now, when I try to load the library specifying relative path, it cannot find the library.
If I give the absolute path, it works fine.
I want to know, is there something to do with relative and absolute path on MAc OS. Because same code works well on linux(even though I specify relative path on that).
Please Help.
Defining the system property jna.debug_load (pass -Djna.debug_load=true to your JVM) will result in console output indicating where JNA is looking for your native library.
Keep in mind you need to define jna.library.path to be the directory where JNA can find your library. That value should be an absolute path. If you're using something like myapp/libs then your operation is going to be dependent on whatever the process's current directory is set to.
How can I load a custom dll file in my web application? I've tried the following:
Copied all required dlls in system32 folder and tried to load one of them in Servlet constructor System.loadLibrary
Copied required dlls into tomcat_home/shared/lib and tomcat_home/common/lib
All these dlls are in WEB-INF/lib of the web-application
In order for System.loadLibrary() to work, the library (on Windows, a DLL) must be in a directory somewhere on your PATH or on a path listed in the java.library.path system property (so you can launch Java like java -Djava.library.path=/path/to/dir).
Additionally, for loadLibrary(), you specify the base name of the library, without the .dll at the end. So, for /path/to/something.dll, you would just use System.loadLibrary("something").
You also need to look at the exact UnsatisfiedLinkError that you are getting. If it says something like:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no foo in java.library.path
then it can't find the foo library (foo.dll) in your PATH or java.library.path. If it says something like:
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.example.program.ClassName.foo()V
then something is wrong with the library itself in the sense that Java is not able to map a native Java function in your application to its actual native counterpart.
To start with, I would put some logging around your System.loadLibrary() call to see if that executes properly. If it throws an exception or is not in a code path that is actually executed, then you will always get the latter type of UnsatisfiedLinkError explained above.
As a sidenote, most people put their loadLibrary() calls into a static initializer block in the class with the native methods, to ensure that it is always executed exactly once:
class Foo {
static {
System.loadLibrary('foo');
}
public Foo() {
}
}
Changing 'java.library.path' variable at runtime is not enough because it is read only once by JVM. You have to reset it like:
System.setProperty("java.library.path", path);
//set sys_paths to null
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);
Please, take a loot at: Changing Java Library Path at Runtime.
The original answer by Adam Batkin will lead you to a solution, but if you redeploy your webapp (without restarting your web container), you should run into the following error:
java.lang.UnsatisfiedLinkError: Native Library "foo" already loaded in another classloader
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1715)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1646)
at java.lang.Runtime.load0(Runtime.java:787)
at java.lang.System.load(System.java:1022)
This happens because the ClassLoader that originally loaded your DLL still references this DLL. However, your webapp is now running with a new ClassLoader, and because the same JVM is running and a JVM won't allow 2 references to the same DLL, you can't reload it. Thus, your webapp can't access the existing DLL and can't load a new one. So.... you're stuck.
Tomcat's ClassLoader documentation outlines why your reloaded webapp runs in a new isolated ClassLoader and how you can work around this limitation (at a very high level).
The solution is to extend Adam Batkin's solution a little:
package awesome;
public class Foo {
static {
System.loadLibrary('foo');
}
// required to work with JDK 6 and JDK 7
public static void main(String[] args) {
}
}
Then placing a jar containing JUST this compiled class into the TOMCAT_HOME/lib folder.
Now, within your webapp, you just have to force Tomcat to reference this class, which can be done as simply as this:
Class.forName("awesome.Foo");
Now your DLL should be loaded in the common classloader, and can be referenced from your webapp even after being redeployed.
Make sense?
A working reference copy can be found on google code, static-dll-bootstrapper .
You can use System.load() to provide an absolute path which is what you want, rather than a file in the standard library folder for the respective OS.
If you want native applications that already exist, use System.loadLibrary(String filename). If you want to provide your own you're probably better with load().
You should also be able to use loadLibrary with the java.library.path set correctly. See ClassLoader.java for implementation source showing both paths being checked (OpenJDK)
In the case where the problem is that System.loadLibrary cannot find the DLL in question, one common misconception (reinforced by Java's error message) is that the system property java.library.path is the answer. If you set the system property java.library.path to the directory where your DLL is located, then System.loadLibrary will indeed find your DLL. However, if your DLL in turn depends on other DLLs, as is often the case, then java.library.path cannot help, because the loading of the dependent DLLs is managed entirely by the operating system, which knows nothing of java.library.path. Thus, it is almost always better to bypass java.library.path and simply add your DLL's directory to LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS), or Path (Windows) prior to starting the JVM.
(Note: I am using the term "DLL" in the generic sense of DLL or shared library.)
If you need to load a file that's relative to some directory where you already are (like in the current directory), here's an easy solution:
File f;
if (System.getProperty("sun.arch.data.model").equals("32")) {
// 32-bit JVM
f = new File("mylibfile32.so");
} else {
// 64-bit JVM
f = new File("mylibfile64.so");
}
System.load(f.getAbsolutePath());
For those who are looking for java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path
I was facing same exception; I tried everything and important things to make it work are:
Correct version of pdf lib.jar ( In my case it was wrong version jar kept in server runtime )
Make a folder and keep the pdflib jar in it and add the folder in your PATH variable
It worked with tomcat 6.
If you believe that you added a path of native lib to %PATH%, try testing with:
System.out.println(System.getProperty("java.library.path"))
It should show you actually if your dll is on %PATH%
Restart the IDE Idea, which appeared to work for me after I setup the env variable by adding it to the %PATH%
The issue for me was naming:
The library name should begin with "lib..." such as libnative.dll.
So you might think you need to load "libnative": System.loadLibrary("libnative")
But you actually need to load "native": System.loadLibrary("native")
Poor me ! spent a whole day behind this.Writing it down here if any body replicates this issue.
I was trying to load as Adam suggested but then got caught with AMD64 vs IA 32 exception.If in any case after working as per Adam's(no doubt the best pick) walkthrough,try to have a 64 bit version of latest jre.Make sure your JRE AND JDK are 64 bit and you have correctly added it to your classpath.
My working example goes here:unstatisfied link error
I'm using Mac OS X Yosemite and Netbeans 8.02, I got the same error and the simple solution I have found is like above, this is useful when you need to include native library in the project. So do the next for Netbeans:
1.- Right click on the Project
2.- Properties
3.- Click on RUN
4.- VM Options: java -Djava.library.path="your_path"
5.- for example in my case: java -Djava.library.path=</Users/Lexynux/NetBeansProjects/NAO/libs>
6.- Ok
I hope it could be useful for someone.
The link where I found the solution is here:
java.library.path – What is it and how to use
It is simple just write java -XshowSettings:properties on your command line in windows and then paste all the files in the path shown by the java.library.path.
I had the same problem and the error was due to a rename of the dll.
It could happen that the library name is also written somewhere inside the dll.
When I put back its original name I was able to load using System.loadLibrary
First, you'll want to ensure the directory to your native library is on the java.library.path. See how to do that here. Then, you can call System.loadLibrary(nativeLibraryNameWithoutExtension) - making sure to not include the file extension in the name of your library.
I have been googling around, trying to understand what the Java Classpath and Path are. However, I am stil not quite sure if I have understood it or not. If feel that this topic is one of those grey areas.
Can someone explain me what those are? I mean, where do I find and set them (where is the actual text file on Mac/Windows)? Is there only one instance of each one? If so, how do I set the path for multiple classes?
As you might have notices, I am totally confused right now after reading so many different tutorials... So now I really would like to have a straight forward explanation.
Please help me, I just trying to learn :)
Thank you all
A path is just a folder location. The path is where your OS will look for programs by default. If java, javac, javap, etc, etc, are in your path then you can just type their names without the entire folder location.
Your classpath is similar. It is a set of folders that contain .class files describing classes(hence the name) and .jar files, which are basically files that contain .class files. All code that you're running is either out of the classpath, generated, or out of the java libaries(also part of the classpath, techncically).
With each run of a java program you can specify a classpath by parameters passed to the java executable. It also grabs classes out of "extension folders,", special folders Java keeps around to act as a system classpath, and finally, the "bootstrap classes", which are a set of important classes almost any Java program needs to run.
Simple mean of path is location of file system. if you want to access any file then you have to manually needs to go there location.
just example: d:\text1.txt then needs to go that d:\ location. same way java program have command like
javac -for compile
java - for run
.
.
.
etc.
that inside java-jdk\bin folder
so if you don't set into classpath. then you can execute java program like
run->cmd
c:\jdk1.6\bin> javac test.java
so without going explicit way you can set it into classpath, and direct execute java program from anywhere.
You can set java path as environment variable of computer.
The PATH is basically where your JDK is installed; this is essentially what your IDE will look for when trying to compile or create Javadoc or such; it's basically just the location of a folder on your hard drive, set as a Windows (or other OS) environment variable to make it easier to use.
The CLASSPATH is a property that tells the compiler where to look for classes. Basically if you download a library or such from somewhere, you need to add it to the CLASSPATH for the compiler to use it. Usually you can do this in your IDE, however, you should not need to directly access the CLASSPATH variable.
By the way, the Wikipedia article is pretty helpful.
1)java Path: it is location of binary executable files
example :javac , java
this file are used for compile and run
2)class Path: it is location of .class file(file create after compile your source code .java file)
I am calling C++ method using DLL file in my Java project. Right now, I have hard coded the path.
The application will be deployed on many machines and it also run on multiple machine. Where should I put my DLL file so that I can load it and call it on any machine?
I've seen applications that put the DLL into the JAR file. At run-time, they extract the DLL from the JAR into a temporary directory and then access it there.
It's not the most efficient approach but the easiest from a deployment perspective.
You have to make sure your DLL is in the classpath.
One such way to do so is to put the path to the DLL in PATH environment variable.
Other option is to add it to the VM arguments in the variable LD_LIBRARY_PATH, like this:
java -Djava.library.path=/path/to/my/dll -cp /my/classpath/goes/here MainClass
If you are developing a complex application, that has to be stable you have to ensure that the DLL you need is put somewhere, where the OS is going to look for it, probably think of an installer script/program.
C:\WINDOWS\system32 (assuming C is the drive where windows is installed, probably you can get it from registry)
I used to use windows long time ago & not an expert, so I made a google search for you and find the link http://vlaurie.com/computers2/Articles/dll.htm
See the last topic in the link (the one starting with headline Using Regsvr32.exe to Register DLLs)
Is there a java sdk for cygwin?
It would be nice if there were a native cygwin implementation which used the cygwin file system and X-windows for display, unfortunately I am not aware of such a release. I would assume it is quite an effort to port OpenJDK as well, but I haven't tried.
Although there is no java sdk for cygwin, you can get the Windows jdk to work if you are willing to accommodate workarounds for various problems:
some cygwin paths are not handled as expected by java programs
the file path separator is backslash rather than slash
the PATH entry separator is semicolon instead of colon
In my experience, the first bullet is by far biggest problem, although the three are somewhat inter-related. The separators tend to take care of themselves as a side-effect of solving the first problem.
All three problems are largely resolved by setting up a development environment in which all file paths of interest (as viewed by java.io.File and java.nio.Path, etc.) can be represented without specifying a drive letter.
As it turns out, it's rarely necessary to use backslashes in a file path string under windows. The only exceptions to this rule that I have encountered are when passing file path strings as parameters when spawning a command line for a program that require backslashes (e.g., CMD.EXE). The java.io and java.nio packages all accept forward slashes, and so, for that matter, do the Microsoft development libraries. Most programs that reject a path with forward slashes are (IMHO) likely to be doing so gratuitously.
So, the real problem is that "/cygdrive/c" is not recognized by java.io.File as referring to "C:\".
In other words, the following file test will return false:
new java.io.File("/cygdrive/c").exists()
whereas this works as expected:
new java.io.File("c:/").exists()
Recent versions of Windows now support general symlinks, providing a way to setup a cygwin development environment in which drive letters are not used. With a unified view of the entire filesystem (with all files appearing below "/", the default drive letter being invariant, e.g., C:) , the drive letter can be discarded from file path strings. In other words, you want to be able to refer to "c:/" as "/". This can be accomplished in various ways, one being to symlink other drives below c:/, for example:
$ ln -sFT d:/ c:/d
If env variable CYGWIN contains "winsymlinks:native", this will create a Windows symlink, with the result that (assuming c: is the default drive) your java program will correctly recognize the string "/d" as referring to "D:\", so you can do this:
new java.io.File("/d").isDirectory // returns true, as expected
If you are unable or reluctant to modify you cygwin environment, there is another approach, which is more universal. You can extend java.io.File and override constructors and various methods to (in effect) to translate cygwin paths to their windows equivalent (like cygpath -m or -w), and to translate windows path strings to a more POSIX-like format. I have such a library (written in scala, but usable from java) and intend to make it available, hopefully sometime soon.