Home > Java > JNA meets JNI

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!

To go further:

email
Send to Kindle
Categories: Java Tags: , , , , , , ,
  1. June 21st, 2009 at 09:44 | #1

    Hi Nicolas,
    Nice introductory post :-)

    You should check out JNAerator, which does the job of translating the C definitions into JNA wrappings automatically for you. It’s not yet finalized, but basically you just have to run it on a set of headers and it will JNAerate a compiled JAR with your wrappings.

    Cheers !

  2. June 21st, 2009 at 10:43 | #2

    Hi Olivier,

    I quickly checked your link: it doesn’t alleviate the need to have the .h headers at development time. JNA’s advantage is that it can do without since you can work directly on the compiled library. IMHO, this is the gap between JNI and JNA.

    Wish you the best for your product.

  3. August 17th, 2009 at 18:46 | #3

    Hi Nicolas,

    In its new version 0.9, JNAerator supports working without any header.
    This is limited to C++-decorated functions and static methods exported in Win32 DLLs (no support for instance methods, __cdecl or extern “C” functions, nor for structures reverse-engineering), but it might be helpful for some simple reverse-engineering tasks.
    And JNA can “work without headers”, but it does needs Java interfaces, which are pretty much the same as headers, albeit Java-fied. JNAerator gives you the Java interface if you wrote or found the C header.

    Best regards

  4. Hillence-Rain
    August 3rd, 2010 at 13:12 | #4

    Thanks for your sharing jna with everyone,but ,I still have problems in using jna to program;
    package test;

    import com.sun.jna.Library;
    import com.sun.jna.Native;

    class HelloWorld {
    public interface CLibrary extends Library {
    CLibrary INSTANCE = (CLibrary) Native.loadLibrary( “test”, CLibrary.class);
    int add(int a,int b);
    }

    public static void main(String[] args) {
    CLibrary.INSTANCE.add(1,2);

    }
    }
    could you please shou me what is the matter with the above code?I really don’t konwn how to solve the problem since the Netbeans always throws exception like:
    run:
    Exception in thread “main” java.lang.UnsatisfiedLinkError: Error looking up function ‘add': ÕҲ»µ½ָ¶¨µ
    at com.sun.jna.Function.(Function.java:126)
    at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:219)
    at com.sun.jna.Library$Handler.invoke(Library.java:191)
    at $Proxy0.add(Unknown Source)
    at test.HelloWorld.main(HelloWorld.java:14)
    Java Result: 1
    Thanks in advance!

  5. August 3rd, 2010 at 19:07 | #5

    From what I see, it seems you defined the interface method with Java types whereas JNA would expect native types. Just look at the native types here: it seems you need jint instead.

  6. Arnold
    April 12th, 2012 at 10:04 | #6

    Hi Nicolas,

    Do you know if JNA can call also a custom dll?
    If so, kindly help give an example how to do it?

    Any help is much appreciated.

    Thanks a lot.

  7. January 10th, 2013 at 22:41 | #7

    @Arnold

    The advantage of JNA over JNI is that you don’t need to have access to the source. So, it would appear that all you need to do is compile the DLL with the compiler of your choice (MSVC or g++) and use it as you would a 3rd party dynamic library.

  1. No trackbacks yet.