summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qjniobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qjniobject.cpp')
-rw-r--r--src/corelib/kernel/qjniobject.cpp135
1 files changed, 87 insertions, 48 deletions
diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp
index 8f3da9a8595..59117bd01d4 100644
--- a/src/corelib/kernel/qjniobject.cpp
+++ b/src/corelib/kernel/qjniobject.cpp
@@ -348,7 +348,10 @@ static inline QByteArray cacheKey(Args &&...args)
return (QByteArrayView(":") + ... + QByteArrayView(args));
}
-typedef QHash<QByteArray, jclass> JClassHash;
+struct JClassHash : QHash<QByteArray, jclass>
+{
+ jmethodID loadClassMethod = 0;
+};
Q_GLOBAL_STATIC(JClassHash, cachedClasses)
Q_GLOBAL_STATIC(QReadWriteLock, cachedClassesLock)
@@ -391,29 +394,22 @@ bool QJniObjectPrivate::isJString(JNIEnv *env) const
*/
static QJniObject getCleanJniObject(jobject object, JNIEnv *env)
{
- if (QJniEnvironment::checkAndClearExceptions(env) || !object) {
- if (object)
- env->DeleteLocalRef(object);
+ if (!object || env->ExceptionCheck())
return QJniObject();
- }
- QJniObject res(object);
- env->DeleteLocalRef(object);
- return res;
+ return QJniObject::fromLocalRef(object);
}
-/*!
- \internal
- \a className must be slash-encoded
-*/
-jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env)
+namespace {
+
+jclass loadClassHelper(const QByteArray &className, JNIEnv *env)
{
Q_ASSERT(env);
QByteArray classNameArray(className);
#ifdef QT_DEBUG
if (classNameArray.contains('.')) {
qWarning("QtAndroidPrivate::findClass: className '%s' should use slash separators!",
- className);
+ className.constData());
}
#endif
classNameArray.replace('.', '/');
@@ -442,21 +438,40 @@ jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env)
if (!clazz) {
// Wrong class loader, try our own
- QJniObject classLoader(QtAndroidPrivate::classLoader());
- if (!classLoader.isValid())
+ jobject classLoader = QtAndroidPrivate::classLoader();
+ if (!classLoader)
return nullptr;
+ if (!cachedClasses->loadClassMethod) {
+ jclass classLoaderClass = env->GetObjectClass(classLoader);
+ if (!classLoaderClass)
+ return nullptr;
+ cachedClasses->loadClassMethod =
+ env->GetMethodID(classLoaderClass,
+ "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+ env->DeleteLocalRef(classLoaderClass);
+ if (!cachedClasses->loadClassMethod) {
+ qCritical("Couldn't find the 'loadClass' method in the Qt class loader");
+ return nullptr;
+ }
+ }
+
// ClassLoader::loadClass on the other hand wants the binary name of the class,
// e.g. dot-separated. In testing it works also with /, but better to stick to
// the specification.
const QString binaryClassName = QString::fromLatin1(className).replace(u'/', u'.');
- jstring classNameObject = env->NewString(reinterpret_cast<const jchar*>(binaryClassName.constData()),
- binaryClassName.length());
- QJniObject classObject = classLoader.callMethod<jclass>("loadClass", classNameObject);
+ jstring classNameObject = env->NewString(binaryClassName.utf16(), binaryClassName.length());
+ jobject classObject = env->CallObjectMethod(classLoader,
+ cachedClasses->loadClassMethod,
+ classNameObject);
env->DeleteLocalRef(classNameObject);
- if (!QJniEnvironment::checkAndClearExceptions(env) && classObject.isValid())
- clazz = static_cast<jclass>(env->NewGlobalRef(classObject.object()));
+ if (classObject && !env->ExceptionCheck()) {
+ clazz = static_cast<jclass>(env->NewGlobalRef(classObject));
+ env->DeleteLocalRef(classObject);
+ }
+ // Clearing the exception is the caller's responsibility (see
+ // QtAndroidPrivate::findClass()) and QJniObject::loadClass{KeepExceptions}
}
if (clazz)
@@ -465,11 +480,32 @@ jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env)
return clazz;
}
+} // unnamed namespace
+
+/*!
+ \internal
+ \a className must be slash-encoded
+*/
+jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env)
+{
+ jclass clazz = loadClassHelper(className, env);
+ if (!clazz)
+ QJniEnvironment::checkAndClearExceptions(env);
+ return clazz;
+}
+
jclass QJniObject::loadClass(const QByteArray &className, JNIEnv *env)
{
return QtAndroidPrivate::findClass(className, env);
}
+jclass QJniObject::loadClassKeepExceptions(const QByteArray &className, JNIEnv *env)
+{
+ return loadClassHelper(className, env);
+}
+
+
+
typedef QHash<QByteArray, jmethodID> JMethodIDHash;
Q_GLOBAL_STATIC(JMethodIDHash, cachedMethodID)
Q_GLOBAL_STATIC(QReadWriteLock, cachedMethodIDLock)
@@ -483,9 +519,6 @@ jmethodID QJniObject::getMethodID(JNIEnv *env,
jmethodID id = isStatic ? env->GetStaticMethodID(clazz, name, signature)
: env->GetMethodID(clazz, name, signature);
- if (QJniEnvironment::checkAndClearExceptions(env))
- return nullptr;
-
return id;
}
@@ -525,7 +558,8 @@ jmethodID QJniObject::getCachedMethodID(JNIEnv *env,
jmethodID id = getMethodID(env, clazz, name, signature, isStatic);
- cachedMethodID->insert(key, id);
+ if (id)
+ cachedMethodID->insert(key, id);
return id;
}
}
@@ -549,9 +583,6 @@ jfieldID QJniObject::getFieldID(JNIEnv *env,
jfieldID id = isStatic ? env->GetStaticFieldID(clazz, name, signature)
: env->GetFieldID(clazz, name, signature);
- if (QJniEnvironment::checkAndClearExceptions(env))
- return nullptr;
-
return id;
}
@@ -583,7 +614,8 @@ jfieldID QJniObject::getCachedFieldID(JNIEnv *env,
jfieldID id = getFieldID(env, clazz, name, signature, isStatic);
- cachedFieldID->insert(key, id);
+ if (id)
+ cachedFieldID->insert(key, id);
return id;
}
}
@@ -1008,15 +1040,15 @@ QJniObject QJniObject::callObjectMethod(const char *methodName, const char *sign
{
JNIEnv *env = jniEnv();
jmethodID id = getCachedMethodID(env, methodName, signature);
- if (id) {
- va_list args;
- va_start(args, signature);
- QJniObject res = getCleanJniObject(env->CallObjectMethodV(d->m_jobject, id, args), env);
- va_end(args);
- return res;
- }
+ va_list args;
+ va_start(args, signature);
+ // can't go back from variadic arguments to variadic templates
+ jobject object = id ? jniEnv()->CallObjectMethodV(javaObject(), id, args) : nullptr;
+ QJniObject res = getCleanJniObject(object, env);
+ va_end(args);
- return QJniObject();
+ QJniEnvironment::checkAndClearExceptions(env);
+ return res;
}
/*!
@@ -1150,7 +1182,7 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId,
*/
/*!
- \fn template <typename T> void QJniObject::setStaticField(const char *className, const char *fieldName, const char *signature, T value);
+ \fn template <typename Ret, typename Type> auto QJniObject::setStaticField(const char *className, const char *fieldName, const char *signature, Type value);
Sets the static field \a fieldName on the class \a className to \a value
using the setter with \a signature.
@@ -1158,7 +1190,7 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId,
*/
/*!
- \fn template <typename T> void QJniObject::setStaticField(jclass clazz, const char *fieldName, const char *signature, T value);
+ \fn template <typename Ret, typename Type> auto QJniObject::setStaticField(jclass clazz, const char *fieldName, const char *signature, Type value);
Sets the static field \a fieldName on the class \a clazz to \a value using
the setter with \a signature.
@@ -1196,19 +1228,19 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId,
*/
/*!
- \fn template <typename T> void QJniObject::setStaticField(const char *className, const char *fieldName, T value)
+ \fn template <typename Ret, typename Type> auto QJniObject::setStaticField(const char *className, const char *fieldName, Type value)
Sets the static field \a fieldName of the class \a className to \a value.
*/
/*!
- \fn template <typename T> void QJniObject::setStaticField(jclass clazz, const char *fieldName, T value)
+ \fn template <typename Ret, typename Type> auto QJniObject::setStaticField(jclass clazz, const char *fieldName, Type value)
Sets the static field \a fieldName of the class \a clazz to \a value.
*/
/*!
- \fn template <typename Klass, typename T> auto QJniObject::setStaticField(const char *fieldName, T value)
+ \fn template <typename Klass, typename Ret, typename Type> auto QJniObject::setStaticField(const char *fieldName, Type value)
Sets the static field \a fieldName of the class \c Klass to \a value.
@@ -1263,11 +1295,16 @@ QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName,
{
JNIEnv *env = QJniEnvironment::getJniEnv();
jfieldID id = getFieldID(env, clazz, fieldName, signature, true);
- return getCleanJniObject(env->GetStaticObjectField(clazz, id), env);
+
+ const auto clearExceptions = qScopeGuard([env]{
+ QJniEnvironment::checkAndClearExceptions(env);
+ });
+
+ return getCleanJniObject(getStaticObjectFieldImpl(env, clazz, id), env);
}
/*!
- \fn template <typename T> void QJniObject::setField(const char *fieldName, const char *signature, T value)
+ \fn template <typename Ret, typename Type> void QJniObject::setField(const char *fieldName, const char *signature, Type value)
Sets the value of \a fieldName with \a signature to \a value.
@@ -1304,14 +1341,16 @@ QJniObject QJniObject::getObjectField(const char *fieldName, const char *signatu
{
JNIEnv *env = jniEnv();
jfieldID id = getCachedFieldID(env, fieldName, signature);
- if (!id)
- return QJniObject();
- return getCleanJniObject(env->GetObjectField(d->m_jobject, id), env);
+ const auto clearExceptions = qScopeGuard([env]{
+ QJniEnvironment::checkAndClearExceptions(env);
+ });
+
+ return getCleanJniObject(getObjectFieldImpl(env, id), env);
}
/*!
- \fn template <typename T> void QJniObject::setField(const char *fieldName, T value)
+ \fn template <typename Ret, typename Type> void QJniObject::setField(const char *fieldName, Type value)
Sets the value of \a fieldName to \a value.