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













10 comments:

  1. Can you solve one more problem for me?

    "I want to know that whether it is possible to monitor lappy battery adapter's presence or not using java code?

    Some tell that since Java sits on top of the OS, its not possible for java to do that.

    I am designing a software where when laptop's battery is fully charged (100%) then the java app will prompt the user to disconnect the charger. If user does not disconnect the charger, then the app will turn off the lappy after some period of time."

    Thanking you in anticipation...

    ReplyDelete
  2. On linux system you may check files in /proc/acpi/battery for battery information (e.g. /proc/acpi/battery/BAT0/state). You may write a java program to read the data.
    I don't know how can that be done on windows.

    ReplyDelete
  3. great job Nipun!!! congrat's
    I have a problem that look like with your example...In this gist I've a C source that correspond a neural network, I need call the method rede explicated in gist... by Java source code with jna... it will return a float array.
    https://gist.github.com/andregnhoato/7681034

    how step's I need follow? can you help-me?
    In you example you compile your c source, generated a shared lib and then you not reference the lib to load in Java source...

    Cheers

    ReplyDelete
  4. hello, how can I use JNA for C++ Classes and Java Classe:

    //Calculadora.h

    #ifndef CALCULADORA_H
    #define CALCULADORA_H

    #ifdef CALCULADORA_SDK
    #define CALCULADORA_API __declspec(dllexport)
    #else
    #define CALCULADORA_API __declspec(dllimport)
    #endif

    namespace Matematica
    {
    class CALCULADORA_API Calculadora
    {
    public:
    double sumar(double a, double b);
    };
    }

    #endif

    // Calculadora.cpp
    #include "Calculadora.h"

    namespace Matematica
    {
    double Calculadora::sumar(double a, double b)
    {
    return a + b;
    }
    }

    After that, I've compiled and generate dll library with the following commands:

    g++ -c -DCALCULADORA_SDK Calculadora.cpp

    g++ -shared -o Calculadora.dll Calculadora.o -Wl,--out-implib,libCalculadora.a

    Now, I've created my test application as follow:

    //Prueba.cpp

    #include
    #include "Calculadora.h"

    using namespace std;

    int main(int argc, char ** argv)
    {
    Matematica::Calculadora c;

    cout << c.sumar(3,4) << endl;

    return 0;
    }

    After that, I've compiled with the following command:

    g++ -c Prueba.cpp

    g++ -o Prueba.exe Prueba.o -L. -lCalculadora

    I've get a successfull result.

    Now, I create a Interface class on Java Language:

    //Calculadora.java

    package Matematica;

    import com.sun.jna.Library;
    import com.sun.jna.Native;

    public interface Calculadora extends Library {
    Calculadora INSTANCE = (Calculadora) Native.loadLibrary("Calculadora", Calculadora.class);

    double sumar(double a, double b);

    }

    Also, I've created my test class as follow:

    //CalculadoraTest.java

    package Matematica;

    public class CalculadoraTest {

    public static void main(String [] args) {
    Calculadora c = Calculadora.INSTANCE;

    System.out.println(c.sumar(3, 4));
    }
    }

    When I've run the application, I've got the following result:

    Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'sumar': No se encontrĂ³ el proceso especificado.

    at com.sun.jna.Function.(Function.java:208)
    at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:536)
    at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:513)
    at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:499)
    at com.sun.jna.Library$Handler.invoke(Library.java:199)
    at com.sun.proxy.$Proxy0.sumar(Unknown Source)
    at Matematica.CalculadoraTest.main(CalculadoraTest.java:8)

    Please, help me, because I don't know how to solve this issue.


    ReplyDelete
    Replies
    1. It is not easy to call C++ object method using JNA. We need to do a lot of extra work. Hence, it is better and easier to use them through C wrapper routines. Basically, the call "c.sumar(3, 4)" (assuming c is the object) will translate to a-mangled-c++-method-name(address-of-the-object, 3, 4). address-of-the-object is nothing but the "this" pointer. First we need to create the C++ object and here we need to call the C++ object's constructor method and then pass the address of the object (as the first parameter) to the mangled C++ method along with the other parameters. This is really messy, especially when the constructor(s) are inlined.

      If the C++ class method is static, it is somewhat easier as we don't need an object to call it.

      I compiled your sample code on a Linux machine with G++ 4.8.1. I declared the sumar method as static. The sumar method for class Calculadora mangled to _ZN10Matematica11Calculadora5sumarEdd.

      Now I declared the interface as shown below:

      public interface Calculadora extends Library {
      Calculadora INSTANCE = (Calculadora) Native.loadLibrary("Calculadora", Calculadora.class);

      double _ZN10Matematica11Calculadora5sumarEdd(double a, double b);

      }

      and from the Java class CalculadoraTest I called it as shown below:
      System.out.println(Calculadora.INSTANCE._ZN10Matematica11Calculadora5sumarEdd(3,4));

      There are ways to call the constructor methods explicitly( to create the object to work with non-static methods). But that may be incredibly messy. Hence, better to use C wrappers in stead.

      Delete
    2. A good tool for check the assignature of DLL's method is Dependency Walker, use this tool for view all full functions names and the dependencies of yout library.

      Delete
  5. Hi! Thanks for this great tutorial. Could you help me with my code?
    There is a function in a DLL, which gets double* as variable and sends data back through it:

    void leoGetBirdPosition(double *posX, double *posY, double *posZ, double *rotX, double *rotY, double *rotZ);

    In the LeoAPI class I wrote:

    void leoGetBirdPosition(
    Pointer posX,
    Pointer posY,
    Pointer posZ,
    Pointer rotX,
    Pointer rotY,
    Pointer rotZ
    );

    Now is it ok? How can I get the double values?

    ReplyDelete
  6. Hello, is it possible to use your StringByReference source code in a commercial project? If so, what are the conditions? Thank you.

    ReplyDelete