JNA meets JNI

I reccently stumbled upon a nice framework you’ll love if you ever have to work with native code. Before this framework, if you needed to call native code, you would use JNI. JNI uses a proved but complex and error-prone process.

First thing first, you write your Java classes like always. But for methods you want to delegate to native code, you use the native keyword and do not provide an implementation. Then, you call a JDK-provided executable named javah. This generates your C header file (*.h) and an empty stub implementation: you have to fill the voids. Finally, you compile both Java and C files.

At runtime, do not forget to load the library with System.loadLibrary("mylib"). Notice you do not provide the extension, the JVM does it automatically for you, depending on you platform (.dll on Windows, .so on Linux). Then call you Java class and it will magically delegate to your native code.

This whole process always frustrated me (and so, I can imagine, lots of developers) because of the following reasons:

  • since I’m a Java developer and not a C developer, I could never write good C code. It hurts my head to even consider memory allocations or to bring myself to think about function pointers 😉
  • if I need to change the native Java method signature, I have to run the whole process again or change both header and C files without errors, and then compile everything again. In this case, I can’t stress out the importance of having a very automated build process or the adequate IDE (I tend toward the former)
  • last, but not least, what if I do not have access to the source C file? JNI can’t help you call Windows dll…​ or you have to write a proxy-like C file to do so

Rejoice people. Java.net brought you the solution. The answer to your problems is Java Native Access or JNA. Now calling a NTLM authentication or showing the running services inside your application will be a breeze. Let’s try to get informations about your computer running under Windows - sorry 'Nix users.

The first thing is to know which function will get you there: such is the goal of the MSDN library. Now, create an interface, preferably name after the DLL you will use and make it inherit from com.sun.jna.Libray. Its methods will have to map exactly the name and the arguments of the DLL. For example, let’s say you want to display your computer’s name. Under Windows, there’s a method named GetComputerNameW() that is provided by kernel32.dll. So, you interface will have a method adequately named GetComputerNameW(). The Devil being in the details, you’ll have to map each parameter documented in MSDN on a parameter in your interface’s method’s signature. GetComputerNameW() takes 2 parameters: a LPTSTR (pointer to a char buffer) and a LPDWORD (pointer to a integer). Running to JNA documentation, the mapping in Java becomes a char[] and a com.sun.jna.ptr.IntByReference.

Your interface now looks like this:

public interface Kernel32 extends StdCallLibrary {

    int GetComputerNameW(char[] name, IntByReference number);
    // Other method mappings

Now, in order to access a Kernel32 reference, just use the following codeline. Under the table, it will bind our interface to the underlying implementation through a proxy:

Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);

This done, each subsequent call to kernel32’s GetComputerName() method will fill the char buffer with our computer’s name.

JNA still suffers from some drawbacks:

  • JNA usually performs 10x slower than JNI. It has some techniques to speed up execution, so if you are in a performance-aware environment, you’ll probably want to use them
  • it won’t make you a pro C programmer so very complex method signatures will throw you into frenzy: the harder part of the job will be mapping the datatypes from C to Java. This will probably frustrate you to no end since you will be seeing java.lang.UnsatisfiedLinkError: Error looking up function XXX: La procédure spécifiée est introuvable more often than not. In this case, call a C programmer for help!

The sources of this small project are provided Maven-style. Have fun with Java and Windows!

Nicolas Fränkel

Nicolas Fränkel

Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.

Read More
JNA meets JNI
Share this