javavisual-c++java-native-interfacejnienv

Java jbytearray access in c (JNI)


I have a set of java classes that I need at my job to be ran in C/C++.

And, since I am fairly new to java, I am taking it one step at a time. I've gotten to be able to call java with string, int double etc, but the end results will be getting a byte array back (a pdf document) so I tried sending back a simple two element byte array.

Here is the java:

public class ReturnData
{
    int returnValue;
    String Log;
    Byte[] data = new Byte[2];

     public ReturnData(int nRetVal, String szLog)
     {
         this.data[0] = 100;
         this.data[1] = 12;
         this.returnValue = nRetVal;
         this.Log = szLog;
     }
}

and here is the c++ code (JNI initialization removed. It works for simple types so ...)

jbyteArray jbyteData = (jbyteArray)jniEnvironment->GetObjectField(jobjRetData,
    jniEnvironment->GetFieldID(clsReturn, "data", "Ljava/lang/ByteArray;"));

And now anytime I access the jbyteData element, such as:

jsize len = jniEnvironment->GetArrayLength(jbyteData);

I get an Exception

System.AccessViolationException was unhandled
Message: Attempted to read or write protected memory. This is often an indication that other 
memory is corrupt.

Solution

  • Try to change the field Byte[] data = new Byte[2]; to byte[] data = new byte[2];

    Then in your JNI method use GetFieldID(clsReturn, "data", "[B"));

    Edit: To be able to get the internal signature of each type ([B for byte[] in your case) you can declare the field you want to a class (let's call it Test), compile it and then run javap -s Test. It produces an output like below:

    Compiled from "SimpleMain.java"
    public class SimpleMain extends java.lang.Object{
    public byte[] data;
      Signature: [B            // <-- signature shows the internal type 
    public SimpleMain();
      Signature: ()V
    public static void main(java.lang.String[]);
      Signature: ([Ljava/lang/String;)V
    }