119

JNA seems a fair bit easier to use to call native code compared to JNI. In what cases would you use JNI over JNA?

Marcus Leon
  • 55,199
  • 118
  • 297
  • 429
  • One important factor that we chose JNA over JNI, is that JNA did not require any modifications to our native libraries. Having to customize native libraries just to be able to work with Java was a big NO for us. – kvr Aug 26 '17 at 19:33

10 Answers10

127
  1. JNA does not support mapping of c++ classes, so if you're using c++ library you will need a jni wrapper
  2. If you need a lot of memory copying. For example, you call one method which returns you a large byte buffer, you change something in it, then you need to call another method which uses this byte buffer. This would require you to copy this buffer from c to java, then copy it back from java to c. In this case jni will win in performance because you can keep and modify this buffer in c, without copying.

These are the problems I've encountered. Maybe there's more. But in general performance is not that different between jna and jni, so wherever you can use JNA, use it.

EDIT

This answer seems to be quite popular. So here are some additions:

  1. If you need to map C++ or COM, there is a library by Oliver Chafic, creator of JNAerator, called BridJ. It is still a young library, but it has many interesting features:
    • Dynamic C / C++ / COM interop : call C++ methods, create C++ objects (and subclass C++ classes from Java!)
    • Straightforward type mappings with good use of generics (including much nicer model for Pointers)
    • Full JNAerator support
    • works on Windows, Linux, MacOS X, Solaris, Android
  2. As for memory copying, I believe JNA supports direct ByteBuffers, so memory copying can be avoided.

So, I still believe that wherever possible, it is better to use JNA or BridJ, and revert to jni if performance is critical, because if you need to call native functions frequently, performance hit is noticeable.

randers
  • 5,031
  • 5
  • 37
  • 64
Denis Tulskiy
  • 19,012
  • 6
  • 50
  • 68
  • 6
    I disagree, JNA has much overhead. Though its convenience is worth using in non time critical code – Gregory Pakosz Jan 15 '10 at 15:57
  • 3
    I'd advise caution before using BridJ for an Android project, to quote directly from its [download page](https://code.google.com/p/bridj/wiki/Download#Android): "BridJ works partially on Android/arm emulators (with the SDK), and __probably even on actual devices (untested).__" – kizzx2 Jan 24 '12 at 03:19
  • well i am using jna and as denis said i call one method which returns me a large byte buffer data of an image from an usb device. But in my case the method depends on an external camera device so until somebody does not capture the picture it has to wait inside that dll. generically this works fine but in many other computer other than mine it automatically returns from the method taking blank data without waiting even a second. I have faced this problems in older computers and the one with usb 3.0. So is it a jna problem? – Jony Dec 26 '12 at 07:29
  • @AshishDonvir: you'd better ask a separate question about it. JNA developers often answer questions here. – Denis Tulskiy Dec 26 '12 at 07:54
  • @DenisTulskiy I'm not sure what exactly is meant by "mapping of C++ classes." Would you care to elaborate? – StockB Jan 10 '13 at 19:10
  • 1
    @StockB: if you have a library with api where you have to pass C++ objects, or call methods on C++ object, JNA can not do that. It can only call vanilla C methods. – Denis Tulskiy Jan 11 '13 at 03:31
  • 2
    As far as I understand, JNI can only call global `JNIEXPORT` functions. I'm currently exploring JavaCpp as an option, which uses JNI, but I don't think vanilla JNI supports this. Is there a way to call C++ member functions using vanilla JNI that I am overlooking? – StockB Jan 28 '13 at 16:33
  • 1
    Please take a look here http://stackoverflow.com/questions/20332472/catch-a-double-hotkey – Incerteza Dec 02 '13 at 16:39
31

It's difficult to answer such a generic question. I suppose the most obvious difference is that with JNI, the type conversion is implemented on the native side of the Java/native border, while with JNA, the type conversion is implemented in Java. If you already feel quite comfortable with programming in C and have to implement some native code yourself, I would assume that JNI won't seem too complex. If you are a Java programmer and only need to invoke a third party native library, using JNA is probably the easiest path to avoid the perhaps not so obvious problems with JNI.

Although I've never benchmarked any differences, I would because of the design, at least suppose that type conversion with JNA in some situations will perform worse than with JNI. For example when passing arrays, JNA will convert these from Java to native at the beginning of each function call and back at the end of the function call. With JNI, you can control yourself when a native "view" of the array is generated, potentially only creating a view of a part of the array, keep the view across several function calls and at the end release the view and decide if you want to keep the changes (potentially requiring to copy the data back) or discard the changes (no copy required). I know you can use a native array across function calls with JNA using the Memory class, but this will also require memory copying, which may be unnecessary with JNI. The difference may not be relevant, but if your original goal is to increase application performance by implementing parts of it in native code, using a worse performing bridge technology seems not to be the most obvious choice.

