Working with JNI


There are a lot of examples of writing a simple jni library for calling from a java class.  Unfortunately, few of them explain how to push your JNI class/loadable library into a package of it's own.  I ran into this problem today while trying to integrate a JNI library I'd written outside of our ant-based build system into that same build system.  If you don't specify a package name then the JNI class and it's associated shared object (or dll under Windows) are in the global namespace and everything just kind of works.  At least when the main() is in a class that is also in that namespace. 

But when I put the JNI class and it's object into it's own package, then things got hairy.  Turns out you need to put the Java source into a directory structure that matches the package name, then run javac and javah (to generate the JNI header your C code needs) in the right way.  Here is what I did.

First, let's call the library JNILib.  The package for this library was named one.two.three.four (hey, this is for work – I can't give out all the super secrets, can I?).  So the Java class source (JNILib.java) was placed under one/two/three/four, relative to the current directory.  To compile the class file for the library I do:

    javac one/two/three/four/JNILib.java

which produces one/two/three/four/JNILib.class.  To get the header file I need for my C source, I do this:

    javah -jni one/two/three/four/JNILib

which produces one_two_three_four_JNILib.h in the current directory.  I include this in my C source:

    #include "one_two_three_four_JNILib.h"

And compile the C source with:

    gcc -I/usr/java/j2sdk1.4.2_12/include -I/usr/java/j2sdk1.4.2_12/include/linux -c JNILib.c -o JNILib.o
    gcc -shared -Wl,-soname,libJNILib.so -o libJNILib.so JNILib.o

Substitute the paths to your Java header files as appropriate.   The class file is copied into runtime/one/two/three/four and the shared object libJNILib.so is copied into runtime/lib.  The Java application that uses this library imports the JNILib class:

    import one.two.three.four.JNILib;

and to run the application I need to set my CLASSPATH to include runtime and set my java.library.path as such:

    export CLASSPATH=…/runtime
    java -Djava.library.path=…/runtime/lib MyJavaApp

All of this might be slightly off because I'm translating from my Makefile (which I don't have permission to post) but it's pretty close to what you have to do.