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

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

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类记录一个类的这些常量,用于后面的频繁调用。

/* 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

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

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

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开发的相关内容就写完了。后续如果有更多的内容,还可能会继续补充。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值