Looooong time… Kind of busy… So, no blogs.
Now I worked on a bit (means really a tiny part) of JNI. Thought of sharing how to write a sample JNI app.
- A linux box. (I haven’t tried writing a JNI app in Windows.)
- JDK installed in your machine.
- And more importantly, a bit of interest in writing a JNI app. 😀 Dont ask me whether I had it or not
Lets get started…
Phase 1 : Creating the JNI method and header files.
- Create a class that declares a native method. Something like this:
native char myMethod();
- Also, you can have other methods that invokes your native method. Use
System.loadLibrarymethod to load your native library. One thing worth noting here is the invocation of loadLibrary method.
It will be something like this:
The runtime will search for the file “libFileName.so” in the java.library.path. ie. It prepends “lib” and appends “.so” to the FileName. In windows it will search for FileName.dll (I guess the file name is right) file. So, your code will be portable across platforms.
- Compile your class.
- Then run the following command.
javah -jni -o OutputHeaderFile.h package.name.ClassName
Phase 1 completed. You are half way through.
Phase 2: Creating the shared object.
- Once you have created the header file, create your native implementation file. This file should include both jni.h and OutputHeaderFile.h (created in Phase1)
- Once you have created your implementation, compile it using:
gcc YourImpl.cpp -shared -I/opt/jdk1.5.0_08/include -I/opt/jdk1.5.0_08/include/linux -lc -lstdc++ -o libFileName.so
Phase 2 completed. You are 90% done.
Phase 3: Execute
- Copy your libFileName.so to java.library.path
- Run your class file.
You are done 🙂
Looks very vague. Could not understand head or tail. Isn’t it? Lets see what we were doing in each phase (ONLY the important steps that needs some explanation.) and what might have happened.
Step 1: We are declaring that myMethod is a native method and it returns a char.
Step 4: Here, javah reads your class file and creates a header file. This file should be used while implementing the method in native language.
What javah might have done?
I guess, it parses the class file and finds out the signatures of the native methods and creates a header file with that signature. The method declaration will be something like this in the header file:
(JNIEnv *, jobject);
It includes package name and class name in the method’s name.
I assume this phase might not need much explanation. You are compiling your native implementation and creating a “so” file.
Just you are placing the file in a location known to the java runtime. Read the 2nd error I faced, for a bit more explanation.
I donno about you. But I faced only “UnsatisfiedLinkError” in two cases.
- Here, I didn’t copy the “so” file in java.library.path. As it could not find the so file, it threw that error.
- This was an interesting one (Atleast for me):
Exception in thread "main" java.lang.UnsatisfiedLinkError: myMethod
at test.MyClass.myMethod(Native Method)
I understood, on seeing the error, that my runtime could not locate the method. As the method was present in the “so” file, I could not find the reason for this error. Another reason is, “It was working previously”. (A typical programmer’s response. Huh??? )
After some time, I did a “less” (unix command) of that “so” file (I used to do it in case just got curious about any binary file) and found that the method has the package name in it. Then I realized what I have done.
I had changed the package name of my class and then tried to use the same old “so” file. ie. Changed packge from test1 to test. So when I invoked the method, what might have happened is, “Runtime was looking for Java_test_MyClass_myMethod”. But in the “so”, the method name is “Java_test1_MyClass_myMethod”.
Once I re-created the header file and the so file, Well!!! You know what might have happened 😉 Otherwise this blog post might not be there 😀
Try it out… and in case you got any other info, leave a comment. I’ll love it.