基于JNI 实现 嵌套 List 类型参数解析

基于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);
    }
    
}
相关推荐
Hical_W5 分钟前
深入学习CPP17_PMR
c++·学习
A-Jie-Y22 分钟前
JAVA框架-SpringBoot环境搭建指南
java·spring boot
深兰科技30 分钟前
深兰科技与淡水河谷合作推进:矿区示范加速落地
java·人工智能·python·c#·scala·symfony·深兰科技
计算机安禾42 分钟前
【数据结构与算法】第42篇:并查集(Disjoint Set Union)
c语言·数据结构·c++·算法·链表·排序算法·深度优先
码界奇点42 分钟前
基于Spring Boot的前后端分离商城系统设计与实现
java·spring boot·后端·java-ee·毕业设计·源代码管理
一叶飘零_sweeeet44 分钟前
深度剖析:Java 并发三大量难题 —— 死锁、活锁、饥饿全解
java·死锁·活锁·饥饿
IT乐手1 小时前
java 对比分析对象是否有变化
android·java
云烟成雨TD1 小时前
Spring AI Alibaba 1.x 系列【18】Hook 接口和四大抽象类
java·人工智能·spring
Hachi被抢先注册了1 小时前
Docker学习记录
java·云原生·eureka
devilnumber2 小时前
Spring Boot 2 vs Spring Boot 3:50 条核心区别 + 升级优势 + 避坑指南
java·spring boot·springboot升级