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

C++11 JNI开发中RAII的应用(二)--JNI函数封装

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

在上一节《C++11 JNI开发中RAII的应用(一)》中我们已经有了一些基本的RAII封装工具,本节就简单了,就是根据需要把一些常用的JNIEnv函数封装成更方便使用的模板函数。

raii_NewGlobalRef

raii_NewGlobalRef函数顾名思义,就是封装JNIEnv::NewGlobalRef,将一个本地引用的jobject转为全局引用封装在raii_var中。

代码语言:javascript
复制
    /* 封装JNIEnv::NewGlobalRef 返回jobject对象全局引用(RAII管理) */
    template<typename T=jobject,typename TYPE=typename std::conditional<!std::is_same<T,jobject>::value,T,jobject>::type>
    static raii_var<TYPE>
    raii_NewGlobalRef(T localRef) {
        static_assert(
                std::is_base_of<typename std::remove_pointer<jobject>::type,
                                        typename std::remove_pointer<T>::type>::value,
                "T is not derived from jobject");
        return raii_var<TYPE>(
            [localRef]()->TYPE {return static_cast<TYPE>(getJNIEnv()->NewGlobalRef(localRef));},
            [](TYPE &gref) {getJNIEnv()->DeleteGlobalRef(gref);});
    }

在调用时,如果不指定T的类型,则返回的raii_var类中的类型默认为jobject,否则

下面所有的模板函数都是这个用法。

raii_FindClass_LocalRef & raii_FindClass_GlobalRef

raii_FindClass_LocalRefraii_FindClass_GlobalRef,封装了JNIEnv::FindClass,返回字符串name指定的类名的jclass对象,raii_FindClass_LocalRef 返回的是本地引用,raii_FindClass_GlobalRef返回全局引用。

代码语言:javascript
复制
    /* 封装JNIEnv::FindClass 返回jclass对象局部引用(RAII管理) */
        static raii_var<jclass> raii_FindClass_LocalRef(const char* name) {
        assert(nullptr != name);
        return raii_jobject_env(&JNIEnv::FindClass, name);
    }
    /* 封装JNIEnv::FindClass 返回jclass对象全局引用(RAII管理) */
    static raii_var<jclass> raii_FindClass_GlobalRef(const char* name) {
        return raii_NewGlobalRef<jclass>(raii_FindClass_LocalRef(name).get());
    }

比如:

代码语言:javascript
复制
auto jstring_class=raii_FindClass_LocalRef("Ljava/lang/String;");
//返回String类的jclass对象

raii_GetObjectClass

raii_GetObjectClass封装JNIEnv::GetObjectClass,返回一个jobjectjclass对象

代码语言:javascript
复制
    static raii_var<jclass> raii_GetObjectClass(jobject obj) {
        assert(nullptr != obj);
        return raii_jobject_env(&JNIEnv::GetObjectClass, obj);
    }

raii_CallObjectMethod

raii_CallObjectMethod封装JNIEnv:CallObjectMethod

代码语言:javascript
复制
//通过methodID调用指定的方法
    template<typename T=jobject,typename... Args>
    static raii_var<T> raii_CallObjectMethod( jobject obj, jmethodID methodID, Args&&... args) {
        return raii_jobject_env<T>(&JNIEnv::CallObjectMethod,obj, methodID,std::forward<Args>(args)...);
    }
//通过name指定的方法名和sig指定的方法签名调用指定的方法
    template<typename T=jobject,typename... Args>
    static raii_var<T> raii_CallObjectMethod( jobject obj, const char *name, const char *sig, Args&&... args) {
        raii_var<jclass> clazz=raii_GetObjectClass(obj);
        auto methodID = getJNIEnv()->GetMethodID(clazz.get(), name, sig);
        assert(nullptr != methodID);
        return raii_CallObjectMethod<T>(obj,methodID,std::forward<Args>(args)...);
    }

raii_NewObject

raii_NewObject封装JNIEnv::NewObject有5个重载函数

代码语言:javascript
复制
//通过constructor指定的jmethodID调用指定的构造方法
    template<typename T=jobject,typename... Args>
    static raii_var<T> raii_NewObject( jclass clazz, jmethodID constructor, Args&&... args) {
        return raii_jobject_env(&JNIEnv::NewObject,clazz,constructor,std::forward<Args>(args)...);
    }
//通过sig指定的构造方法签名来调用指定的构造方法
    template<typename T=jobject,typename... Args>
    static raii_var<T> raii_NewObject( jclass clazz, const char *sig, Args&&... args) {
        assert(nullptr != clazz);
        auto constructor = getJNIEnv()->GetMethodID(clazz, "<init>", nullptr==sig?"void (V)":sig);
        assert(nullptr != constructor);
        return raii_NewObject<T>(clazz,constructor,std::forward<Args>(args)...);
    }
//通过class_name指定类名和sig指定的构造方法签名来创建新对象   
    template<typename T=jobject,typename... Args>
    static raii_var<T> raii_NewObject( const char * class_name, const char *sig,Args&&... args) {
        return raii_NewObject<T>(raii_FindClass_LocalRef(class_name).get(),sig,std::forward<Args>(args)...);
    }
//用默认构造方法创建clazz指定的对象
    template<typename T=jobject>
    static raii_var<T> raii_NewObject( jclass clazz) {
        return raii_NewObject<T>(clazz,(const char *)nullptr);
    }
//用默认构造方法创建clas_name指定的对象
    template<typename T=jobject>
    static raii_var<T> raii_NewObject( const char * class_name) {
        return raii_NewObject<T>(raii_FindClass_LocalRef(class_name).get());
    }

