Java JNA
Explain how to use the Java Native Access library (JRA) to access native libraries. References: Using JNA to Access Native Dynamic Libraries 1. Introduction Sometimes we need to use native code to implement some functionality: Reusing legacy code written in C/C++ or any other language able to create native code. Accessing system-specific functionality not available in the standard Java runtime. Trace-offs: Can’t directly use static libraries Slower when compared to handcrafted JNI code. => JNA today is probably the best available choice to access native code from Java. 2. JNA Project Setup Add JNA dependency to the project’s pom.xml (latest version of jna-platform) <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> <version>5.6.0</version> </dependency> 3. Using JNA Step1: Create a Java interface that extends JNA’s Library interface to describe the methods and types used when calling the target native code. Step2: Pass this interface to JNA which returns a concrete implementation of this interface that we use to invoke native methods. 3.1. Example 1: Calling methods from the C Standard Library CMath.java import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Platform; public interface CMath extends Library { CMath INSTANCE = Native.load(Platform.isWindows() ? "msvcrt" : "c", CMath.class); double cosh(double value); } load() method takes two arguments, the return a concrete implementation of this interface, allowing to call any of its methods. The dynamic lib name The Java interface describing the methods that we’ll use We don’t have to add the .so (Linux) or .dll(Window) extension as they’are implied. Also, for Linux-based systems, we don’t need to specific the lib prefix. Main.java public class Main { public static void main(String[] args) { System.out.println(CMath.INSTANCE.cosh(180)); } } 3.2. Example 2: Basic types Mapping char => byte short => short wchar_t => char int => int long => com.sun.jna.NativeLong long long => long float => float double => double char * => String JNA provides the NativeLong type, which uses the proper type depending on the system’architecture. 3.3. Structures and Unions Given this C struct and union struct foo_t { int field1; int field2; char *field3; }; union foo_u { String foo; double bar; }; Java peer class would be @FieldOrder({"field1","field2","field3"}) public class FooType extends Structure { int field1; int field2; String field3; }; public class MyUnion extends Union { public String foo; public double bar; }; MyUnion u = new MyUnion(); u.foo = "test"; u.setType(String.class); lib.some_method(u); Java requires the @FiledOrder annotation so it can properly serialize data into a memory buffer before using it as an argument to the target method.