JNI使用过程记录,Java调用C++函数,JNI层使用和实例化Java对象

2023-05-02 15:27:29 浏览数 (2)

近期提供给JAVA应用使用的编解码协议库,需求就是编码的字符串,需要解码为Java对象;回应消息的Java对象,需要编码为指定格式的字符串,把模板代码总结下,主要涉及几个点:

1、在JNI层找到Java对象,及其属性变量的值,然后转换为JNI层的内存数据;

2、在JNI层实例化Java对象,并设置这个Java对象的属性变量,并返回这个Java对象;

示例代码如下:

Java对象 

代码语言:javascript复制
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:

代码语言:javascript复制
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] = {''};
    char description[255]= {''};
    char cryptographic_algorithm[128]= {''};
    int  cryptographic_algorithm_length = 0;
    int  cryptographic_usage_mask = 0;
    char source[128]= {''}; 
      
    //中间省略赋值过程

	
    //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层使用

代码语言:javascript复制
public class CommonResponseMessage{
	
	public int    return_code;
	public int    result_reason;
	public String error_message;
	 
	public String uniq_id;
}

JNI层使用Java对象

代码语言:javascript复制
//输入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:%drn", (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这个函数调用后需要释放内存吗?

0 人点赞