raii_NewByteArray

raii_NewByteArray封装JNIEnv::NewByteArray,创建指定长度的byte数组

代码语言:javascript
复制
    static raii_var<jbyteArray> raii_NewByteArray( jsize len) {
        return raii_jobject_env(&JNIEnv::NewByteArray, len);
    }

tojbytearray

调用raii_NewByteArray将一个C++的字节数组转为java字节数组(jbyteArray)

代码语言:javascript
复制
    /* 将bytes转成raii_var<jbyteArray>对象 */
    static raii_var<jbyteArray> tojbytearray(jbyte* bytes, jsize len) {
        auto byteArray = raii_NewByteArray(len);
        if (nullptr != bytes)
            getJNIEnv()->SetByteArrayRegion(byteArray.get(), 0, len, bytes);
        return byteArray;
    }

raii_NewStringUTF&raii_NewString

raii_NewStringUTF封装JNIEnv::NewStringUTF,将一个UTF-8编码的字符串转为java String(jstring) raii_NewStringUTF封装JNIEnv::NewString,将一个Unicode 编码的jchar数组转为java String(jstring)

代码语言:javascript
复制
    /* 将UTF-8字符串转成一个raii_var管理的JString对象 */
    static raii_var<jstring> raii_NewStringUTF(const char* pStr) {
        return raii_jobject_env(&JNIEnv::NewStringUTF, pStr);
    }
    /* 将Unicode字符串转成一个raii_var管理的JString对象 */
    static raii_var<jstring> raii_NewString(const jchar* pStr, jsize len) {
        return raii_jobject_env(&JNIEnv::NewString, pStr, len);
    }

raii_GetObjectField

raii_GetObjectField封装JNIEnv::GetObjectField,返回指定fieldID的对象(jobject)

代码语言:javascript
复制
    /* 封装JNIEnv::GetObjectField 返回T指定的jobject基类对象(RAII管理) */
    template<typename T=jobject>
    static raii_var<T> raii_GetObjectField(jobject obj, jfieldID fieldID) {
        return raii_jobject_env<T>(&JNIEnv::GetObjectField,obj,fieldID);
    }

raii_GetObjectArrayElement

raii_GetObjectArrayElement封装JNIEnv::GetObjectArrayElement,返回对象数组指定下标的java 对象(jobject)

代码语言:javascript
复制
    /* 封装JNIEnv::GetObjectField 返回T指定的jobject基类对象(RAII管理) */
    template<typename T=jobject>
    static raii_var<T> raii_GetObjectArrayElement(jobjectArray array, jsize index) {
        return raii_jobject_env<T>(&JNIEnv::GetObjectArrayElement,array,index);
    }

raii_GetByteArrayElements

raii_GetByteArrayElements封装JNIEnv::GetByteArrayElements,返回java字节数组byte[]的C++字节数组

代码语言:javascript
复制
    static auto raii_GetByteArrayElements(jbyteArray bytes, jint release_mode = JNI_ABORT)
        -> raii_var<decltype(getJNIEnv()->GetByteArrayElements(bytes, nullptr))> {
        using type = decltype(getJNIEnv()->GetByteArrayElements(bytes, nullptr));
        assert(nullptr != bytes);
        return raii_var<type>(
                [bytes]()->type {
                    jboolean isCopy;
                    auto result=getJNIEnv()->GetByteArrayElements(bytes, &isCopy);
                    assert(isCopy); // 调用成功断言
                    return std::move(result);
                },
                [release_mode,bytes](type &obj) {getJNIEnv()->ReleaseByteArrayElements(bytes, obj, release_mode);});
    }

raii_GetStringUTFChars

raii_GetStringUTFChars封装JNIEnv::GetStringUTFChars,返回java String的UTF-8字符串

代码语言:javascript
复制
    static auto raii_GetStringUTFChars(
            jstring jstr) -> raii_var<decltype(getJNIEnv()->GetStringUTFChars(jstr, nullptr))> {
        using type = decltype(getJNIEnv()->GetStringUTFChars(jstr, nullptr));
        assert(nullptr != jstr);
        return raii_var<type>([jstr]()->type {
            jboolean isCopy;
            auto result=getJNIEnv()->GetStringUTFChars(jstr, &isCopy);
            assert(isCopy); // 调用成功断言
                return std::move(result);
            }, [jstr](type &obj) {getJNIEnv()->ReleaseStringUTFChars(jstr,obj);});
    }

throwByName

throwByName抛出name指定类名的异常,msg为异常信息 throwIllegalArgumentException抛出 java.lang.IllegalArgumentException异常

代码语言:javascript
复制
void throwByName(const char* name, const char* msg) {
    auto cls = raii_FindClass_LocalRef(name);
    /* if cls is NULL, an exception has already been thrown */
    if (cls.get() != nullptr) {
        getJNIEnv()->ThrowNew(cls.get(), name);
    } else {
        throw invalid_argument(string("not found java class:").append(name).data());
    }
}
void throwIllegalArgumentException(const char* msg) {
    throwByName("java/lang/IllegalArgumentException", msg);
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-12-03,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • raii_NewGlobalRef
  • raii_FindClass_LocalRef & raii_FindClass_GlobalRef
  • raii_GetObjectClass
  • raii_CallObjectMethod
  • raii_NewObject
  • raii_NewByteArray
  • tojbytearray
  • raii_NewStringUTF&raii_NewString
  • raii_GetObjectField
  • raii_GetObjectArrayElement
  • raii_GetByteArrayElements
  • raii_GetStringUTFChars
  • throwByName
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档