1

I have problem with JNI. I would like to call getter (over JNI) returning two dimensional array and process this array in C/C++.

In Java, I've implemented following class:

package eu.cbridge;
...

public class LDIContainer {
    private double[][] doubleData;   
    ...

    public double[][] getDoubleData() {
       return doubleData;
   }
   ...
}

In the C/C++, following native method has been implemented:

JNIEXPORT void JNICALL Java_eu_cbridge_CWrapper_transferData__Leu_cbridge_LDIContainer
   (JNIEnv *env, jobject, jobject) {

   //Get class identifier 
   jclass cls = env->FindClass("eu/cbridge/LDIContainer");

   // Get method ID 
   jmethodID mid = env->GetMethodID(cls, "getDoubleData", "()[[D");

   // Call Java method
   jobject mvdata = env->CallObjectMethod(cls, mid); // Causes an access violation in C!!!

   ...

   }

Further, I would like to process returned two dimensional array. However, I can access class (cls) and get jmethodID (mid). When I call the method, I get access violation exception :(.

Does anybody know how to get two dimensional array from Java's object by using object's getter?

Martin
  • 19
  • 1
  • 1
    Java only has one-dimensional arrays. You have an array of arrays of double on the Java side. On the JNI side, there are primitive arrays so you have an array of double arrays. – Tom Blodget Oct 04 '17 at 16:33

3 Answers3

0

I would flatten your 2d array to 1d and than send it. It should be more performant than sending each row individually.

Convert a 2D array into a 1D array

schorsch312
  • 5,553
  • 5
  • 28
  • 57
0

Your're calling CallObjectMethod with a Java class instead of a Java object:

//Get class identifier 
jclass cls = env->FindClass("eu/cbridge/LDIContainer");

// Get method ID 
jmethodID mid = env->GetMethodID(cls, "getDoubleData", "()[[D");

// Call Java method
jobject mvdata = env->CallObjectMethod(cls, mid); // Causes an access violation in C!!!

Yes, I bet that does cause an access violation. See Calling a java method from c++ in Android

You haven't provided details (and some would say you deserve a downvote or two for that...), and the code you put in your question won't even compile (and even more would say you deserve a dozen more downvotes for posting code that won't even compile...), but I suspect one of the jobject objects you pass to your method is an object of the proper class that contains your two-dimensional array.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
0

You need to decompose outer array. In JNI you have support for 1D arrays only. After moving to higher dimensions you have to retrieve content form objects and go down as long as you have more than 1D. Take a look below:

#include <stdio.h>
#include "jni.h"
#include "recipeNo039_PassArray2D.h"

JNIEXPORT int JNICALL Java_recipeNo039_PassArray2D_displayArray2D
  (JNIEnv *env, jclass obj) {

  /* Get objarg's class - objarg is the one we pass from
     Java */
  jclass cls = (*env)->GetObjectClass(env, obj);

  /* Remember that you can alway get method signature using javap tool
     > javap -classpath target -s -p recipeNo039.PassArray2D | grep -A +1 getDoubleData
         public double[][] getDoubleData();
           descriptor: ()[[D
  */

  jmethodID mid =
    (*env)->GetMethodID(env, cls, "getDoubleData", "()[[D");

  /* We have to make sure that method exists */
  if (mid == NULL) {
    return -1; /* method not found */
  }

  /* Now, it's time for getting array of arrays */
  jobject objArray = (*env)->CallObjectMethod(env, obj, mid);

  /* We will iterate over the array so we can get into next array */
  int arraySize = (*env)->GetArrayLength(env, objArray);

  /* We want to go over all elements (all sub arrays) */
  for (int i=0; i < arraySize; i++)
  {
    jdoubleArray array = (*env)->GetObjectArrayElement(env, objArray, i);

    /* get size of the array */
    jsize len = (*env)->GetArrayLength(env, array);

    /* get the body of array; it will be referecende by C pointer */
    jdouble *body = (*env)->GetDoubleArrayElements(env, array, 0);

    /* do some stuff */
    for(int p=0; p < len; p++) {
      printf("Double value [%d;%d]: %f\n", i, p, body[p]);
    }

    /* release body when you decide it is no longer needed */
    (*env)->ReleaseDoubleArrayElements(env, array, body, 0);
  }

  return 0;

}

At first, you need to get object that represents Array of Arrays. Then, you have to iterate over all it's elements and retrieve content.

You can find full sample code here: recipeNo039

Oo.oO
  • 12,464
  • 3
  • 23
  • 45