近期提供给JAVA应用使用的编解码协议库,需求就是编码的字符串,需要解码为Java对象;回应消息的Java对象,需要编码为指定格式的字符串,把模板代码总结下,主要涉及几个点:
1、在JNI层找到Java对象,及其属性变量的值,然后转换为JNI层的内存数据;
2、在JNI层实例化Java对象,并设置这个Java对象的属性变量,并返回这个Java对象;
示例代码如下:
Java对象
public class TestKey { public String name; public String desc; public int usage; public String keySpec; public String expire; public String source; public String credential_username; public String credential_password; }
JNI层实例化TestKey:
static jobject get_jobject(JNIEnv *env, const char *object_name){ if (env == NULL || object_name == NULL){ return NULL; } jclass clazz = NULL; jobject jobj = NULL; jmethodID mid_construct = NULL; //1. 获取Person类的Class引用 clazz = env->FindClass(object_name); if(clazz == NULL){ LOGD("clazz null"); return NULL; } //2. 获取类的默认构造函数ID mid_construct = env->GetMethodID(clazz, "<init>", "()V"); if(mid_construct == NULL){ LOGD("construct null"); return NULL; } //3.实例化这个对象 jobj = env->NewObject(clazz, mid_construct); if(jobj == NULL){ LOGD("jobject null"); return NULL; } return jobj; } JNIEXPORT jobject JNICALL Java_com_xxx_kmip_ProtocolUtil_decodeTestKeyRequestMessage (JNIEnv *env, jclass obj, jbyteArray j_input){ jclass clazz = NULL; jobject jobj = NULL; jfieldID fid_name = NULL; jfieldID fid_desc = NULL; jfieldID fid_usage = NULL; jfieldID fid_keySpec = NULL; jfieldID fid_expire = NULL; jfieldID fid_source = NULL; jfieldID fid_credential_name = NULL; jfieldID fid_credential_passwd = NULL; env->GetJavaVM(&javaVM); char* decode_str = (char*)env->GetByteArrayElements(j_input, 0); int length = env->GetArrayLength(j_input); char name[32] = {'\0'}; char description[255]= {'\0'}; char cryptographic_algorithm[128]= {'\0'}; int cryptographic_algorithm_length = 0; int cryptographic_usage_mask = 0; char source[128]= {'\0'}; //中间省略赋值过程 //1. 找到请求Class的引用 clazz = env->FindClass("com/test/api/entity/TestKey"); if(clazz == NULL){ LOGD("clazz null"); return NULL; } //2. 获取实例方法ID和变量ID fid_name = env->GetFieldID(clazz, "name", "Ljava/lang/String;"); fid_keySpec = env->GetFieldID(clazz, "keySpec", "Ljava/lang/String;"); fid_desc = env->GetFieldID(clazz, "desc", "Ljava/lang/String;"); fid_expire = env->GetFieldID(clazz, "expire", "Ljava/lang/String;"); fid_source = env->GetFieldID(clazz, "source", "Ljava/lang/String;"); fid_usage = env->GetFieldID(clazz, "usage", "I"); fid_credential_name = env->GetFieldID(clazz, "credential_username", "Ljava/lang/String;"); fid_credential_passwd = env->GetFieldID(clazz, "credential_password", "Ljava/lang/String;"); if(fid_name==NULL || fid_keySpec==NULL || fid_desc==NULL || fid_source==NULL || fid_usage==NULL){ LOGD("age|name null"); return NULL; } //获取输出对象 jobj = get_jobject(env, "com/test/api/entity/TestKey"); if (jobj == NULL){ return NULL; } //赋值 env->SetIntField(jobj, fid_usage, 2); jstring j_name = env->NewStringUTF(name); env->SetObjectField(jobj, fid_name, j_name); jstring j_desc= env->NewStringUTF(description); env->SetObjectField(jobj, fid_desc, j_desc); jstring j_spec = env->NewStringUTF(cryptographic_algorithm); env->SetObjectField(jobj, fid_keySpec, j_spec); //释放内存 env->ReleaseByteArrayElements(j_input, (jbyte*)decode_str, JNI_ABORT); kmip_free_request_message(&ctx, &req_msg_client); return jobj; }
Java对象,输入到JNI层使用
public class CommonResponseMessage{ public int return_code; public int result_reason; public String error_message; public String uniq_id; }
JNI层使用Java对象
//输入java对象,输出byte[]数组 JNIEXPORT jbyteArray JNICALL Java_com_xxx_ProtocolUtil_encodeTestKeyResponseMessage (JNIEnv *env, jclass obj, jobject j_input, jint op_code){ if (j_input == NULL){ return NULL; } jclass clazz = NULL; jfieldID fid_return_code = NULL; jfieldID fid_uniq_id = NULL; jfieldID fid_error_message = NULL; jfieldID fid_result_reason = NULL; env->GetJavaVM(&javaVM); //1. 获取Class引用 clazz = env->FindClass("com/test/api/entity/CommonResponseMessage"); if(clazz == NULL){ LOGD("clazz null"); return NULL; } //2. 获取实例方法ID和变量ID fid_uniq_id = env->GetFieldID(clazz, "uniq_id", "Ljava/lang/String;"); fid_error_message = env->GetFieldID(clazz, "error_message", "Ljava/lang/String;"); fid_return_code = env->GetFieldID(clazz, "return_code", "I"); fid_result_reason = env->GetFieldID(clazz, "result_reason", "I"); if(fid_uniq_id == NULL || fid_return_code==NULL || fid_error_message==NULL || fid_result_reason == NULL){ LOGD("age|name null"); return NULL; } //3.得到对象值 jint return_code = env->GetIntField(j_input, fid_return_code); printf("return_code:%d\r\n", (int)return_code); if (return_code != 0){ //failed. resp_bi.result_status = KMIP_STATUS_OPERATION_FAILED; jstring j_fid_error_message = (jstring)env->GetObjectField(j_input, fid_error_message); const char* cstr= env->GetStringUTFChars(j_fid_error_message, NULL); //保存cstr env->ReleaseStringUTFChars(j_fid_error_message, cstr); //fid_result_reason jint result_reason = env->GetIntField(j_input, fid_result_reason); }else{ jstring j_fid_uniq_id = (jstring)env->GetObjectField(j_input, fid_uniq_id); const char* cstr= env->GetStringUTFChars(j_fid_uniq_id, NULL); //保存cstr env->ReleaseStringUTFChars(j_fid_uniq_id, cstr); } //….省略编码处理 return result; }
Java 基本类型与方法签名中参数类型和返回值类型的映射关系如下:
内存使用,关于局部引用和全局引用,讲的还是蛮清晰的:http://www.itpub.net/2020/01/02/4987/
Native层返回的jobject对象和引用是否需要在native层销毁,这篇文章有说:jni中的NewStringUTF这个函数调用后需要释放内存吗?
-------------------广告线---------------
项目、合作,欢迎勾搭,邮箱:promall@qq.com
本文为呱牛笔记原创文章,转载无需和我联系,但请注明来自呱牛笔记 ,it3q.com