前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++11 JNI开发中RAII的应用(三)--JavaClassMirror

C++11 JNI开发中RAII的应用(三)--JavaClassMirror

作者头像
10km
发布2022-05-07 10:10:26
2610
发布2022-05-07 10:10:26
举报
文章被收录于专栏:10km的专栏10km的专栏

以下是我以前写的将一个C++对象转成java对象的函数toJCodeBean

代码语言:javascript
复制
static jobject toJCodeBean(JNIEnv* env, const code_bean& bean) {
    auto code_bean_class =jni_utilits::raii_FindClass_LocalRef("Lnet/gdface/facedbsdk/local/CodeCacheManager$CodeBean;");
    auto constructor = env->GetMethodID(code_bean_class.get(), "<init>", "()V");
    auto obj = env->NewObject(code_bean_class.get(), constructor);
    auto field_id = env->GetFieldID(code_bean_class.get(), "id", "[B");
    env->SetObjectField(obj, field_id, jni_utilits::tojbytearray((jbyte*) (((&bean.id))), (jsize) ((sizeof(bean.id)))).get());
    auto field_code = env->GetFieldID(code_bean_class.get(), "code", "[B");
    env->SetObjectField(obj, field_code,
    jni_utilits::tojbytearray((jbyte*) &(FACE_CODE_CONVERT(bean.code)), (jsize) sizeof(bean.code)).get());
    auto field_imgMD5 = env->GetFieldID(code_bean_class.get(), "imgMD5", "Ljava/lang/String;");
    env->SetObjectField(obj, field_imgMD5, MD5toJString(bean.imgMD5).get());
    auto field_similarity = env->GetFieldID(code_bean_class.get(), "similarity", "F");
    env->SetFloatField(code_bean_class.get(), field_similarity, (jfloat) (((bean.similarity))));
    return obj;
}

如果这段代码被频繁调用,那么每次都要重复的去调用JNIEnv::FindClass,通过字符串去查找jobject,每次都要调用GetFieldID通过字符串查找获取FieldID。对是一个java class,这都是常量啊,为什么不可以一开始把这些值都记下来,每次使用时直接取这个值就行了? 于是,在前面《C++11 JNI开发中RAII的应用(一)–制作基础工具》《C++11 JNI开发中RAII的应用(二)–JNI函数封装》两节的基础之上,我决定做一个JavaClassMirror类记录一个类的这些常量,用于后面的频繁调用。

