基于JNI 实现 嵌套 List 类型参数解析
背景
在前面两篇文章中,我们总结了Java 调用 C/C++ SDK 的几种方案,分享了JNI在实践过程中的一些踩坑点,而在这篇文章将继续分享针对Java List类型及其嵌套类型,我们的JNI如何接收。
分析
如下,是我的的SDK的结构体定义:
c
struct CustomParam{
std::string key;
std::vector<std::string> values;
};
SDK的请求体入参定义如下:
c
struct Request
{
std::string ref_text;
std::vector<CustomParam> word_list;
Request& operator=(const Request &other){
ref_text = other.ref_text;
word_list = other.word_list;
return *this;
}
};
解决
● 根据上面的SDK结构体的相关定义,我们在Java层可以有如下的 类型定义:
cpp
public class CustomParam {
String key = "";
List<String> values = new ArrayList<>();
public String getKey() {
return key;
}
public void setWord(String key) {
this.key = key;
}
public List<String> getValues() {
return values;
}
public void setValues(List<String> values) {
this.values = values;
}
}
● 关于native的方法申明如下:
cpp
public class CustomParamNative {
public static native int starts(ArrayList<Object> customParam);
}
● 根据native方法生成 头部文件
javac -encoding utf8 -h . XXX.java
● 如下为生成的native方法的头部文件
c
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_study_core_jni_CustomParamNative */
#ifndef _Included_com_study_core_jni_CustomParamNative
#define _Included_com_study_core_jni_CustomParamNative
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_study_core_jni_CustomParamNative
* Method: starts
* Signature: (JLjava/lang/String;Ljava/lang/String;F)I
*/
JNIEXPORT jint JNICALL Java_com_study_core_jni_CustomParamNative_starts
(JNIEnv *, jclass, jlong, jstring, jstring, jfloat);
#ifdef __cplusplus
}
#endif
#endif
● 头部文件的具体实现
bash
#include "com_study_core_jni_CustomParamNative.h"
#include <vector>
#undef __request
#define __request Request
#include "stdio.h"
#include "stdlib.h"
JNIEXPORT jint JNICALL Java_com_study_core_jni_CustomParamNative_starts(JNIEnv *env, jclass obj, jstring jni_ref, jobject customParamList)
{
__request request;
CopyString(env, thread->text_buff, jni_ref);
request.ref_text = thread->text_buff.data();
CopyString(env, thread->text_buff, jni_utt);
request.audio_id = thread->text_buff.data();
if (customParamList != NULL)
{
// 获取ArrayList类和对应的方法ID
jclass arrayListClass = env->FindClass("java/util/ArrayList");
jmethodID getMethodID = env->GetMethodID(arrayListClass, "get", "(I)Ljava/lang/Object;");
jmethodID sizeMethodID = env->GetMethodID(arrayListClass, "size", "()I");
// 获取CustomParam类和对应的字段ID
jclass customParamClass = env->FindClass("com/seewo/study/core/bo/CustomParam");
jfieldID wordFieldID = env->GetFieldID(customParamClass, "key", "Ljava/lang/String;");
jfieldID valuesFieldID = env->GetFieldID(customParamClass, "values", "Ljava/util/List;");
// 获取ArrayList的大小
jint size = env->CallIntMethod(customParamList, sizeMethodID);
printf("size = %d\n", size);
// 遍历ArrayList并解析CustomParam对象
for (int i = 0; i < size; i++)
{
// 获取CustomParam对象
jobject customParamObj = env->CallObjectMethod(customParamList, getMethodID, i);
// 获取key字段的值
jstring wordString = (jstring)env->GetObjectField(customParamObj, wordFieldID);
printf("字符 = %c\n", wordString);
jboolean is_copy;
const char *word = env->GetStringUTFChars(wordString, &is_copy);
printf("字符 = %c\n", word);
// 将word和values赋值给C++结构体
// 创建CustomParam结构体对象
CustomParam customParam;
// 将word字段的值赋值给C++结构体
customParam.word = word;
// 获取values字段的值
jobject valuesList = env->GetObjectField(customParamObj, valuesFieldID);
jclass listClass = env->FindClass("java/util/List");
jmethodID toArrayMethodID = env->GetMethodID(listClass, "toArray", "()[Ljava/lang/Object;");
jobjectArray valuesArray = (jobjectArray)env->CallObjectMethod(valuesList, toArrayMethodID);
jsize size = env->GetArrayLength(valuesArray);
std::vector<std::string> values;
for (int j = 0; j < size; j++)
{
jstring valuesString = (jstring)env->GetObjectArrayElement(valuesArray, j);
const char *pron = env->GetStringUTFChars(valuesString, &is_copy);
values.push_back(pron);
env->ReleaseStringUTFChars(valuesString, pron);
env->DeleteLocalRef(valuesString);
}
customParam.values = values;
request.word_list.push_back(customParam);
// 释放资源
env->DeleteLocalRef(customParamObj);
env->ReleaseStringUTFChars(wordString, word);
env->DeleteLocalRef(wordString);
env->DeleteLocalRef(valuesList);
env->DeleteLocalRef(valuesArray);
}
// 释放资源
env->DeleteLocalRef(arrayListClass);
env->DeleteLocalRef(customParamClass);
return ThreadHandleStarts<__request>(request);
}
}