Refactor duplicate code for clearing JNI exceptions before returning

Add a private function to handle checking/clearing and deleting the
local reference to jobject before returning a QJniObject.

Task-number: QTBUG-89633
Pick-to: 6.1
Change-Id: I0ea28c8ba4da0bfc1e341c6b4c1f61fecfec87a6
Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io>
This commit is contained in:
Assam Boudjelthia 2021-02-04 13:28:24 +02:00
parent deca7cd730
commit c7bcc51e2c

View File

@ -716,6 +716,27 @@ QJniObject::QJniObject(jobject obj)
env->DeleteLocalRef(cls); env->DeleteLocalRef(cls);
} }
/*!
\brief Get a JNI object from a jobject variant and do the necessary
exception clearing and delete the local reference before returning.
The JNI object can be null if there was an exception.
*/
inline static QJniObject getCleanJniObject(jobject obj)
{
if (!obj)
return QJniObject();
QJniEnvironment env;
if (env.exceptionCheckAndClear()) {
env->DeleteLocalRef(obj);
return QJniObject();
}
QJniObject res(obj);
env->DeleteLocalRef(obj);
return res;
}
/*! /*!
\fn QJniObject::~QJniObject() \fn QJniObject::~QJniObject()
@ -797,19 +818,11 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz,
va_list args) va_list args)
{ {
QJniEnvironment env; QJniEnvironment env;
jobject res = nullptr;
jmethodID id = getMethodID(env, clazz, methodName, signature, true); jmethodID id = getMethodID(env, clazz, methodName, signature, true);
if (id) { if (!id)
res = env->CallStaticObjectMethodV(clazz, id, args); return QJniObject();
if (env.exceptionCheckAndClear()) {
env->DeleteLocalRef(res);
res = nullptr;
}
}
QJniObject obj(res); return getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args));
env->DeleteLocalRef(res);
return obj;
} }
/*! /*!
@ -1150,22 +1163,16 @@ DECLARE_JNI_METHODS(Double, jdouble, "()D")
QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const
{ {
QJniEnvironment env; QJniEnvironment env;
jobject res = nullptr;
jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, signature); jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, signature);
if (id) { if (id) {
va_list args; va_list args;
va_start(args, signature); va_start(args, signature);
res = env->CallObjectMethodV(d->m_jobject, id, args); QJniObject res = getCleanJniObject(env->CallObjectMethodV(d->m_jobject, id, args));
va_end(args); va_end(args);
if (env.exceptionCheckAndClear()) { return res;
env->DeleteLocalRef(res);
res = nullptr;
}
} }
QJniObject obj(res); return QJniObject();
env->DeleteLocalRef(res);
return obj;
} }
/*! /*!
@ -1187,7 +1194,6 @@ QJniObject QJniObject::callStaticObjectMethod(const char *className,
...) ...)
{ {
QJniEnvironment env; QJniEnvironment env;
jobject res = nullptr;
jclass clazz = loadClass(className, env); jclass clazz = loadClass(className, env);
if (clazz) { if (clazz) {
jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className),
@ -1195,18 +1201,13 @@ QJniObject QJniObject::callStaticObjectMethod(const char *className,
if (id) { if (id) {
va_list args; va_list args;
va_start(args, signature); va_start(args, signature);
res = env->CallStaticObjectMethodV(clazz, id, args); QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args));
va_end(args); va_end(args);
if (env.exceptionCheckAndClear()) { return res;
env->DeleteLocalRef(res);
res = nullptr;
}
} }
} }
QJniObject obj(res); return QJniObject();
env->DeleteLocalRef(res);
return obj;
} }
/*! /*!
@ -1221,23 +1222,18 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz,
...) ...)
{ {
QJniEnvironment env; QJniEnvironment env;
jobject res = nullptr;
if (clazz) { if (clazz) {
jmethodID id = getMethodID(env, clazz, methodName, signature, true); jmethodID id = getMethodID(env, clazz, methodName, signature, true);
if (id) { if (id) {
va_list args; va_list args;
va_start(args, signature); va_start(args, signature);
res = env->CallStaticObjectMethodV(clazz, id, args); QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args));
va_end(args); va_end(args);
if (env.exceptionCheckAndClear()) { return res;
env->DeleteLocalRef(res);
res = nullptr;
}
} }
} }
QJniObject obj(res);
env->DeleteLocalRef(res); return QJniObject();
return obj;
} }
/*! /*!
@ -1534,15 +1530,7 @@ QJniObject QJniObject::getStaticObjectField(const char *className,
if (!id) if (!id)
return QJniObject(); return QJniObject();
jobject res = env->GetStaticObjectField(clazz, id); return getCleanJniObject(env->GetStaticObjectField(clazz, id));
if (env.exceptionCheckAndClear()) {
env->DeleteLocalRef(res);
res = nullptr;
}
QJniObject obj(res);
env->DeleteLocalRef(res);
return obj;
} }
/*! /*!
@ -1562,19 +1550,11 @@ QJniObject QJniObject::getStaticObjectField(jclass clazz,
const char *signature) const char *signature)
{ {
QJniEnvironment env; QJniEnvironment env;
jobject res = nullptr;
jfieldID id = getFieldID(env, clazz, fieldName, signature, true); jfieldID id = getFieldID(env, clazz, fieldName, signature, true);
if (id) { if (!id)
res = env->GetStaticObjectField(clazz, id); return QJniObject();
if (env.exceptionCheckAndClear()) {
env->DeleteLocalRef(res);
res = nullptr;
}
}
QJniObject obj(res); return getCleanJniObject(env->GetStaticObjectField(clazz, id));
env->DeleteLocalRef(res);
return obj;
} }
/*! /*!
@ -1693,19 +1673,11 @@ void QJniObject::setField<jobjectArray>(const char *fieldName,
QJniObject QJniObject::getObjectField(const char *fieldName, const char *signature) const QJniObject QJniObject::getObjectField(const char *fieldName, const char *signature) const
{ {
QJniEnvironment env; QJniEnvironment env;
jobject res = nullptr;
jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, signature); jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, signature);
if (id) { if (!id)
res = env->GetObjectField(d->m_jobject, id); return QJniObject();
if (env.exceptionCheckAndClear()) {
env->DeleteLocalRef(res);
res = nullptr;
}
}
QJniObject obj(res); return getCleanJniObject(env->GetObjectField(d->m_jobject, id));
env->DeleteLocalRef(res);
return obj;
} }
/*! /*!
@ -1802,17 +1774,8 @@ DECLARE_JNI_OBJECT_FILEDS(jdoubleArray, "[D")
QJniObject QJniObject::fromString(const QString &string) QJniObject QJniObject::fromString(const QString &string)
{ {
QJniEnvironment env; QJniEnvironment env;
jstring res = env->NewString(reinterpret_cast<const jchar*>(string.constData()), return getCleanJniObject(env->NewString(reinterpret_cast<const jchar*>(string.constData()),
string.length()); string.length()));
if (env.exceptionCheckAndClear()) {
env->DeleteLocalRef(res);
res = nullptr;
}
QJniObject obj(res);
env->DeleteLocalRef(res);
return obj;
} }
/*! /*!