代码语言:javascript
复制
/* java类与C++类的镜像,便于操作java对象 */
class JavaClassMirror{
public:
    /* raii_var类变量,java class 的全局引用,JavaClassMirror析构的时候会自动释放全局引用*/
    raii_var<jclass> javaclass;
    /* 类构造函数的 jmethodID  */
    jmethodID  constructor;
    /* 方法名与jfieldID的映射,可以通过方法名查找到对应的jfieldID,不支持重载的多个方法*/
    unordered_map<string,jfieldID> field;
    /* 根据类名,构造函数签名,以及 initializer_list提供的pair<string, string>
     * 初始化类,并将
     */
    JavaClassMirror(string canonicalName, std::pair<string, string> constr,
            std::initializer_list<std::pair<string, string> > field_signature) :
        javaclass(jni_utilits::raii_FindClass_GlobalRef(canonicalName.data())), 
        constructor(jni_utilits::getJNIEnv()->GetMethodID(javaclass.get(), constr.first.data(), constr.second.data())) {
    auto env =jni_utilits::getJNIEnv();
    //根据方法名和签名获取FieldID,加入field映射中
    for (auto node : field_signature) {
        auto f = env->GetFieldID(javaclass.get(), node.first.data(), node.second.data());
        assert(nullptr != f);
        field.emplace(node.first, f);
    }
}
    JavaClassMirror(JavaClassMirror&&)=default;
    //根据不同的数据类型提供统一的SetField/GetField方法
    template<typename T>
    typename std::enable_if<std::is_same<T,jdouble>::value>::type SetField(jobject obj, const char* name, T fieldObj) {
        jni_utilits::getJNIEnv()->SetDoubleField(obj, field.find(name)->second, fieldObj);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T,jfloat>::value>::type SetField(jobject obj,const char* name,T fieldObj){
        jni_utilits::getJNIEnv()->SetFloatField(obj,field.find(name)->second,fieldObj);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T, jlong>::value>::type SetField(jobject obj, const char* name, T fieldObj) {
        jni_utilits::getJNIEnv()->SetLongField(obj, field.find(name)->second, fieldObj);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T, jint>::value>::type SetField(jobject obj, const char* name, T fieldObj) {
        jni_utilits::getJNIEnv()->SetIntField(obj, field.find(name)->second, fieldObj);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T, jshort>::value>::type SetField(jobject obj, const char* name, T fieldObj) {
        jni_utilits::getJNIEnv()->SetShortField(obj, field.find(name)->second, fieldObj);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T, jchar>::value>::type SetField(jobject obj, const char* name, T fieldObj) {
        jni_utilits::getJNIEnv()->SetCharField(obj, field.find(name)->second, fieldObj);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T, jbyte>::value>::type SetField(jobject obj, const char* name, T fieldObj) {
        jni_utilits::getJNIEnv()->SetByteField(obj, field.find(name)->second, fieldObj);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T, jboolean>::value>::type SetField(jobject obj, const char* name, T fieldObj) {
        jni_utilits::getJNIEnv()->SetBooleanField(obj, field.find(name)->second, fieldObj);
    }
    template<typename T>
    typename std::enable_if<std::is_base_of<_jobject,typename std::remove_pointer<T>::type>::value>::type
    SetField(jobject obj, const char* name, T fieldObj) {
        jni_utilits::getJNIEnv()->SetObjectField(obj, field.find(name)->second, fieldObj);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T,jdouble>::value,T>::type GetField(jobject obj,const char* name){
        return jni_utilits::getJNIEnv()->GetDoubleField(obj,field.find(name)->second);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T,jfloat>::value,T>::type GetField(jobject obj,const char* name){
        return jni_utilits::getJNIEnv()->GetFloatField(obj,field.find(name)->second);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T,jlong>::value,T>::type GetField(jobject obj,const char* name){
        return jni_utilits::getJNIEnv()->GetLongField(obj,field.find(name)->second);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T,jint>::value,T>::type GetField(jobject obj,const char* name){
        return jni_utilits::getJNIEnv()->GetIntField(obj,field.find(name)->second);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T,jshort>::value,T>::type GetField(jobject obj,const char* name){
        return jni_utilits::getJNIEnv()->GetShortField(obj,field.find(name)->second);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T,jchar>::value,T>::type GetField(jobject obj,const char* name){
        return jni_utilits::getJNIEnv()->GetCharField(obj,field.find(name)->second);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T,jbyte>::value,T>::type GetField(jobject obj,const char* name){
        return jni_utilits::getJNIEnv()->GetByteField(obj,field.find(name)->second);
    }
    template<typename T>
    typename std::enable_if<std::is_same<T,jboolean>::value,T>::type GetField(jobject obj,const char* name){
        return jni_utilits::getJNIEnv()->GetBooleanField(obj,field.find(name)->second);
    }
    template<typename T>
    typename std::enable_if<std::is_base_of<_jobject,typename std::remove_pointer<T>::type>::value,raii_var<T>>::type
    GetField(jobject obj,const char* name){
        return jni_utilits::raii_GetObjectField<T>(obj,field.find(name)->second);
    }//返回raii_var封装的jobject
};

有了这个类之后,比如我们可以像这样初始化JavaClassMirror

代码语言:javascript
复制
JavaClassMirror mirror(
    "Lnet/gdface/facedbsdk/local/CodeCacheManager$CodeBean;",//类名
    {"<init>", "()V"}, //构造函数
    {
        {"id", "[B"},
        {"code", "[B"},
        {"imgMD5", "Ljava/lang/String;"},
        {"similarity", "F"}
    }//成员变量名及类型签名
    );

最开始那段代码toJCodeBean就可以改成这样了,多么清楚简单。

代码语言:javascript
复制
raii_var<jobject> BeanUtilits::toJCodeBean(const code_bean& bean, JavaClassMirror& mirror) {
    auto var = jni_utilits::raii_NewObject(mirror.javaclass.get(), mirror.constructor);
    auto obj = *var;
    if (nullptr != obj) {
        mirror.SetField(obj, "id", MD5tojbyteArray(bean.id).get());
        mirror.SetField(obj, "code",face_codetojbyteArray(FACE_CODE_CONVERT(bean.code)).get());
        mirror.SetField(obj, "imgMD5", MD5toJString(bean.imgMD5).get());
        mirror.SetField(obj, "similarity", (jfloat) (bean.similarity));
    }
    return var;
}

当然JavaClassMirror功能并不完整,并不能满足所有JNI开发的需要,只是在我的项目中这样做已经够了,自己完全可以按这个思路根据需要把更多的功能封装到这里。到这里关于C++11下JNI开发的相关内容就写完了。后续如果有更多的内容,还可能会继续补充。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-12-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档