Skip to main content

Calling Java methods from C++

 
In one of my projects, I had the need to call a Java function from a C++ class and somewhat surprisingly it was more complicated than I initially expected it to be. Arguably there are more resources on how to call C++ functions from a Java class then the other way around. Also one needs to ensure that the documentation refers to calling Java from C++ instead of C, as there differences in the function calls. Hence based on my experience here's the solution that I came up with.

Requirements

I wanted a Java class to perform a certain task and return an array of double (primitive type). I would then invoke this Java method from my C++ class and use the values of that double array.

A sample of my Java class
public class Test{ 
    public[] double array; 
    public int size; 
    public double[] getArray() { 
        array = new double[]{1.2,3.2,1.2}; return array; 
    } 
} 

Hurdles and initial mistakes

Initially what I was trying was to invoke the method using the code below which was causing a segmentation fault i.e. segfault (a term we all know and love)

void getArrayFromJava(JNIEnv* env)
{
    jmethodID method;
    jclass testClass = env->FindClass("test");
    method = env->GetMethodID(testClass,"getArray","()Ljava/lang/Object");
    //below is the point in code where the segmentation fault in the jvm occured
    jdoubleArray r = (jdoubleArray)env->CallObjectMethod(testClass,method,NULL);
    return r;
}
At first I thought it was because I was calling an object method directly without instantiating the object, however even when I did change the getArrayFromJava method to a static method, the same segfault occurred.

My Solution

So what did I do? Well, I declare the double array as well as the size(arraySize) of the array as class variables and that are set when instantiating the Java class i.e. via values passed in the constructor.

the java code being called
 class Test{

     public double[] array = null;
     public int arraySize;
     public String str;
     public Test(String value,int val)
     {
        str = value;
        setArray(val);
        arraySize = 3;
     }
     public void setArray(int val)
     {
         double []db = new double[]{val,val,1.4};
         this.array = db;
     }
}
Below is the C++ code that invokes the uses the Java class Test. To keep this post brief and to focus on the main objective of this post, I will not going into details of creating a pointer to the JNIEnv. You could get that info from one of the links in the References used section of this post or those of you reading this post, think that this post is incomplete without it, please let me know and I will see what I can do to add that info here.
void getArrayFromJava(JNIEnv* env)
{
    jclass testClass;
    jobject testObj;
    jmethodID constructor;
    const char* utfChars;
    testClass = env->FindClass("Test");//get the class

    //get the constructor for the java class by using <init>
    constructor = env->GetMethodID(testClass,"<init>","(Ljava/lang/String;I)V");
    jstring stringArgs = env->NewStringUTF("\nTest sample");
    jint intParam = 1;
    testObj = env->NewObject(testClass,constructor,stringArgs,intParam);//instantiate a class object

    //get the array field from the object
    jobject tArr = env->GetObjectField(testObj,env->GetFieldID(testClass,"array","[D"));

    //get the array size field from the object
    jint arraySize = (jint)env->GetIntField(testObj,env->GetFieldID(testClass,"arraySize","I"););

    jdoubleArray *arr = reinterpret_cast<jdoubleArray*>(&tArr); 
    //now we have a pointer to the array and a size which tells us of the number of elements

    double* data = env->GetDoubleArrayElements(*arr,NULL);
    /*accessing a pointer to a double array is now simple and can be done using the information in 'data' and  array size' */
}

References used

http://java.sun.com/docs/books/jni/html/objtypes.html#4013

http://www.codeproject.com/Articles/22881/How-to-Call-Java-Functions-from-C-Using-JNI

http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniexamp.html#run







Comments

Popular posts from this blog

Upload to AWS S3 from Java API

In this post, you will see code samples for how to upload a file to AWS S3 bucket from a Java Spring Boot app. The code you will see here is from one of my open-source repositories on Github, called document-sharing. Problem Let’s say you are building a document sharing app where you allow your users to upload the file to a public cloud solution. Now, let’s say you are building the API for your app with Spring Boot and you are using AWS S3 as your public cloud solution. How would you do that? This blog post contains the code that can help you achieve that. Read more below,  Upload to AWS S3 bucket from Java Spring Boot app - My Day To-Do (mydaytodo.com)

Addressing app review rejections for auto-renewing subscription in-app purchase (iOS)

The ability to know what the weather is like while planning your day is a feature of  My Day To-Do  Pro and as of the last update it’s also a part of the  Lite version . Unlike the Pro version it’s an auto-renewing subscription based  in-app purchase (IAP)  in the Lite version. What means is that when a user purchases it, the user only pays for the subscription duration after which the user will be automatically charged for the next period. Adding an  auto-renewing  subscription based IAP proved to be somewhat challenging in terms of the app store review i.e. the app update was rejected by the App Review team thrice because of missing information about the IAP. Therefore in this post I will share my experiences and knowledge of adding auto-renewing IAP in hopes to save someone else the time that I had to spend on this problem. In-App purchase This year I started adding IAPs to My Day To-Do Lite which lead to learning about different types of IAP...

Serving HTML content in an iOS app that works in iOS 7 and later (using Swift)

As I have mentioned in an earlier post , I really enjoying coding in Swift. Now what am I doing with it? Well I am trying to build an HTML5 app that must work on devices with iOS 7. So in iOS8 apple has introduced a whole bunch of features that facilitate easy communication between web content and lets just call it back-end Swift code, but those features are not in iOS 7. So why do I want to build something that would work in an older OS? well I do not expect existing iOS users to upgrade to iOS 8 straight away and i also know a couple of people who would be very reluctant to upgrade their iPhones to iOS 8. Now in case you do not, you can have a read of the "Working with WebViews" section of this post , to know how to serve HTML content with WebViews. So when I started building my app, I wanted to know: How do I invoke some Swift code from my HTML content? Well the solution to this may feel a little bit "hacky" but it is a solution to achieve this.  The followi...