简体   繁体   中英

How to return both status and byte[] from C++ to Java

I have a C++ method with the following signature:

int cppGetData(string& data);

It should be called from a Java method.

Version I :

byte[] javaGetData();

Which should return null if cppGetData returns a non zero return code.

I understand that I have to write something like this:

JNIEXPORT jbyteArray JNICALL jniGetData(JNIEnv * env, jobject thisObj) 
(
  string data;
  if (cppGetData(data))
  {
    return NULL;
  }

  jbyteArray jData = env->NewByteArray(data.size());
  env->SetByteArrayRegion(jData, 0, data.size(), (jbyte *)data.c_str());

  return jData;
}

My problem is that I loose the status returned by cppGetData . On the other hand, Java does not have return by reference, so I am puzzled. How do I return byte[] and an integer status?

Of course, I could have a wrapper, something like this:

public class ByteArrayWrapper{
  public byte[] bytes;
}

And then javaGetData becomes:

int javaGetData(ByteArrayWrapper wrapper);

This is awful. Both in terms of the API signature and in terms of the jniGetData method complexity.

Is there a better way?

The closest to what you have that will work is

native static int cppGetData(ByteBuffer bb);

This is not a lot better than what you have in that ByteBuffer is a wrapper for a byte[], but it uses built in class to do it. A limitation is that the underlying byte[] is not resizable but you can make it smaller by setting the limit .

Another option is to use

native static int cppGetData(byte[][] bytes)

This allows you to return a different byte[].

Or you could

int[] num = { 0 };

native static byte[] cppGetData(int[] num)

or update fields of the object like

class CallsCppGetData {
    int num;
    byte[] bytes;

    native void cppGetData(); // sets this.num and this.bytes.
}

The solution to returning more than one value is to use an object.

Either you

  • update multiple fields of the object you are calling the method on.
  • return an object when wraps multiple fields.
  • pass a mutable object to be set. eg you can pass an int[] which has one element.

While creating new classes is awful, so is having a method without than one result. ;)

If passing an object is so a problem, i see only one other solution: have two separate methods

jint prepareData();
jbyteArray getData();

Second one called only if the first one returns zero, as you specified. Of course this solution is not particularly atomic neither thredsafe as it requires storing a persistent data between calls at the C side. Unless you wrap both native calls in synchronized block on Java side. But many ubiquitous frameworks use this technique fearlessly for reporting some common internal state after other function calls. Win32 API GetLastError comes to mind, though that one is threadsafe.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM