Introducing Java Native Access (JNA) – Foreign (Function) Memory API


138. Introducing Java Native Access (JNA)

Java Native Access (JNA) is a brave open-source attempt to address JNI complexity via a more intuitive and easy-to-use API. Being a third-party library, JNA must be added as a dependency in our project:

<dependency>
  <groupId>net.java.dev.jna</groupId>
  <artifactId>jna-platform</artifactId>
  <version>5.8.0</version>
</dependency>

Next, let’s try to call the same sumTwoInt() method from Problem 137. This function is defined in a C native shared library named math.dll and stored in our project in the jna/cpp folder.We start by writing a Java interface that extends the JNA’s Library interface. This interface contains declarations of methods and types that we plan to call from Java and are defined in native code. We write the SimpleMath interface containing the sumTwoInt() declaration as follows:

public interface SimpleMath extends Library {
  long sumTwoInt(int x, int y);
}

Next, we have to instruct JNA to load the math.dll library and generate a concrete implementation of this interface so we can call its methods. For this, we need the jna.library.path system property and the JNA’s Native class as follows:

package modern.challenge;
public class Main {
  public static void main(String[] args) {
    System.setProperty(“jna.library.path”, “./jna/cpp”);
    SimpleMath math = Native.load(Platform.isWindows()
      ? “math” : “NOT_WINDOWS”, SimpleMath.class);
    long result = math.sumTwoInt(3, 9);
    System.out.println(“Result: ” + result);
  }
}

Here, we instruct JNA to load math.dll from jna/cpp via System.setProperty(), but you can also do it from a terminal via –Djna.library.path=jna/cpp.Next, we call Native.load() which takes two arguments. First, it takes the native library name, which in our case is math (without the .dll extension). Second, it takes the Java interface containing the declaration of the methods, which in our case is SimpleMath.class. The load() method returns a concrete implementation of SimpleMath that we use to call the sumTwoInt() method.The JNA Platform helper allows us to provide the name of the native library specific to the current operating system. We have only math.dll for Windows.

Implementing the .cpp and .h files

This time, there is no naming convention from the .cpp and .h files, so let’s name them Arithmetic.cpp and Arithmetic.h (the header file is optional). The source code of Artihmetic.cpp is basically plain C code:

#include <iostream>
#include “Arithmetic.h”
long sumTwoInt(int x, int y) {
  std::cout << “C++: The received arguments are : ” << x <<
     ” and ” << y << std::endl;
  return (long)x + (long)y;
}

As you can see, with JNA, there is no need to patch our code with the JNI-specific bridge code. It is only plain C code. The Arithmetic.h is optional and we can write it as follows:

#ifndef FUNCTIONS_H_INCLUDED
#define FUNCTIONS_H_INCLUDED
  long sumTwoInt(int x, int y);
#endif

Next, we can compile our code.

Leave a Reply

Your email address will not be published. Required fields are marked *