0
votes

I'm have following code to return Array of Object Array filled with struct elements of primitive types , I don't know how to convert primitive types to jobject, and then set to ObjectArray using SetObjectArrayElement method,

Here is my C struct info

struct cheqdtl {
unsigned long irno;
char bank_accno1 [16];
unsigned long bank_id;
unsigned long outlet_id;
char bank_accno [16];
char cheque_num [41];
double deposit_amt;
char chq_date [4]; };

My JNI code

JNIEXPORT jobjectArray JNICALL Java_nativeclass_Jmain_getChequeList (JNIEnv *env,jobject jobj,jint ch,jstring benAccNo,jstring fromDate,jstring toDate){
clientlist *cl = new clientlist();
ShortInt lcount = 0;
int i;
jmp_buf jmpb;
const char *ben_acc_no = env->GetStringUTFChars(benAccNo, NULL);
const char *from_date = env->GetStringUTFChars(fromDate, NULL);
const char *to_date = env->GetStringUTFChars(toDate, NULL);

struct b_date f_date, t_date;
char temp_date[10];

mov_mem((char *)from_date, temp_date, 2);
temp_date[2] = '\0';
f_date.day = atoi(temp_date);
mov_mem((char *)from_date + 3, temp_date, 2);
temp_date[2] = '\0';
f_date.month = atoi(temp_date);
mov_mem((char *)from_date+6, temp_date, 4);
temp_date[4] = '\0';    
f_date.year = atoi(temp_date);

mov_mem((char *)to_date, temp_date, 2);
temp_date[2] = '\0';
t_date.year = atoi(temp_date);
mov_mem((char *)to_date + 3, temp_date, 2);
temp_date[2] = '\0';
t_date.month = atoi(temp_date);
mov_mem((char *)to_date + 6, temp_date, 4);
temp_date[4] = '\0';
t_date.year = atoi(temp_date);

struct cheqdtl *cq_dtl = NULL;
cq_dtl = (struct cheqdtl *)malloc( sizeof( struct cheqdtl) );

cl->get_cheque_list((int)ch,(char *)ben_acc_no, &f_date, &t_date, &cq_dtl, &lcount);

jclass objCls= env->FindClass("java/lang/Object");
if( objCls == NULL )
    return NULL;

jobjectArray outObjArr = env->NewObjectArray( lcount, objCls, NULL );
jmethodID jobjConstrId = env->GetMethodID( objCls, "<init>", "()V" );
if( jobjConstrId == 0)
    return NULL;
jobjectArray rowObjArr ;

if( !lcount )
    return NULL;
for( i = 0; i < lcount; ++i ) {
    rowObjArr = env->NewObjectArray(8, objCls, NULL);
    cout<<"\n Get Array Length:- "<<env->GetArrayLength(rowObjArr)<<endl;   

    std::cout<<cq_dtl[i].irno<<"\n";
    std::cout<<cq_dtl[i].bank_accno1<<"\n";
    std::cout<<cq_dtl[i].bank_id<<"\n";
    std::cout<<cq_dtl[i].outlet_id<<"\n";
    std::cout<<cq_dtl[i].bank_accno<<"\n";
    std::cout<<cq_dtl[i].cheque_num<<"\n";
    std::cout<<cq_dtl[i].deposit_amt<<"\n";
    std::cout<<cq_dtl[i].chq_date<<"\n";

    env->SetObjectArrayElement(rowObjArr, 0, (jobject) cq_dtl[i].irno);
    env->SetObjectArrayElement(rowObjArr, 1, (jobject) cq_dtl[i].bank_accno1);
    env->SetObjectArrayElement(rowObjArr, 2, (jobject) cq_dtl[i].bank_id);
    env->SetObjectArrayElement(rowObjArr, 3, (jobject) cq_dtl[i].outlet_id);
    env->SetObjectArrayElement(rowObjArr, 4, (jobject) cq_dtl[i].bank_accno);
    env->SetObjectArrayElement(rowObjArr, 5, (jobject) cq_dtl[i].cheque_num);
    env->SetObjectArrayElement(rowObjArr, 6, (jobject) cq_dtl[i].deposit_amt);
    env->SetObjectArrayElement(rowObjArr, 7, (jobject) cq_dtl[i].chq_date);

    if( rowObjArr )
        env->SetObjectArrayElement( outObjArr, i, rowObjArr );
    env->DeleteLocalRef( rowObjArr );
}
env->DeleteLocalRef( objCls );
free( cq_dtl );
delete cl;
return outObjArr;      }

The Error I got is

 A fatal error has been detected by the Java Runtime Environment:

SIGSEGV (0xb) at pc=0x010290e5, pid=4754, tid=4152195952

JRE version: 7.0_09-b05 Java VM: Java HotSpot(TM) Client VM (23.5-b02 mixed mode linux-x86 ) Problematic frame: V [libjvm.so+0x2a80e5] jni_SetObjectArrayElement+0x1c5

Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again

An error report file with more information is saved as: /DATA1/home/user1/Myname/myproject/hs_err_pid4754.log

If you would like to submit a bug report, please visit: http://bugreport.sun.com/bugreport/crash.jsp

My questions are

  1. Can I return Array Of Object array like above
  2. If yes how to convert primitive type to jobject

What is wrong with above JNI code ....??? Thank you...

1
It'd be a lot easier to create a Java CheqDtl class with fields like long irno and String bank_accno1, pass that object to your JNI call, and just fill in the fields in that one object: protected static native void FillCheqDtl( CheqDtl dtl);... CheqDtl dtl = new CheqDtl(); FillCheqDtl( dtl );... See docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/…Andrew Henle
I have done with creating class, then fill its value , I just want to give try like this without class...tyShantaram Tupe

1 Answers

1
votes

You can't achieve this by simply converting to jobject. C++ has absolutely no knowledge of java autoboxing. You will need to instantiate appropriate java objects manually.

For example, irno needs to be converted to instance of java Long class (assuming 64-bit OS). In order to do so, you need:

  1. Locate identifier of Long class with FindClass
  2. Locate identifier of its constructor which accepts primitive type long with GetMethodID
  3. Create new java Long object by passing irno as argument to its constructor with NewObjectA

Other variables must be converted to their corresponding java types: c++ double to java Double, c++ char[] to java String or to java char[] and so on.

If you are going to pass a lot of such primitive objects to and from java, then I suggest that you use some serialization library, such as google protobuf. You fill in protobuf message in java, serialize it into byte array and pass this byte array into java. In java, you deserialize it and get nice java object. When you need to add more fields, then you won't need to write any more error-prone JNI code.