在上一节《C++11 JNI开发中RAII的应用(一)》中我们已经有了一些基本的RAII封装工具,本节就简单了,就是根据需要把一些常用的JNIEnv函数封装成更方便使用的模板函数。
raii_NewGlobalRef
函数顾名思义,就是封装JNIEnv::NewGlobalRef,将一个本地引用的jobject
转为全局引用封装在raii_var
中。
/* 封装JNIEnv::NewGlobalRef 返回jobject对象全局引用(RAII管理) */
template<typename T=jobject,typename TYPE=typename std::conditionalstd::is_same::value,T,jobject>::type>
static raii_var
raii_NewGlobalRef(T localRef) {
static_assert(
std::is_base_of<typename std::remove_pointer::type,
typename std::remove_pointer::type>::value,
"T is not derived from jobject");
return raii_var(
[localRef]()->TYPE {return static_cast(getJNIEnv()->NewGlobalRef(localRef));},
[](TYPE &gref) {getJNIEnv()->DeleteGlobalRef(gref);});
}
在调用时,如果不指定T的类型,则返回的raii_var
类中的类型默认为jobject
,否则
下面所有的模板函数都是这个用法。
raii_FindClass_LocalRef
和raii_FindClass_GlobalRef
,封装了JNIEnv::FindClass,返回字符串name
指定的类名的jclass
对象,raii_FindClass_LocalRef
返回的是本地引用,raii_FindClass_GlobalRef
返回全局引用。
/* 封装JNIEnv::FindClass 返回jclass对象局部引用(RAII管理) */
static raii_var raii_FindClass_LocalRef(const char* name) {
assert(nullptr != name);
return raii_jobject_env(&JNIEnv::FindClass, name);
}
/* 封装JNIEnv::FindClass 返回jclass对象全局引用(RAII管理) */
static raii_var raii_FindClass_GlobalRef(const char* name) {
return raii_NewGlobalRef(raii_FindClass_LocalRef(name).get());
}
比如:
auto jstring_class=raii_FindClass_LocalRef("Ljava/lang/String;");
//返回String类的jclass对象
raii_GetObjectClass
封装JNIEnv::GetObjectClass,返回一个jobject
的jclass
对象
static raii_var raii_GetObjectClass(jobject obj) {
assert(nullptr != obj);
return raii_jobject_env(&JNIEnv::GetObjectClass, obj);
}
raii_CallObjectMethod
封装JNIEnv:CallObjectMethod
//通过methodID调用指定的方法
template<typename T=jobject,typename... Args>
static raii_var raii_CallObjectMethod( jobject obj, jmethodID methodID, Args&&... args) {
return raii_jobject_env(&JNIEnv::CallObjectMethod,obj, methodID,std::forward(args)...);
}
//通过name指定的方法名和sig指定的方法签名调用指定的方法
template<typename T=jobject,typename... Args>
static raii_var raii_CallObjectMethod( jobject obj, const char *name, const char *sig, Args&&... args) {
raii_var clazz=raii_GetObjectClass(obj);
auto methodID = getJNIEnv()->GetMethodID(clazz.get(), name, sig);
assert(nullptr != methodID);
return raii_CallObjectMethod(obj,methodID,std::forward(args)...);
}
raii_NewObject
封装JNIEnv::NewObject有5个重载函数
//通过constructor指定的jmethodID调用指定的构造方法
template<typename T=jobject,typename... Args>
static raii_var raii_NewObject( jclass clazz, jmethodID constructor, Args&&... args) {
return raii_jobject_env(&JNIEnv::NewObject,clazz,constructor,std::forward(args)...);
}
//通过sig指定的构造方法签名来调用指定的构造方法
template<typename T=jobject,typename... Args>
static raii_var raii_NewObject( jclass clazz, const char *sig, Args&&... args) {
assert(nullptr != clazz);
auto constructor = getJNIEnv()->GetMethodID(clazz, "" , nullptr==sig?"void (V)":sig);
assert(nullptr != constructor);
return raii_NewObject(clazz,constructor,std::forward(args)...);
}
//通过class_name指定类名和sig指定的构造方法签名来创建新对象
template<typename T=jobject,typename... Args>
static raii_var raii_NewObject( const char * class_name, const char *sig,Args&&... args) {
return raii_NewObject(raii_FindClass_LocalRef(class_name).get(),sig,std::forward(args)...);
}
//用默认构造方法创建clazz指定的对象
template<typename T=jobject>
static raii_var raii_NewObject( jclass clazz) {
return raii_NewObject(clazz,(const char *)nullptr);
}
//用默认构造方法创建clas_name指定的对象
template<typename T=jobject>
static raii_var raii_NewObject( const char * class_name) {
return raii_NewObject(raii_FindClass_LocalRef(class_name).get());
}
raii_NewByteArray
封装JNIEnv::NewByteArray,创建指定长度的byte数组
static raii_var raii_NewByteArray( jsize len) {
return raii_jobject_env(&JNIEnv::NewByteArray, len);
}
调用raii_NewByteArray
将一个C++的字节数组转为java字节数组(jbyteArray
)
/* 将bytes转成raii_var对象 */
static raii_var tojbytearray(jbyte* bytes, jsize len) {
auto byteArray = raii_NewByteArray(len);
if (nullptr != bytes)
getJNIEnv()->SetByteArrayRegion(byteArray.get(), 0, len, bytes);
return byteArray;
}
raii_NewStringUTF
封装JNIEnv::NewStringUTF,将一个UTF-8编码的字符串转为java String(jstring
)
raii_NewStringUTF
封装JNIEnv::NewString,将一个Unicode 编码的jchar数组转为java String(jstring
)
/* 将UTF-8字符串转成一个raii_var管理的JString对象 */
static raii_var raii_NewStringUTF(const char* pStr) {
return raii_jobject_env(&JNIEnv::NewStringUTF, pStr);
}
/* 将Unicode字符串转成一个raii_var管理的JString对象 */
static raii_var raii_NewString(const jchar* pStr, jsize len) {
return raii_jobject_env(&JNIEnv::NewString, pStr, len);
}
raii_GetObjectField
封装JNIEnv::GetObjectField,返回指定fieldID的对象(jobject
)
/* 封装JNIEnv::GetObjectField 返回T指定的jobject基类对象(RAII管理) */
template<typename T=jobject>
static raii_var raii_GetObjectField(jobject obj, jfieldID fieldID) {
return raii_jobject_env(&JNIEnv::GetObjectField,obj,fieldID);
}
raii_GetObjectArrayElement
封装JNIEnv::GetObjectArrayElement,返回对象数组指定下标的java 对象(jobject
)
/* 封装JNIEnv::GetObjectField 返回T指定的jobject基类对象(RAII管理) */
template<typename T=jobject>
static raii_var raii_GetObjectArrayElement(jobjectArray array, jsize index) {
return raii_jobject_env(&JNIEnv::GetObjectArrayElement,array,index);
}
raii_GetByteArrayElements
封装JNIEnv::GetByteArrayElements,返回java字节数组byte[]
的C++字节数组
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(
[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
封装JNIEnv::GetStringUTFChars,返回java String的UTF-8字符串
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([jstr]()->type {
jboolean isCopy;
auto result=getJNIEnv()->GetStringUTFChars(jstr, &isCopy);
assert(isCopy); // 调用成功断言
return std::move(result);
}, [jstr](type &obj) {getJNIEnv()->ReleaseStringUTFChars(jstr,obj);});
}
throwByName
抛出name指定类名的异常,msg
为异常信息
throwIllegalArgumentException
抛出 java.lang.IllegalArgumentException
异常
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);
}