6

I'm reading about Java Native Access and so far i have been able to successfully call C functions from Java.

Is there a way to do the opposite? Googling didnt help much.

2
  • 1
    Using JNI, you can go both ways. I don't know for JNA. Commented Apr 2, 2012 at 21:17
  • Yes you can. please see my answer Commented Jan 14, 2016 at 11:46

4 Answers 4

11

Off course you can! Let's create simple example.

let's create header file header.h. For callback we will use callbackTriger method. getDeviceRandomStatus and randNum is just helper methods to generate random data responses.

#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED

typedef void(*NotificationListener)(char *, int);

void callbackTriger(const NotificationListener l);

void getDeviceRandomStatus(char *answer, int sizeOfChars);

int randNum( int min,  int max);

#endif // HEADER_H_INCLUDED

header.c

#include<stdio.h>
#include "header.h"
#include <stdlib.h>
#include <time.h>

void callbackTriger(const NotificationListener l){
     int size=randNum(1,20);
     char answer[size];
     getDeviceRandomStatus(answer, size);
     (*l)(answer, sizeof(answer));
}

void getDeviceRandomStatus(char *answer, int sizeOfChars){
    int i;
    for(i=0; i<sizeOfChars; i++){
        int i=randNum(0,255);
        answer[i]=i+'0';
    }
}


int randNum( int min,  int max){
    srand ( time(NULL) );
    double scaled = (double)rand()/RAND_MAX;
    int val=(max - min +1)*scaled + min;
    return val;
}

main.c for testing library methods:

#include<stdio.h>
#include <limits.h>
#include <stdlib.h>

int main(void)
{
  int sizeOfChars=randNum(1,10);
  char answer[sizeOfChars];
  getDeviceRandomStatus(answer, sizeOfChars);

  int i;
  for (i = 0; i < sizeof(answer); ++i){
       printf("%d ", answer[i]);
  }

   return 0;
}

Now lets create Shared lib and test it:

cd <path>
gcc -c -Wall -Werror -fpic header.c
gcc -shared -o libHeader.so header.o
gcc main.c -o main -lHeader -L<path> -Wl,-rpath=/home/vq/Desktop
./main

Now we need JAVA classes! Let's go:

  import java.util.Arrays;
    import java.util.logging.Logger;

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

    public class CallBack {

        public static Logger log = Logger.getLogger(CallBack.class.getSimpleName());

        public interface CLibrary extends Library {

            public interface NotificationListener extends Callback {
                void invoke(Pointer val, int lenth);
            }

            public static class NotificationListenerImpl implements NotificationListener {
                @Override
                public void invoke(Pointer val, int lenth) {
                    log.info("returned byte array, size: "+lenth);
                    log.info("java mehtod, callback: " +    Arrays.toString(val.getByteArray(0, lenth)));
                }
            }

            public void callbackTriger(NotificationListener callback);
        }


        static public void main(String argv[]) {

            CLibrary clib = (CLibrary) Native.loadLibrary("<path>/libHeader.so", CLibrary.class);

            // instantiate a callback wrapper instance
            CLibrary.NotificationListenerImpl callbackImpl = new CLibrary.NotificationListenerImpl();

            // pass the callback wrapper to the C library
            clib.callbackTriger(callbackImpl);


        }

    }
Sign up to request clarification or add additional context in comments.

1 Comment

When repeating java main in a loop the java program crahes with stack smashing detected: terminated
2

Looks like you can start the JVM and call functions in Java from C, using the JNI library. Is this what you are after?

1 Comment

I basically want to know if there is a way i can do that using JNA. I have tried with JNI and it works. This is just as a fun of exploring JNA
0

Here's a simple sample. The java code, called ssm/SSMFuse.java calls a C function called littleWorkC, in fuseSSM.c (libfuseSSM.so), which calls a java method called Times10J -- twice and returns the sum of the two calls to the java Times10J method (which just returns 10 times its int argument. (The 'fuse' stuff is because I'm working on a File system in User Space project on Linux)

