How to receive a set<String> returned by java method in C++ JNI, can we Convert jobject to set<String>?

1.1k views Asked by At

I am calling an instance method of Java class from C++ using JNI. My Java's method return set and I need to catch this in C++.Can someone please help?

My Java method look like below.

@Override
public Set<String> getRealmRights() 
{
     Set<String> realmRights = new HashSet<>();
     -----------------
     -----------------
     return realmRights;
}

I am invoking the method from C++ like below.

jmethodID getRealmRightsMethodId = env->GetMethodID(keycloakAdapterApplicationClassId, "getRealmRights", "()Ljava/util/Set;");
if(getRealmRightsMethodId != nullptr)
{
    jobject rights = (jobject ) env->CallObjectMethod(keycloakAdapterApplication, getRealmRightsMethodId);
    //@ this stage I want to read the information from jobject,Please help?
}

I am getting method id correctly and even able to execute the method.

I tried to type cast jobject in set but failed. Can I directly catch this in a set OR can i convert jobject into set ?

I want to print the information returned by java function.Please help?

1

There are 1 answers

0
Oo.oO On BEST ANSWER

You have to access Set class methods and retrieve objects stored inside collection.

I don't have out of the box sample for sets, but it will be very similar to code that you can find here:

https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo037

What you need to do, is to get methods from Set object using GetMethodID and then, call them.

This way, you can descent to data stored inside Set. In your case, you have to:

  • call method GetMethodID (and pass Set object into it) to get Iterator from Set

https://docs.oracle.com/javase/7/docs/api/java/util/Set.html#iterator()

  • call method GetMethodID for object of class Iterator so you can get two methods: hasNext and next

  • then, you have to iterate over Set using the Iterator and retrieve elements one by one (they will be of jobjects type)

You can also take a look here:

https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo042

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

  /* Use javap to get propper descriptor
     > javap -s -p java.util.Set | grep -A 1 toArray
         public abstract java.lang.Object[] toArray();
           descriptor: ()[Ljava/lang/Object;
  */

  jmethodID midToArray =
    (*env)->GetMethodID(env, clsSet, "toArray", "()[Ljava/lang/Object;");

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

  /* Once we have method, we can call "toArray" and this way
     get array of all keys */
  jobjectArray arrayOfElements = (*env)->CallObjectMethod(env, objarg, midToArray);

  /* We will iterate over the array so we can get value for each key */
  int arraySize = (*env)->GetArrayLength(env, arrayOfElements);

  /* We want to go over all elements (all keys) */
  for (int i=0; i < arraySize; i++)
  {
    /* First, we need to get key value from array of all keys */
    jstring obj = (*env)->GetObjectArrayElement(env, arrayOfElements, i);
    const char* c_string = (*env)->GetStringUTFChars(env, obj, 0);

    /* We can print values passed to C from Java */
    printf("[value] = [%s]\n", c_string);

    /* Make sure to release local stuff */
    (*env)->ReleaseStringUTFChars(env, obj, c_string);

  }