JNI:在转换后将原始类型转换为对象类型的jobject或SetObjectArrayElement
JNI : convert Primitive type to jobject Or SetObjectArrayElement of Object type after casting
我有以下代码 return 填充原始类型结构元素的对象数组数组,我不知道如何将原始类型转换为 jobject,然后使用 SetObjectArrayElement 方法设置为 ObjectArray ,
这是我的 C 结构信息
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]; };
我的 JNI 代码
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] = '[=11=]';
f_date.day = atoi(temp_date);
mov_mem((char *)from_date + 3, temp_date, 2);
temp_date[2] = '[=11=]';
f_date.month = atoi(temp_date);
mov_mem((char *)from_date+6, temp_date, 4);
temp_date[4] = '[=11=]';
f_date.year = atoi(temp_date);
mov_mem((char *)to_date, temp_date, 2);
temp_date[2] = '[=11=]';
t_date.year = atoi(temp_date);
mov_mem((char *)to_date + 3, temp_date, 2);
temp_date[2] = '[=11=]';
t_date.month = atoi(temp_date);
mov_mem((char *)to_date + 6, temp_date, 4);
temp_date[4] = '[=11=]';
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; }
我得到的错误是
A fatal error has been detected by the Java Runtime Environment:
PC=0x010290e5 处的 SIGSEGV (0xb),pid=4754,tid=4152195952
JRE 版本:7.0_09-b05
Java 虚拟机:Java HotSpot(TM) 客户端虚拟机(23.5-b02 混合模式 linux-x86)
有问题的框架:
V [libjvm.so+0x2a80e5] jni_SetObjectArrayElement+0x1c5
无法写入核心转储。核心转储已被禁用。要启用核心转储,请在再次启动 Java 之前尝试 "ulimit -c unlimited"
包含更多信息的错误报告文件保存为:
/DATA1/home/user1/Myname/myproject/hs_err_pid4754.log
如果您想提交错误报告,请访问:
http://bugreport.sun.com/bugreport/crash.jsp
我的问题是
- 我可以 return Array Of Object array 像上面那样吗
- 如果是,如何将原始类型转换为jobject
上面的 JNI 代码有什么问题....???
谢谢...
您无法通过简单地转换为 jobject
来实现此目的。 C++ 完全不知道 java 自动装箱。您将需要手动实例化适当的 java 对象。
例如,irno
需要转换为 java Long class 的实例(假设 64 位 OS)。为此,您需要:
- 用 FindClass
找到 Long class 的标识符
- 定位其构造函数的标识符,该构造函数接受原始类型 long GetMethodID
- 通过将
irno
作为参数传递给其构造函数 NewObjectA 来创建新的 java 长对象
其他变量必须转换为它们对应的java类型:c++ double 转换为java Double,c++ char[] 转换为java String 或转换为java char[ ] 等等。
如果您打算将大量此类原始对象传入和传出java,那么我建议您使用一些序列化库,例如google protobuf。你在java中填入protobuf message,序列化成字节数组,然后把这个字节数组传入java。在 java 中,你反序列化它并得到漂亮的 java 对象。当你需要添加更多的字段时,你就不需要再写容易出错的JNI代码了。
我有以下代码 return 填充原始类型结构元素的对象数组数组,我不知道如何将原始类型转换为 jobject,然后使用 SetObjectArrayElement 方法设置为 ObjectArray ,
这是我的 C 结构信息
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]; };
我的 JNI 代码
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] = '[=11=]';
f_date.day = atoi(temp_date);
mov_mem((char *)from_date + 3, temp_date, 2);
temp_date[2] = '[=11=]';
f_date.month = atoi(temp_date);
mov_mem((char *)from_date+6, temp_date, 4);
temp_date[4] = '[=11=]';
f_date.year = atoi(temp_date);
mov_mem((char *)to_date, temp_date, 2);
temp_date[2] = '[=11=]';
t_date.year = atoi(temp_date);
mov_mem((char *)to_date + 3, temp_date, 2);
temp_date[2] = '[=11=]';
t_date.month = atoi(temp_date);
mov_mem((char *)to_date + 6, temp_date, 4);
temp_date[4] = '[=11=]';
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; }
我得到的错误是
A fatal error has been detected by the Java Runtime Environment:
PC=0x010290e5 处的 SIGSEGV (0xb),pid=4754,tid=4152195952
JRE 版本:7.0_09-b05 Java 虚拟机:Java HotSpot(TM) 客户端虚拟机(23.5-b02 混合模式 linux-x86) 有问题的框架: V [libjvm.so+0x2a80e5] jni_SetObjectArrayElement+0x1c5
无法写入核心转储。核心转储已被禁用。要启用核心转储,请在再次启动 Java 之前尝试 "ulimit -c unlimited"
包含更多信息的错误报告文件保存为: /DATA1/home/user1/Myname/myproject/hs_err_pid4754.log
如果您想提交错误报告,请访问: http://bugreport.sun.com/bugreport/crash.jsp
我的问题是
- 我可以 return Array Of Object array 像上面那样吗
- 如果是,如何将原始类型转换为jobject
上面的 JNI 代码有什么问题....??? 谢谢...
您无法通过简单地转换为 jobject
来实现此目的。 C++ 完全不知道 java 自动装箱。您将需要手动实例化适当的 java 对象。
例如,irno
需要转换为 java Long class 的实例(假设 64 位 OS)。为此,您需要:
- 用 FindClass 找到 Long class 的标识符
- 定位其构造函数的标识符,该构造函数接受原始类型 long GetMethodID
- 通过将
irno
作为参数传递给其构造函数 NewObjectA 来创建新的 java 长对象
其他变量必须转换为它们对应的java类型:c++ double 转换为java Double,c++ char[] 转换为java String 或转换为java char[ ] 等等。
如果您打算将大量此类原始对象传入和传出java,那么我建议您使用一些序列化库,例如google protobuf。你在java中填入protobuf message,序列化成字节数组,然后把这个字节数组传入java。在 java 中,你反序列化它并得到漂亮的 java 对象。当你需要添加更多的字段时,你就不需要再写容易出错的JNI代码了。