An affair with the Java native access (JNA)

Posted on
21 May 2012

I was recently speaking to a colleague about my first couple projects here at NAG. The first project was learning to call the Library from Python using c-types (thanks to Mike Croucher’s blog(link is external) which helped immensely). Next, was a project using the Java Native Interface (JNI), which I had difficulty using. After hearing the above two pieces of information, my colleague recommended I look into Java Native Access (JNA) as it was very similar to c-types in Python. Thus began a brief love affair! I say ‘love affair’ because my experience the JNA was a bit of a roller coaster of highs and lows. In the beginning, the JNA and I got along great. As time went on, I was left sitting at the computer screen wondering what to do next, hoping for the JNA to fix things.

Background of JNI

NAG already has a thorough technical report on our website(link is external) for calling the NAG Library using the Java Native Interface. This includes creating header files, compiling java files, compiling the interface library, and running the program. Seems like lots of work, even for simple functions. I was hoping the JNA would be easier.

First date with the JNA

To start using the JNA you just need to go to download the .jar file from https://github.com/twall/jna(link is external). Download the file and then move it to the directory you will be working in. Unzip it to create a com folder and you’re done! You can now start using it. Whenever you need to use a package from the JNA, just import it at the top of your Java file.

My first impression of the JNA started off on a high note. I found it extremely easy to start using the interface. Looking at code for calling the Bessel function (routine s17acc):

import com.sun.jna.Library;

import com.sun.jna.Native;

import com.sun.jna.Platform;

public class HelloWorldBessel { public interface CLibrary extends Library { CLibrary INSTANCE = (CLibrary)Native.loadLibrary("/opt/NAG/cll3a09dgl/lib/libnagc_nag.so", CLibrary.class);

 

double s17acc(double k,int fail); } public static void main(String[] args) {

int k=0; int retCode=0;

System.out.println("Y0(" + k + ") is " + CLibrary.INSTANCE.s17acc(k,retCode));

}

}

Using the JNA takes only a couple lines! Feel free to compile and run it yourself! No header files, no Javac/Javah code to compile, no JNI in sight! I was excited how easy the JNA was and very eager to try other functions.

Falling in love again

The second impression of the JNA was very nice as well. The reason I ‘fell in love’ was that it took only a couple more lines of code from the above Bessel example to call the linear equation solver (f04arc). Once variables are initialized and we’ve declared the f04arc method, all we need is a call to

CLibrary.INSTANCE.f04arc(n, a, tda, b, x,fail);

Again, it was nice and easy to use. Note: if the NAG function detects an error in the inputs, the error is automatically printed, and the entire program is terminated. A small inconvenience, but all relationships have some skeletons hidden in the closet.

Never getting Calledback

The JNA and I hit of rough patch with the callbacks. It proved to be difficult on getting the right calls, in addition to mapping C structures to Java. It took me pages of online forums and reading through user comments, but you end up needing to add extra lines when loading the library, creating the callback, and adding a structure class. A brief excerpt:

public interface CLibrary extends Library { CLibrary INSTANCE = (CLibrary)
Native.loadLibrary("/opt/NAG/cll3a09dgl/lib/libnagc_nag.so", CLibrary.class); 
interface acallback extends Callback{ 
double invoke(double x); 


void d01ajc(Callback fun, double a, double b, double epsabs, double epsrel, int max_num_subint, DoubleByReference result, DoubleByReferenceabserr, Nag_QuadProgress qp,int fail);
}

CLibrary.acallback fn=new CLibrary.acallback(){
public double invoke(double x){ 
return(x*x*x);
}
};

You’ll note when calling d01ajc, I needed to pass a Quad_Progress structure into the function. To do this, we need to create a structure with variables, but if you examine the contents of these variable after the call d01ajc, their information is meaningless (comments on how the call to d01ajc populates these fields are welcome below!). On top of this, the JNA does not handle errors very well. Since it is not apart of Java itself, I would oftentimes get “An error occurred outside Java” and left wondering which argument I got wrong.

Timings

Averaged over 100 runs, the timings are:
  JNA JNI
s17acc .0015s .0010s
f04arc .0082s .0015s
d01ajc .0377s .0388s

Back to the JNI

My first impression of the JNA was nice. It was simple and no 'glue code' was required. Upon further investigation I found a couple of drawbacks which include:

  • Mapping C structures to Java
  • Slightly slower than JNI
  • Error Handling

Since we already have most (if not all) the wrappers for the Library using the JNI, I will stick with that for now. Alas, my time with the JNA was fun while it lasted.