jarnbjo
  • 33,923
  • 7
  • 70
  • 94
8
  1. You are writing code a few years ago before there was JNA or are targeting a pre 1.4 JRE.
  2. The code you are working with is not in a DLL\SO.
  3. You are working on code that is incompatible with LGPL.

That is only what I can come up with off the top of my head, though I am not a heavy user of either. It also seems like you might avoid JNA if you wanted a better interface than the one they provide but you could code around that in java.

stonemetal
  • 6,111
  • 23
  • 25
  • 9
    I disagree about 2 -- converting static lib to dynamic lib is easy. See my question abput it http://stackoverflow.com/questions/845183/convert-static-windows-library-to-dll – jb. Oct 15 '09 at 12:48
  • 3
    Starting with JNA 4.0, JNA is dual-licensed under both LGPL 2.1 and Apache License 2.0, and which you choose is up to you – sbarber2 Aug 05 '16 at 12:22
8

By the way, in one of our projects, we kept a very small JNI foot print. We used protocol buffers for representing our domain objects and thus had only one native function to bridge Java and C (then of course that C function would call a bunch of other functions).

Ustaman Sangat
  • 1,505
  • 1
  • 14
  • 26
  • 5
    So, instead of a method call we have message passing. I have invested quite a bit of time in JNI and JNA and also BridJ, but pretty soon, they all get a bit too scary. – Ustaman Sangat Apr 06 '12 at 01:04
6

It's not a direct answer and I have no experience with JNA but, when I look at the Projects Using JNA and see names like SVNKit, IntelliJ IDEA, NetBeans IDE, etc, I'm tend to believe it's a pretty decent library.

Actually, I definitely think I would have used JNA instead of JNI when I had to as it indeed looks simpler than JNI (which has a boring development process). Too bad, JNA wasn't released at this time.

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
4

I actually did some simple benchmarks with JNI and JNA.

As others already pointed out, JNA is for convenience. You don't need to compile or write native code when using JNA. JNA's native library loader is also one of the best/easiest to use I've ever seen. Sadly, you can't use it for JNI it seems. (That's why I wrote an alternative for System.loadLibrary() that uses the path convention of JNA and supports seamless loading from the classpath (ie jars).)

The performance of JNA however, can be much worse than that of JNI. I made a very simple test that called a simple native integer increment function "return arg + 1;". Benchmarks done with jmh showed that JNI calls to that function are 15 times faster than JNA.

A more "complex" example where the native function sums up an integer array of 4 values still showed that JNI performance is 3 times faster than JNA. The reduced advantage was probably because of how you access arrays in JNI: my example created some stuff and released it again during each summing operation.

Code and test results can be found at github.

user1050755
  • 11,218
  • 4
  • 45
  • 56
3

If you want JNI performance but are daunted by its complexity, you may consider using tools that generate JNI bindings automatically. For example, JANET (disclaimer: I wrote it) allows you to mix Java and C++ code in a single source file, and e.g. make calls from C++ to Java using standard Java syntax. For example, here's how you'd print a C string to the Java standard output:

native "C++" void printHello() {
    const char* helloWorld = "Hello, World!";
    `System.out.println(#$(helloWorld));`
}

JANET then translates the backtick-embedded Java into the appropriate JNI calls.

2

I investigated JNI and JNA for performance comparison because we needed to decide one of them to call a dll in project and we had a real time constraint. The results have showed that JNI has greater performance than JNA(approximately 40 times). Maybe there is a trick for better performance in JNA but it is very slow for a simple example.

Mustafa Kemal
  • 1,292
  • 19
  • 24
1

Unless I'm missing something, isn't the main difference between JNA vs JNI that with JNA you can't call Java code from native (C) code?

Augusto
  • 11
  • 1
  • 6
    You can. With a callback class that corresponds to a function pointer on the C side. void register_callback(void (*)(const int)); would be mapped to public static native void register_callback(MyCallback arg1); where MyCallback is an interface extending com.sun.jna.Callback with a single method void apply(int value); – Ustaman Sangat Nov 23 '11 at 21:51
  • @Augusto this can be a comment also please – swiftBoy Dec 27 '12 at 12:09
0

In my specific application, JNI proved far easier to use. I needed to read and write continuous streams to and from a serial port -- and nothing else. Rather than try to learn the very involved infrastructure in JNA, I found it much easier to prototype the native interface in Windows with a special-purpose DLL that exported just six functions:

  1. DllMain (required to interface with Windows)
  2. OnLoad (just does an OutputDebugString so I can know when Java code attaches)
  3. OnUnload (ditto)
  4. Open (opens the port, starts read and write threads)
  5. QueueMessage (queues data for output by the write thread)
  6. GetMessage (waits for and returns data received by the read thread since the last call)
Walter Oney
  • 1
  • 1
  • 1