Friday, March 30, 2012


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.
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.

// 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();
    }
}
// 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);
    }
}

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);
        }
    }
}