Java native access is an easy way to access native shared
libraries from java without depending on java native interface. JNA's design
aims to provide native access in a natural way with a minimum of effort. It
doesn’t require any generated headers and wrapper to your native library routines
unlike in the case of JNI.
It’s an amazing library and you can get all the details here. Mainly you will need the jna.jar to be used
with your java program to access your native library. Jna.jar includes all the
native libraries which facilitate your java program to use the native routines.
At the heart of JNA lies an foreign function interfacing library libffi.
The java primitive data types to native data types mapping are available here.
The java primitive data types to native data types mapping are available here.
There is a similar library xFunction. But it
supports lesser number of platforms, doesn’t support 64 bit platforms and most
probably development of xFunction is stopped.
Below example is showing how we can call C library
functions. We need to define an interface which extends com.sun.jna.Library and
this will load the C library. Also we need to declare the C library functions
we will be calling from java.
Exmaple 1
Below is the first program demonstrating simple use of JNA. It calls C library routines getpid,getppid and time.
Exmaple 1
Below is the first program demonstrating simple use of JNA. It calls C library routines getpid,getppid and time.
// This exaple is for linux platform only
// Save the code in a file named jnatest.java
// Keep the jna.jar in the same directory
// Then compile it as
// $javac -cp jna.jar jnatest.java
//
// Then run it as below:
// $java -cp .:jna.jar jnatest
import com.sun.jna.Library;
import com.sun.jna.Native;
interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);
int getpid();
int getppid();
long time(long buf[]);
}
public class jnatest {
/**
* @param args
*/
public static void main(String[] args) {
try {
System.out.println(CLibrary.INSTANCE.getpid());
System.out.println(CLibrary.INSTANCE.getppid());
long[] timenul = new long[1];
System.out.println(CLibrary.INSTANCE.time(timenul));
} catch (UnsatisfiedLinkError e) {
System.out.println("Exception" + e);
}
}
}
Exmaple 2
We will now demonstrate how we can pass a reference to a pointer to the native library routines and how an array of structures may be passed to the native data and how a string may be sent to native library by reference.
Below is the C-code for our native library. Save the code in a file test.c and now lets create a shared library.
$gcc -c test.c -fPI
$gcc -shared -fPIC -o libtest.so test.o
// Save this in a file test.c
#include <stdio.h> #include <stdlib.h>
struct mystruct
{
int a;
int b;
} ;
int fun_alloc(struct mystruct **allocint)
{
*allocint = (struct mystruct *) malloc (sizeof(struct mystruct));
printf("Native allocted pointer %p\n", *allocint);
(*allocint)->a = 10000;
(*allocint)->b = 20099;
printf("Struct field has values %d %d \n", (*allocint)->a, (*allocint)->b);
return 0;
}
int fun_free(struct mystruct **ptr)
{
struct mystruct *p = *ptr;
printf("Native Freeing mem %p with val %d %d\n", p, p->a, p->b);
free(p);
return 0;
}
int setvals(struct mystruct **ptr, int num_structs)
{
int i = 0;
if (num_structs < 0)
return 0;
printf("Native recieved the pointer to an array of structures with %d elements\n", num_structs);
while (i < num_structs) {
ptr[i]->a = i;
ptr[i]->b = i + 100;
i++;
}
return 0;
}
int setstring(char *ptr)
{
printf("Native recived string %s \n", ptr);
printf("Native will set first char to 1 in that string");
ptr[0]='1';
return 0;
}
// Code for class MyStruct. Save this in a file MyStruct.java in the current directory
//
import com.sun.jna.Structure;
import com.sun.jna.Pointer;
public class MyStruct extends Structure implements Structure.ByReference {
public int a;
public int b;
public MyStruct() {
}
public MyStruct(Pointer p) {
super(p);
read();
}
}
import com.sun.jna.Pointer;
public class MyStruct extends Structure implements Structure.ByReference {
public int a;
public int b;
public MyStruct() {
}
public MyStruct(Pointer p) {
super(p);
read();
}
}
// End of code for MyStruct.java.
Below is the code for passing a String by reference to native C library
// This is a class that facilitates passing a String by reference to
// C library routines so that the string may be modified by the C
// routine and the modifications is reflected on JAVA side as well
// Save this in a file StringByReference.java in current directory
import com.sun.jna.ptr.ByReference;
public class StringByReference extends ByReference {
public StringByReference() {
this(0);
}
public StringByReference(int size) {
super(size < 4 ? 4 : size);
getPointer().clear(size < 4 ? 4 : size);
}
public StringByReference(String str) {
super(str.length() < 4 ? 4 : str.length() + 1);
setValue(str);
}
private void setValue(String str) {
getPointer().setString(0, str);
}
public String getValue() {
return getPointer().getString(0);
}
}
// C library routines so that the string may be modified by the C
// routine and the modifications is reflected on JAVA side as well
// Save this in a file StringByReference.java in current directory
import com.sun.jna.ptr.ByReference;
public class StringByReference extends ByReference {
public StringByReference() {
this(0);
}
public StringByReference(int size) {
super(size < 4 ? 4 : size);
getPointer().clear(size < 4 ? 4 : size);
}
public StringByReference(String str) {
super(str.length() < 4 ? 4 : str.length() + 1);
setValue(str);
}
private void setValue(String str) {
getPointer().setString(0, str);
}
public String getValue() {
return getPointer().getString(0);
}
}
Below is code for jnatest2.java
//Code for calling our library routines
//Save this code in a file jnatest2.java
// This exaple is for linux platform only
// Save the code in a file named jnatest.java
// Keep the jna.jar in the same directory
// Then compile it as
// $javac -cp .:jna.jat MyStruct.java
// $javac -cp .:jna.jar jnatest2.java
//
// Then run it as below:
// $java -cp .:jna.jar jnatest2
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
interface DLibrary extends Library {
DLibrary INSTANCE = (DLibrary) Native.loadLibrary("mytest", DLibrary.class);
int fun_alloc(PointerByReference p);
int fun_free(PointerByReference p);
int setstring(StringByReference str);
int setvals(MyStruct[] mstructs, int sizeofarray);
}
public class jnatest2 {
/**
* @param args
*/
public static void main(String[] args) {
try {
int x;
PointerByReference pref = new PointerByReference();
x = DLibrary.INSTANCE.fun_alloc(pref);
Pointer ptr = pref.getValue();
MyStruct mys = new MyStruct(ptr);
System.out.println("Java got from native "
+ Pointer.nativeValue(ptr) + " " + mys.a + " " + mys.b);
DLibrary.INSTANCE.fun_free(pref);
StringByReference mystring = new StringByReference("ZZZZZ");
DLibrary.INSTANCE.setstring(mystring);
System.out.println(mystring.getValue());
MyStruct[] mystructs = new MyStruct[10];
x = 0;
while (x < 10) {
mystructs[x] = new MyStruct();
x++;
}
DLibrary.INSTANCE.setvals(mystructs, 10);
x = 0;
while (x < 10) {
System.out.println("Struct no " + x + " values " + mystructs[x].a
+ " " + mystructs[x].b);
x++;
}
} catch (UnsatisfiedLinkError e) {
System.out.println("Exception" + e);
}
}
}
// Save the code in a file named jnatest.java
// Keep the jna.jar in the same directory
// Then compile it as
// $javac -cp .:jna.jat MyStruct.java
// $javac -cp .:jna.jar jnatest2.java
//
// Then run it as below:
// $java -cp .:jna.jar jnatest2
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
interface DLibrary extends Library {
DLibrary INSTANCE = (DLibrary) Native.loadLibrary("mytest", DLibrary.class);
int fun_alloc(PointerByReference p);
int fun_free(PointerByReference p);
int setstring(StringByReference str);
int setvals(MyStruct[] mstructs, int sizeofarray);
}
public class jnatest2 {
/**
* @param args
*/
public static void main(String[] args) {
try {
int x;
PointerByReference pref = new PointerByReference();
x = DLibrary.INSTANCE.fun_alloc(pref);
Pointer ptr = pref.getValue();
MyStruct mys = new MyStruct(ptr);
System.out.println("Java got from native "
+ Pointer.nativeValue(ptr) + " " + mys.a + " " + mys.b);
DLibrary.INSTANCE.fun_free(pref);
StringByReference mystring = new StringByReference("ZZZZZ");
DLibrary.INSTANCE.setstring(mystring);
System.out.println(mystring.getValue());
MyStruct[] mystructs = new MyStruct[10];
x = 0;
while (x < 10) {
mystructs[x] = new MyStruct();
x++;
}
DLibrary.INSTANCE.setvals(mystructs, 10);
x = 0;
while (x < 10) {
System.out.println("Struct no " + x + " values " + mystructs[x].a
+ " " + mystructs[x].b);
x++;
}
} catch (UnsatisfiedLinkError e) {
System.out.println("Exception" + e);
}
}
}