Here is the output, indented in the code to show the nesting of java calling C calling java:

  java main code, FuseLib = <libfuseSSM.so@134315239349360>
  java main code, callbackImpl = ssm.SSMFuse$Times10J@2c13da15
  java main code, calling littleWorkC in fuseLib, pass it times10J CB
    C code libfuseSSM.so, in littleWorkC 0x7a28bce15fe0
      java code, Times10J.invoke method, arg: 230
    C code, after calling *pT10J callback, sum: 2300.
      java code, Times10J.invoke method, arg: 230
    C code, after calling *pT10J callback, sum: 4600.
  java main code, after littleWorkC, sum = 4600

The first C code line shows that java called C. The deeply indented java code lines are showing that the number 230 was passed to Times10J in java which returns 2300. The second call to Times10J with 230 again caused 2300+2300, or the sum of 4600 to be returned to the java main code.

Here is the complete java code, called ssm/SSMFuse.java:

package ssm;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Callback;


public class SSMFuse {

  public interface FuseLib extends Library {
    // This interface describes the functions in the (libFuseSSM.so) C library
    public int littleWorkC(Times10J callback); 
  } // end of FuseLib interface

  
  // Define the method that C will call here in java
  public static class Times10J implements Callback {
    public int callback(int val) {  // Returns 10 times the value given
      prt("      java code, Times10J.invoke method, arg: " + val);
      return val*10;
    }
  } // end of Times10J class

  
  public static void main(String[] args) {
    @SuppressWarnings("deprecation")
    final FuseLib fuseLib = (FuseLib)Native.loadLibrary("libfuseSSM.so", 
      FuseLib.class);
    prt("  java main code, FuseLib = "+fuseLib);
    
    // Create a callback object 
    Times10J times10JCB = new Times10J();
    prt("  java main code, callbackImpl = "+times10JCB);

    // Call littleWorkC in C, pass the callback 'function pointer' to Times10J
    prt("  java main code, calling littleWorkC in fuseLib, pass it times10J CB");
    int sum = fuseLib.littleWorkC(times10JCB);
    prt("  java main code, after littleWorkC, sum = "+sum+"\n\n");
  } // end of main

  public static void prt(String ln) { System.out.println(ln); }  
} // end of class SSMFuse

Here is the relevant part of the C code in fuseSSM.c:

// Test of calling C from Java and Java from C, using ssm.fuseSSM.java
typedef int(*Times10J)(int);

int littleWorkC(const Times10J pT10J) {
  printf("    C code libfuseSSM.so, in littleWorkC %p\n",
    (void*)pT10J);

  // Call the Times10J method in java, twice, return the sum
  int sum = 0;
  for (int ii=0; ii<2; ii++) {
    sum += (*pT10J)(230);  // Call 'callback' method in Java Times10J class
    printf("    C code, after calling *pT10J callback, sum: %d.\n", sum);
  }
  return sum;
} // end of littleWorkC

Here is the make output in Linux to produce libfuseSSM.so which is copied to /usr/local/lib:

gcc -fPIC -D_FILE_OFFSET_BITS=64 -Wall -g -c fuseSSM.c -lfuse -o fuseSSM.o
gcc -shared fuseSSM.o -o libfuseSSM.so -lfuse

And how the java code is invoked:

java -cp /ssm/class:/ssm/lib/jna-5.12.1.jar ssm.SSMFuse

Note: The whole point of the interface FuseLib extends Library in java is to list the signatures of the functions in the C .so (or .dll)

The class Times10J implements Callback is the implementation of the callback routine, note that only one method/function can be in each Callback class, You can create multiple different Callback classes if you need to have C call several Java functions.

Comments

-4

This doesn't work with JNA, use JNI instead http://en.wikipedia.org/wiki/Java_Native_Interface

2 Comments

Incorrect . it is possible with JNA . I tried it myself and it worked .
Have the Java / C Code if anyone's interested : basically function pointer in C and then JNAerator does all the magic ...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.