diff options
-rw-r--r-- | src/corelib/kernel/qjnienvironment.h | 8 | ||||
-rw-r--r-- | src/corelib/kernel/qjniobject.cpp | 709 | ||||
-rw-r--r-- | src/corelib/kernel/qjniobject.h | 672 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp | 26 |
4 files changed, 722 insertions, 693 deletions
diff --git a/src/corelib/kernel/qjnienvironment.h b/src/corelib/kernel/qjnienvironment.h index a9a3e99097..69a24cbe18 100644 --- a/src/corelib/kernel/qjnienvironment.h +++ b/src/corelib/kernel/qjnienvironment.h @@ -44,12 +44,6 @@ #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) #include <jni.h> -#else -class JNIEnv; -class JNINativeMethod; -class JavaVM; -class jclass; -#endif QT_BEGIN_NAMESPACE @@ -82,4 +76,6 @@ private: QT_END_NAMESPACE +#endif + #endif // QJNI_ENVIRONMENT_H diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp index 418a404bb4..dbca5321a1 100644 --- a/src/corelib/kernel/qjniobject.cpp +++ b/src/corelib/kernel/qjniobject.cpp @@ -39,11 +39,11 @@ #include "qjniobject.h" -#include "qjnienvironment.h" #include "qjnihelpers_p.h" -#include <QtCore/QReadWriteLock> -#include <QtCore/QHash> +#include <QtCore/qbytearray.h> +#include <QtCore/qhash.h> +#include <QtCore/qreadwritelock.h> QT_BEGIN_NAMESPACE @@ -286,6 +286,35 @@ QT_BEGIN_NAMESPACE Returns true if \a o1 holds a reference to a different object than \a o2. */ +class QJniObjectPrivate +{ +public: + QJniObjectPrivate() = default; + ~QJniObjectPrivate() { + QJniEnvironment env; + if (m_jobject) + env->DeleteGlobalRef(m_jobject); + if (m_jclass && m_own_jclass) + env->DeleteGlobalRef(m_jclass); + } + + friend jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env); + static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded = false) + { + return QJniObject::loadClass(className, env, binEncoded); + } + + static QByteArray toBinaryEncClassName(const QByteArray &className) + { + return QJniObject::toBinaryEncClassName(className); + } + + jobject m_jobject = nullptr; + jclass m_jclass = nullptr; + bool m_own_jclass = true; + QByteArray m_className; +}; + static inline QLatin1String keyBase() { return QLatin1String("%1%2:%3"); @@ -304,11 +333,6 @@ typedef QHash<QString, jclass> JClassHash; Q_GLOBAL_STATIC(JClassHash, cachedClasses) Q_GLOBAL_STATIC(QReadWriteLock, cachedClassesLock) -static QByteArray toBinaryEncClassName(const QByteArray &className) -{ - return QByteArray(className).replace('/', '.'); -} - static jclass getCachedClass(const QByteArray &classBinEnc, bool *isCached = nullptr) { QReadLocker locker(cachedClassesLock); @@ -321,9 +345,14 @@ static jclass getCachedClass(const QByteArray &classBinEnc, bool *isCached = nul return found ? it.value() : 0; } -inline static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded = false) +QByteArray QJniObject::toBinaryEncClassName(const QByteArray &className) +{ + return QByteArray(className).replace('/', '.'); +} + +jclass QJniObject::loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded) { - const QByteArray &binEncClassName = binEncoded ? className : toBinaryEncClassName(className); + const QByteArray &binEncClassName = binEncoded ? className : QJniObject::toBinaryEncClassName(className); bool isCached = false; jclass clazz = getCachedClass(binEncClassName, &isCached); @@ -357,11 +386,11 @@ typedef QHash<QString, jmethodID> JMethodIDHash; Q_GLOBAL_STATIC(JMethodIDHash, cachedMethodID) Q_GLOBAL_STATIC(QReadWriteLock, cachedMethodIDLock) -static inline jmethodID getMethodID(JNIEnv *env, +jmethodID QJniObject::getMethodID(JNIEnv *env, jclass clazz, const char *name, const char *signature, - bool isStatic = false) + bool isStatic) { jmethodID id = isStatic ? env->GetStaticMethodID(clazz, name, signature) : env->GetMethodID(clazz, name, signature); @@ -372,12 +401,17 @@ static inline jmethodID getMethodID(JNIEnv *env, return id; } -static jmethodID getCachedMethodID(JNIEnv *env, - jclass clazz, - const QByteArray &className, - const char *name, - const char *signature, - bool isStatic = false) +void QJniObject::callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const +{ + env->CallVoidMethodV(d->m_jobject, id, args); +} + +jmethodID QJniObject::getCachedMethodID(JNIEnv *env, + jclass clazz, + const QByteArray &className, + const char *name, + const char *signature, + bool isStatic) { if (className.isEmpty()) return getMethodID(env, clazz, name, signature, isStatic); @@ -407,15 +441,21 @@ static jmethodID getCachedMethodID(JNIEnv *env, } } +jmethodID QJniObject::getCachedMethodID(JNIEnv *env, const char *name, + const char *signature, bool isStatic) const +{ + return QJniObject::getCachedMethodID(env, d->m_jclass, d->m_className, name, signature, isStatic); +} + typedef QHash<QString, jfieldID> JFieldIDHash; Q_GLOBAL_STATIC(JFieldIDHash, cachedFieldID) Q_GLOBAL_STATIC(QReadWriteLock, cachedFieldIDLock) -static inline jfieldID getFieldID(JNIEnv *env, - jclass clazz, - const char *name, - const char *signature, - bool isStatic = false) +jfieldID QJniObject::getFieldID(JNIEnv *env, + jclass clazz, + const char *name, + const char *signature, + bool isStatic) { jfieldID id = isStatic ? env->GetStaticFieldID(clazz, name, signature) : env->GetFieldID(clazz, name, signature); @@ -426,12 +466,12 @@ static inline jfieldID getFieldID(JNIEnv *env, return id; } -static jfieldID getCachedFieldID(JNIEnv *env, - jclass clazz, - const QByteArray &className, - const char *name, - const char *signature, - bool isStatic = false) +jfieldID QJniObject::getCachedFieldID(JNIEnv *env, + jclass clazz, + const QByteArray &className, + const char *name, + const char *signature, + bool isStatic) { if (className.isNull()) return getFieldID(env, clazz, name, signature, isStatic); @@ -461,9 +501,17 @@ static jfieldID getCachedFieldID(JNIEnv *env, } } +jfieldID QJniObject::getCachedFieldID(JNIEnv *env, + const char *name, + const char *signature, + bool isStatic) const +{ + return QJniObject::getCachedFieldID(env, d->m_jclass, d->m_className, name, signature, isStatic); +} + jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env) { - const QByteArray &classDotEnc = toBinaryEncClassName(className); + const QByteArray &classDotEnc = QJniObjectPrivate::toBinaryEncClassName(className); bool isCached = false; jclass clazz = getCachedClass(classDotEnc, &isCached); @@ -489,29 +537,11 @@ jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env) } if (!clazz) // We didn't get an env. pointer or we got one with the WRONG class loader... - clazz = loadClass(classDotEnc, QJniEnvironment().jniEnv(), true); + clazz = QJniObjectPrivate::loadClass(classDotEnc, QJniEnvironment().jniEnv(), true); return clazz; } -class QJniObjectPrivate -{ -public: - QJniObjectPrivate() = default; - ~QJniObjectPrivate() { - QJniEnvironment env; - if (m_jobject) - env->DeleteGlobalRef(m_jobject); - if (m_jclass && m_own_jclass) - env->DeleteGlobalRef(m_jclass); - } - - jobject m_jobject = nullptr; - jclass m_jclass = nullptr; - bool m_own_jclass = true; - QByteArray m_className; -}; - /*! \fn QJniObject::QJniObject() @@ -542,7 +572,7 @@ QJniObject::QJniObject(const char *className) d->m_own_jclass = false; if (d->m_jclass) { // get default constructor - jmethodID constructorId = getCachedMethodID(env.jniEnv(), d->m_jclass, d->m_className, "<init>", "()V"); + jmethodID constructorId = getCachedMethodID(env.jniEnv(), "<init>", "()V"); if (constructorId) { jobject obj = env->NewObject(d->m_jclass, constructorId); if (obj) { @@ -574,7 +604,7 @@ QJniObject::QJniObject(const char *className, const char *signature, ...) d->m_jclass = loadClass(d->m_className, env.jniEnv(), true); d->m_own_jclass = false; if (d->m_jclass) { - jmethodID constructorId = getCachedMethodID(env.jniEnv(), d->m_jclass, d->m_className, "<init>", signature); + jmethodID constructorId = getCachedMethodID(env.jniEnv(), "<init>", signature); if (constructorId) { va_list args; va_start(args, signature); @@ -596,7 +626,7 @@ QJniObject::QJniObject(const char *className, const char *signature, const QVaLi d->m_jclass = loadClass(d->m_className, env.jniEnv(), true); d->m_own_jclass = false; if (d->m_jclass) { - jmethodID constructorId = getCachedMethodID(env.jniEnv(), d->m_jclass, d->m_className, "<init>", signature); + jmethodID constructorId = getCachedMethodID(env.jniEnv(), "<init>", signature); if (constructorId) { jobject obj = env->NewObjectV(d->m_jclass, constructorId, args); if (obj) { @@ -720,7 +750,7 @@ QJniObject::QJniObject(jobject obj) 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) +QJniObject QJniObject::getCleanJniObject(jobject obj) { if (!obj) return QJniObject(); @@ -772,7 +802,7 @@ QJniObject QJniObject::callObjectMethodV(const char *methodName, { QJniEnvironment env; jobject res = nullptr; - jmethodID id = getCachedMethodID(env.jniEnv(), d->m_jclass, d->m_className, methodName, signature); + jmethodID id = getCachedMethodID(env.jniEnv(), methodName, signature); if (id) { res = env->CallObjectMethodV(d->m_jobject, id, args); if (env.checkAndClearExceptions()) { @@ -795,7 +825,7 @@ QJniObject QJniObject::callStaticObjectMethodV(const char *className, jobject res = nullptr; jclass clazz = loadClass(className, env.jniEnv()); if (clazz) { - jmethodID id = getCachedMethodID(env.jniEnv(), clazz, toBinaryEncClassName(className), + jmethodID id = QJniObject::getCachedMethodID(env.jniEnv(), clazz, toBinaryEncClassName(className), methodName, signature, true); if (id) { res = env->CallStaticObjectMethodV(clazz, id, args); @@ -836,19 +866,6 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz, \endcode */ -template <> -Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName, const char *signature, ...) const -{ - QJniEnvironment env; - jmethodID id = getCachedMethodID(env.jniEnv(), d->m_jclass, d->m_className, methodName, signature); - if (id) { - va_list args; - va_start(args, signature); - env->CallVoidMethodV(d->m_jobject, id, args); - va_end(args); - env.checkAndClearExceptions(); - } -} /*! \fn template <typename T> T QJniObject::callMethod(const char *methodName) const @@ -860,11 +877,6 @@ Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName, const ch jint size = myJavaString.callMethod<jint>("length"); \endcode */ -template <> -Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName) const -{ - callMethod<void>(methodName, "()V"); -} /*! \fn template <typename T> T QJniObject::callStaticMethod(const char *className, const char *methodName, const char *signature, ...) @@ -878,26 +890,6 @@ Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName) const jint max = QJniObject::callStaticMethod<jint>("java/lang/Math", "max", "(II)I", a, b); \endcode */ -template <> -Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(const char *className, - const char *methodName, - const char *signature, - ...) -{ - QJniEnvironment env; - jclass clazz = loadClass(className, env.jniEnv()); - if (clazz) { - jmethodID id = getCachedMethodID(env.jniEnv(), clazz, toBinaryEncClassName(className), - methodName, signature, true); - if (id) { - va_list args; - va_start(args, signature); - env->CallStaticVoidMethodV(clazz, id, args); - va_end(args); - env.checkAndClearExceptions(); - } - } -} /*! \fn template <typename T> T QJniObject::callStaticMethod(const char *className, const char *methodName) @@ -908,11 +900,6 @@ Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(const char *className, jint value = QJniObject::callStaticMethod<jint>("MyClass", "staticMethod"); \endcode */ -template <> -Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(const char *className, const char *methodName) -{ - callStaticMethod<void>(className, methodName, "()V"); -} /*! \fn template <typename T> T QJniObject::callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...) @@ -928,57 +915,6 @@ Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(const char *className, con jint max = QJniObject::callStaticMethod<jint>(javaMathClass, "max", "(II)I", a, b); \endcode */ -template <> -Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(jclass clazz, - const char *methodName, - const char *signature, - ...) -{ - QJniEnvironment env; - if (clazz) { - jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true); - if (id) { - va_list args; - va_start(args, signature); - env->CallStaticVoidMethodV(clazz, id, args); - va_end(args); - env.checkAndClearExceptions(); - } - } -} - -template <> -Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(const char *className, - const char *methodName, - const char *signature, - va_list args) -{ - QJniEnvironment env; - jclass clazz = loadClass(className, env.jniEnv()); - if (clazz) { - jmethodID id = getCachedMethodID(env.jniEnv(), clazz, - toBinaryEncClassName(className), methodName, - signature, true); - if (id) { - env->CallStaticVoidMethodV(clazz, id, args); - env.checkAndClearExceptions(); - } - } -} - -template <> -Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(jclass clazz, - const char *methodName, - const char *signature, - va_list args) -{ - QJniEnvironment env; - jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true); - if (id) { - env->CallStaticVoidMethodV(clazz, id, args); - env.checkAndClearExceptions(); - } -} /*! \fn template <typename T> T QJniObject::callStaticMethod(jclass clazz, const char *methodName) @@ -991,161 +927,6 @@ Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(jclass clazz, jdouble randNr = QJniObject::callStaticMethod<jdouble>(javaMathClass, "random"); \endcode */ -template <> -Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(jclass clazz, const char *methodName) -{ - callStaticMethod<void>(clazz, methodName, "()V"); -} - -template <> -Q_CORE_EXPORT void QJniObject::callMethodV<void>(const char *methodName, const char *signature, - va_list args) const -{ - QJniEnvironment env; - jmethodID id = getCachedMethodID(env.jniEnv(), d->m_jclass, d->m_className, methodName, signature); - if (id) { - env->CallVoidMethodV(d->m_jobject, id, args); - env.checkAndClearExceptions(); - } -} - -#define MAKE_JNI_METHODS(MethodName, Type, Signature) \ -template <> Q_CORE_EXPORT Type QJniObject::callMethod<Type>(const char *methodName, \ - const char *signature, ...) const \ -{ \ - QJniEnvironment env; \ - Type res = 0; \ - jmethodID id = getCachedMethodID(env.jniEnv(), d->m_jclass, d->m_className, methodName, signature); \ - if (id) { \ - va_list args; \ - va_start(args, signature); \ - res = env->Call##MethodName##MethodV(d->m_jobject, id, args); \ - va_end(args); \ - if (env.checkAndClearExceptions()) \ - res = 0; \ - } \ - return res; \ -}\ -template <> Q_CORE_EXPORT Type QJniObject::callMethod<Type>(const char *methodName) const \ -{ \ - return callMethod<Type>(methodName, Signature); \ -} \ -\ -template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(const char *className, \ - const char *methodName, \ - const char *signature, \ - ...) \ -{ \ - QJniEnvironment env; \ - Type res = 0; \ - jclass clazz = loadClass(className, env.jniEnv()); \ - if (clazz) { \ - jmethodID id = getCachedMethodID(env.jniEnv(), clazz, toBinaryEncClassName(className), methodName, \ - signature, true); \ - if (id) { \ - va_list args; \ - va_start(args, signature); \ - res = env->CallStatic##MethodName##MethodV(clazz, id, args); \ - va_end(args); \ - if (env.checkAndClearExceptions()) \ - res = 0; \ - } \ - } \ - return res; \ -} \ -template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(const char *className, \ - const char *methodName) \ -{ \ - return callStaticMethod<Type>(className, methodName, Signature); \ -}\ -\ -template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(jclass clazz, \ - const char *methodName, \ - const char *signature, \ - ...) \ -{ \ - QJniEnvironment env; \ - Type res = 0; \ - if (clazz) { \ - jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true); \ - if (id) { \ - va_list args; \ - va_start(args, signature); \ - res = env->CallStatic##MethodName##MethodV(clazz, id, args); \ - va_end(args); \ - if (env.checkAndClearExceptions()) \ - res = 0; \ - } \ - } \ - return res; \ -} \ -template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(jclass clazz, \ - const char *methodName) \ -{ \ - return callStaticMethod<Type>(clazz, methodName, Signature); \ -}\ -template <> \ -Q_CORE_EXPORT Type QJniObject::callMethodV<Type>(const char *methodName, const char *signature,\ - va_list args) const\ -{\ - QJniEnvironment env;\ - Type res = 0;\ - jmethodID id = getCachedMethodID(env.jniEnv(), d->m_jclass, d->m_className, methodName, signature);\ - if (id) {\ - res = env->Call##MethodName##MethodV(d->m_jobject, id, args);\ - if (env.checkAndClearExceptions()) \ - res = 0; \ - }\ - return res;\ -}\ -template <>\ -Q_CORE_EXPORT Type QJniObject::callStaticMethodV<Type>(const char *className,\ - const char *methodName,\ - const char *signature,\ - va_list args)\ -{\ - QJniEnvironment env;\ - Type res = 0;\ - jclass clazz = loadClass(className, env.jniEnv());\ - if (clazz) {\ - jmethodID id = getCachedMethodID(env.jniEnv(), clazz, toBinaryEncClassName(className), methodName,\ - signature, true);\ - if (id) {\ - res = env->CallStatic##MethodName##MethodV(clazz, id, args);\ - if (env.checkAndClearExceptions()) \ - res = 0; \ - }\ - }\ - return res;\ -}\ -template <>\ -Q_CORE_EXPORT Type QJniObject::callStaticMethodV<Type>(jclass clazz,\ - const char *methodName,\ - const char *signature,\ - va_list args)\ -{\ - QJniEnvironment env;\ - Type res = 0;\ - jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true);\ - if (id) {\ - res = env->CallStatic##MethodName##MethodV(clazz, id, args);\ - if (env.checkAndClearExceptions()) \ - res = 0; \ - }\ - return res;\ -} - -#define DECLARE_JNI_METHODS(MethodName, Type, Signature) MAKE_JNI_METHODS(MethodName, \ - Type, \ - Signature) -DECLARE_JNI_METHODS(Boolean, jboolean, "()Z") -DECLARE_JNI_METHODS(Byte, jbyte, "()B") -DECLARE_JNI_METHODS(Char, jchar, "()C") -DECLARE_JNI_METHODS(Short, jshort, "()S") -DECLARE_JNI_METHODS(Int, jint, "()I") -DECLARE_JNI_METHODS(Long, jlong, "()J") -DECLARE_JNI_METHODS(Float, jfloat, "()F") -DECLARE_JNI_METHODS(Double, jdouble, "()D") /*! \fn QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const @@ -1162,7 +943,7 @@ DECLARE_JNI_METHODS(Double, jdouble, "()D") QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const { QJniEnvironment env; - jmethodID id = getCachedMethodID(env.jniEnv(), d->m_jclass, d->m_className, methodName, signature); + jmethodID id = getCachedMethodID(env.jniEnv(), methodName, signature); if (id) { va_list args; va_start(args, signature); @@ -1187,15 +968,14 @@ QJniObject QJniObject::callObjectMethod(const char *methodName, const char *sign "(I)Ljava/lang/String;", 10); \endcode */ -QJniObject QJniObject::callStaticObjectMethod(const char *className, - const char *methodName, - const char *signature, - ...) +QJniObject QJniObject::callStaticObjectMethod(const char *className, const char *methodName, + const char *signature, ...) { QJniEnvironment env; - jclass clazz = loadClass(className, env.jniEnv()); + jclass clazz = QJniObject::loadClass(className, env.jniEnv()); if (clazz) { - jmethodID id = getCachedMethodID(env.jniEnv(), clazz, toBinaryEncClassName(className), + jmethodID id = QJniObject::getCachedMethodID(env.jniEnv(), clazz, + QJniObject::toBinaryEncClassName(className), methodName, signature, true); if (id) { va_list args; @@ -1215,10 +995,8 @@ QJniObject QJniObject::callStaticObjectMethod(const char *className, Calls the static method \a methodName from class \a clazz with \a signature specifying the types of any subsequent arguments. */ -QJniObject QJniObject::callStaticObjectMethod(jclass clazz, - const char *methodName, - const char *signature, - ...) +QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodName, + const char *signature, ...) { QJniEnvironment env; if (clazz) { @@ -1289,51 +1067,6 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, Replace the current object with \a object. The old Java object will be released. */ -#define MAKE_JNI_OBJECT_METHODS(Type, Signature) \ -template <> \ -Q_CORE_EXPORT QJniObject QJniObject::callObjectMethod<Type>(const char *methodName) const \ -{ \ - return callObjectMethod(methodName, Signature); \ -} \ -template <> \ -Q_CORE_EXPORT QJniObject QJniObject::callStaticObjectMethod<Type>(const char *className, \ - const char *methodName) \ -{ \ - return callStaticObjectMethod(className, methodName, Signature); \ -} \ -template <> \ -Q_CORE_EXPORT QJniObject QJniObject::callStaticObjectMethod<Type>(jclass clazz, \ - const char *methodName) \ -{ \ - return callStaticObjectMethod(clazz, methodName, Signature); \ -}\ -template <>\ -Q_CORE_EXPORT Type QJniObject::object<Type>() const\ -{\ - return static_cast<Type>(javaObject());\ -}\ -template <>\ -Q_CORE_EXPORT QJniObject &QJniObject::operator=(Type obj)\ -{\ - assign(static_cast<jobject>(obj));\ - return *this;\ -} - -#define DECLARE_JNI_OBJECT_METHODS(Type, Signature) MAKE_JNI_OBJECT_METHODS(Type, Signature) - -DECLARE_JNI_OBJECT_METHODS(jobject, "()Ljava/lang/Object;") -DECLARE_JNI_OBJECT_METHODS(jclass, "()Ljava/lang/Class;") -DECLARE_JNI_OBJECT_METHODS(jstring, "()Ljava/lang/String;") -DECLARE_JNI_OBJECT_METHODS(jobjectArray, "()[Ljava/lang/Object;") -DECLARE_JNI_OBJECT_METHODS(jbooleanArray, "()[Z") -DECLARE_JNI_OBJECT_METHODS(jbyteArray, "()[B") -DECLARE_JNI_OBJECT_METHODS(jshortArray, "()[S") -DECLARE_JNI_OBJECT_METHODS(jintArray, "()[I") -DECLARE_JNI_OBJECT_METHODS(jlongArray, "()[J") -DECLARE_JNI_OBJECT_METHODS(jfloatArray, "()[F") -DECLARE_JNI_OBJECT_METHODS(jdoubleArray, "()[D") -DECLARE_JNI_OBJECT_METHODS(jcharArray, "()[C") -DECLARE_JNI_OBJECT_METHODS(jthrowable, "()Ljava/lang/Throwable;") /*! \fn template <typename T> void QJniObject::setStaticField(const char *className, const char *fieldName, const char *signature, T value); @@ -1342,24 +1075,6 @@ DECLARE_JNI_OBJECT_METHODS(jthrowable, "()Ljava/lang/Throwable;") using the setter with \a signature. */ -template <> -Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(const char *className, - const char *fieldName, - const char *signature, - jobject value) -{ - QJniEnvironment env; - jclass clazz = loadClass(className, env.jniEnv()); - - if (!clazz) - return; - - jfieldID id = getCachedFieldID(env.jniEnv(), clazz, className, fieldName, signature, true); - if (id) { - env->SetStaticObjectField(clazz, id, value); - env.checkAndClearExceptions(); - } -} /*! \fn template <typename T> void QJniObject::setStaticField(jclass clazz, const char *fieldName, const char *signature, T value); @@ -1367,19 +1082,6 @@ Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(const char *className, Sets the static field \a fieldName on the class \a clazz to \a value using the setter with \a signature. */ -template <> Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(jclass clazz, - const char *fieldName, - const char *signature, - jobject value) -{ - QJniEnvironment env; - jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, signature, true); - - if (id) { - env->SetStaticObjectField(clazz, id, value); - env.checkAndClearExceptions(); - } -} /*! \fn T QJniObject::getField(const char *fieldName) const @@ -1415,93 +1117,6 @@ template <> Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(jclass clazz, Sets the static field \a fieldName of the class \a clazz to \a value. */ -#define MAKE_JNI_PRIMITIVE_FIELDS(FieldName, Type, Signature) \ -template <> Q_CORE_EXPORT Type QJniObject::getField<Type>(const char *fieldName) const \ -{ \ - QJniEnvironment env; \ - Type res = 0; \ - jfieldID id = getCachedFieldID(env.jniEnv(), d->m_jclass, d->m_className, fieldName, Signature); \ - if (id) {\ - res = env->Get##FieldName##Field(d->m_jobject, id); \ - if (env.checkAndClearExceptions()) \ - res = 0; \ - } \ - return res;\ -} \ -template <> \ -Q_CORE_EXPORT Type QJniObject::getStaticField<Type>(const char *className, const char *fieldName) \ -{ \ - QJniEnvironment env; \ - jclass clazz = loadClass(className, env.jniEnv()); \ - if (!clazz) \ - return 0; \ - jfieldID id = getCachedFieldID(env.jniEnv(), clazz, toBinaryEncClassName(className), fieldName, \ - Signature, true); \ - if (!id) \ - return 0; \ - Type res = env->GetStatic##FieldName##Field(clazz, id); \ - if (env.checkAndClearExceptions()) \ - res = 0; \ - return res;\ -} \ -template <>\ -Q_CORE_EXPORT Type QJniObject::getStaticField<Type>(jclass clazz, const char *fieldName)\ -{\ - QJniEnvironment env;\ - Type res = 0;\ - jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, Signature, true);\ - if (id) {\ - res = env->GetStatic##FieldName##Field(clazz, id);\ - if (env.checkAndClearExceptions()) \ - res = 0; \ - }\ - return res;\ -}\ -template <> Q_CORE_EXPORT void QJniObject::setStaticField<Type>(const char *className, \ - const char *fieldName, \ - Type value) \ -{ \ - QJniEnvironment env; \ - jclass clazz = loadClass(className, env.jniEnv()); \ - if (!clazz) \ - return; \ - jfieldID id = getCachedFieldID(env.jniEnv(), clazz, className, fieldName, Signature, true); \ - if (!id) \ - return; \ - env->SetStatic##FieldName##Field(clazz, id, value); \ - env.checkAndClearExceptions(); \ -}\ -template <> Q_CORE_EXPORT void QJniObject::setStaticField<Type>(jclass clazz,\ - const char *fieldName,\ - Type value)\ -{\ - QJniEnvironment env;\ - jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, Signature, true);\ - if (id) {\ - env->SetStatic##FieldName##Field(clazz, id, value);\ - env.checkAndClearExceptions();\ - }\ -}\ -template <> Q_CORE_EXPORT void QJniObject::setField<Type>(const char *fieldName, Type value) \ -{ \ - QJniEnvironment env; \ - jfieldID id = getCachedFieldID(env.jniEnv(), d->m_jclass, d->m_className, fieldName, Signature); \ - if (id) { \ - env->Set##FieldName##Field(d->m_jobject, id, value); \ - env.checkAndClearExceptions(); \ - } \ -} \ - -#define DECLARE_JNI_PRIMITIVE_FIELDS(FieldName, Type, Signature) MAKE_JNI_PRIMITIVE_FIELDS(FieldName, Type, \ - Signature) -DECLARE_JNI_PRIMITIVE_FIELDS(Boolean, jboolean, "Z") -DECLARE_JNI_PRIMITIVE_FIELDS(Byte, jbyte, "B") -DECLARE_JNI_PRIMITIVE_FIELDS(Char, jchar, "C") -DECLARE_JNI_PRIMITIVE_FIELDS(Short, jshort, "S") -DECLARE_JNI_PRIMITIVE_FIELDS(Int, jint, "I") -DECLARE_JNI_PRIMITIVE_FIELDS(Long, jlong, "J") -DECLARE_JNI_PRIMITIVE_FIELDS(Float, jfloat, "F") -DECLARE_JNI_PRIMITIVE_FIELDS(Double, jdouble, "D") /*! \fn QJniObject QJniObject::getStaticObjectField(const char *className, const char *fieldName, const char *signature) @@ -1521,10 +1136,12 @@ QJniObject QJniObject::getStaticObjectField(const char *className, const char *signature) { QJniEnvironment env; - jclass clazz = loadClass(className, env.jniEnv()); + jclass clazz = QJniObject::loadClass(className, env.jniEnv()); if (!clazz) return QJniObject(); - jfieldID id = getCachedFieldID(env.jniEnv(), clazz, toBinaryEncClassName(className), fieldName, + jfieldID id = QJniObject::getCachedFieldID(env.jniEnv(), clazz, + QJniObject::toBinaryEncClassName(className), + fieldName, signature, true); if (!id) return QJniObject(); @@ -1544,8 +1161,7 @@ QJniObject QJniObject::getStaticObjectField(const char *className, QJniObject jobj = QJniObject::getStaticObjectField(clazz, "FIELD_NAME", "Ljava/lang/String;"); \endcode */ -QJniObject QJniObject::getStaticObjectField(jclass clazz, - const char *fieldName, +QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName, const char *signature) { QJniEnvironment env; @@ -1557,62 +1173,6 @@ QJniObject QJniObject::getStaticObjectField(jclass clazz, } /*! - \fn QJniObject QJniObject::getStaticObjectField<jobject>(jclass clazz, const char *fieldName, const char *signature) - - Retrieves a JNI object for \c jobject from the static field \a fieldName with - \a signature from \a clazz. -*/ -template <> -Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobject>(jclass clazz, - const char *fieldName, - const char *signature) -{ - return getStaticObjectField(clazz, fieldName, signature); -} - -/*! - \fn QJniObject QJniObject::getStaticObjectField<jobject>(const char *className, const char *fieldName, const char *signature) - - Retrieves a JNI object for \c jobject from the static field \a fieldName with - \a signature from class \a className. -*/ -template <> -Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobject>(const char *className, - const char *fieldName, - const char *signature) -{ - return getStaticObjectField(className, fieldName, signature); -} - -/*! - \fn QJniObject QJniObject::getStaticObjectField<jobjectArray>(jclass clazz, const char *fieldName, const char *signature) - - Retrieves a JNI object for \c jobjectArray from the static field \a fieldName - with \a signature from class \a clazz. -*/ -template <> -Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobjectArray>(jclass clazz, - const char *fieldName, - const char *signature) -{ - return getStaticObjectField(clazz, fieldName, signature); -} - -/*! - \fn QJniObject QJniObject::getStaticObjectField<jobjectArray>(const char *className, const char *fieldName, const char *signature) - - Retrieves a JNI object for \c jobjectArray from the static field \a fieldName - with \a signature from class \a className. -*/ -template <> -Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobjectArray>(const char *className, - const char *fieldName, - const char *signature) -{ - return getStaticObjectField(className, fieldName, signature); -} - -/*! \fn template <typename T> void QJniObject::setField(const char *fieldName, const char *signature, T value) Sets the value of \a fieldName with \a signature to \a value. @@ -1620,33 +1180,10 @@ Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobjectArray>(const ch \code QJniObject stringArray = ...; QJniObject obj = ...; - obj.setField<jobjectArray>("KEY_VALUES", "([Ljava/lang/String;)V", + obj.setObjectField<jobjectArray>("KEY_VALUES", "([Ljava/lang/String;)V", stringArray.object<jobjectArray>()) \endcode */ -template <> Q_CORE_EXPORT -void QJniObject::setField<jobject>(const char *fieldName, const char *signature, jobject value) -{ - QJniEnvironment env; - jfieldID id = getCachedFieldID(env.jniEnv(), d->m_jclass, d->m_className, fieldName, signature); - if (id) { - env->SetObjectField(d->m_jobject, id, value); - env.checkAndClearExceptions(); - } -} - -template <> Q_CORE_EXPORT -void QJniObject::setField<jobjectArray>(const char *fieldName, - const char *signature, - jobjectArray value) -{ - QJniEnvironment env; - jfieldID id = getCachedFieldID(env.jniEnv(), d->m_jclass, d->m_className, fieldName, signature); - if (id) { - env->SetObjectField(d->m_jobject, id, value); - env.checkAndClearExceptions(); - } -} /*! \fn QJniObject QJniObject::getObjectField(const char *fieldName) const @@ -1672,7 +1209,7 @@ void QJniObject::setField<jobjectArray>(const char *fieldName, QJniObject QJniObject::getObjectField(const char *fieldName, const char *signature) const { QJniEnvironment env; - jfieldID id = getCachedFieldID(env.jniEnv(), d->m_jclass, d->m_className, fieldName, signature); + jfieldID id = getCachedFieldID(env.jniEnv(), fieldName, signature); if (!id) return QJniObject(); @@ -1712,52 +1249,6 @@ QJniObject QJniObject::getObjectField(const char *fieldName, const char *signatu \endcode */ -#define MAKE_JNI_OBJECT_FILEDS(Type, Signature) \ -template <> Q_CORE_EXPORT void QJniObject::setField<Type>(const char *fieldName, Type value) \ -{ \ - QJniObject::setField<jobject>(fieldName, Signature, value); \ -} \ -\ -template <> Q_CORE_EXPORT void QJniObject::setStaticField<Type>(const char *className, \ - const char *fieldName, \ - Type value) \ -{ \ - QJniObject::setStaticField<jobject>(className, fieldName, Signature, value); \ -}\ -template <>\ -Q_CORE_EXPORT QJniObject QJniObject::getObjectField<Type>(const char *fieldName) const\ -{\ - return getObjectField(fieldName, Signature);\ -}\ -template <>\ -Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<Type>(jclass clazz,\ - const char *fieldName)\ -{\ - return getStaticObjectField(clazz, fieldName, Signature);\ -}\ -template <>\ -Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<Type>(const char *className,\ - const char *fieldName)\ -{\ - return getStaticObjectField(className, fieldName, Signature);\ -}\ - -#define DECLARE_JNI_OBJECT_FILEDS(Type, Signature) MAKE_JNI_OBJECT_FILEDS(Type, Signature) - -DECLARE_JNI_OBJECT_FILEDS(jobject, "Ljava/lang/Object;") -DECLARE_JNI_OBJECT_FILEDS(jobjectArray, "[Ljava/lang/Object;") -DECLARE_JNI_OBJECT_FILEDS(jstring, "Ljava/lang/String;") -DECLARE_JNI_OBJECT_FILEDS(jclass, "Ljava/lang/Class;") -DECLARE_JNI_OBJECT_FILEDS(jthrowable, "Ljava/lang/Throwable;") -DECLARE_JNI_OBJECT_FILEDS(jbooleanArray, "[Z") -DECLARE_JNI_OBJECT_FILEDS(jbyteArray, "[B") -DECLARE_JNI_OBJECT_FILEDS(jcharArray, "[C") -DECLARE_JNI_OBJECT_FILEDS(jshortArray, "[S") -DECLARE_JNI_OBJECT_FILEDS(jintArray, "[I") -DECLARE_JNI_OBJECT_FILEDS(jlongArray, "[J") -DECLARE_JNI_OBJECT_FILEDS(jfloatArray, "[F") -DECLARE_JNI_OBJECT_FILEDS(jdoubleArray, "[D") - /*! \fn QJniObject QJniObject::fromString(const QString &string) diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h index 0f88695e73..83d64ad485 100644 --- a/src/corelib/kernel/qjniobject.h +++ b/src/corelib/kernel/qjniobject.h @@ -40,14 +40,11 @@ #ifndef QJNIOBJECT_H #define QJNIOBJECT_H -#include <QtCore/QSharedPointer> +#include <QtCore/qsharedpointer.h> #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) #include <jni.h> -#else -class jclass; -class jobject; -#endif +#include <QtCore/qjnienvironment.h> QT_BEGIN_NAMESPACE @@ -64,85 +61,375 @@ public: QJniObject(jobject globalRef); ~QJniObject(); - template <typename T> - T object() const; jobject object() const; + template <typename T> T object() const + { + assertJniObjectType<T>(); + return static_cast<T>(javaObject()); + } template <typename T> - T callMethod(const char *methodName, const char *signature, ...) const; + T callMethod(const char *methodName, const char *signature, ...) const + { + assertJniPrimitiveType<T>(); + QJniEnvironment env; + T res{}; + jmethodID id = getCachedMethodID(env.jniEnv(), methodName, signature); + if (id) { + va_list args; + va_start(args, signature); + callMethodForType<T>(env.jniEnv(), res, object(), id, args); + va_end(args); + if (env.checkAndClearExceptions()) + res = {}; + } + return res; + } + + template <> + void callMethod<void>(const char *methodName, const char *signature, ...) const + { + QJniEnvironment env; + jmethodID id = getCachedMethodID(env.jniEnv(), methodName, signature); + if (id) { + va_list args; + va_start(args, signature); + callVoidMethodV(env.jniEnv(), id, args); + va_end(args); + env.checkAndClearExceptions(); + } + } + template <typename T> - T callMethod(const char *methodName) const; + T callMethod(const char *methodName) const + { + assertJniPrimitiveType<T>(); + constexpr const char *signature = getTypeSignature<T>(); + return callMethod<T>(methodName, QByteArray(signature).prepend("()").constData()); + } + + template <> + void callMethod<void>(const char *methodName) const + { + callMethod<void>(methodName, "()V"); + } + template <typename T> - QJniObject callObjectMethod(const char *methodName) const; + QJniObject callObjectMethod(const char *methodName) const + { + assertJniObjectType<T>(); + constexpr const char *signature = getTypeSignature<T>(); + return callObjectMethod(methodName, QByteArray(signature).prepend("()").constData()); + } + QJniObject callObjectMethod(const char *methodName, const char *signature, ...) const; template <typename T> static T callStaticMethod(const char *className, const char *methodName, - const char *signature, ...); - template <typename T> - static T callStaticMethod(const char *className, const char *methodName); + const char *signature, ...) + { + assertJniPrimitiveType<T>(); + QJniEnvironment env; + T res{}; + jclass clazz = QJniObject::loadClass(className, env.jniEnv()); + if (clazz) { + jmethodID id = getCachedMethodID(env.jniEnv(), clazz, + QJniObject::toBinaryEncClassName(className), + methodName, signature, true); + if (id) { + va_list args; + va_start(args, signature); + callStaticMethodForType<T>(env.jniEnv(), res, clazz, id, args); + va_end(args); + if (env.checkAndClearExceptions()) + res = {}; + } + } + return res; + } + + template <> + void callStaticMethod<void>(const char *className, const char *methodName, + const char *signature, ...) + { + QJniEnvironment env; + jclass clazz = QJniObject::loadClass(className, env.jniEnv()); + if (clazz) { + jmethodID id = getCachedMethodID(env.jniEnv(), clazz, + QJniObject::toBinaryEncClassName(className), + methodName, signature, true); + if (id) { + va_list args; + va_start(args, signature); + env->CallStaticVoidMethodV(clazz, id, args); + va_end(args); + env.checkAndClearExceptions(); + } + } + } + template <typename T> - static T callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...); + static T callStaticMethod(const char *className, const char *methodName) + { + assertJniPrimitiveType<T>(); + constexpr const char *signature = getTypeSignature<T>(); + return callStaticMethod<T>(className, methodName, QByteArray(signature).prepend("()").constData()); + } + + template <> + void callStaticMethod<void>(const char *className, const char *methodName) + { + callStaticMethod<void>(className, methodName, "()V"); + } + template <typename T> - static T callStaticMethod(jclass clazz, const char *methodName); + static T callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...) + { + assertJniPrimitiveType<T>(); + QJniEnvironment env; + T res{}; + if (clazz) { + jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true); + if (id) { + va_list args; + va_start(args, signature); + callStaticMethodForType<T>(env.jniEnv(), res, clazz, id, args); + va_end(args); + if (env.checkAndClearExceptions()) + res = {}; + } + } + return res; + } + + template <> + void callStaticMethod<void>(jclass clazz, const char *methodName, + const char *signature, ...) + { + QJniEnvironment env; + if (clazz) { + jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true); + if (id) { + va_list args; + va_start(args, signature); + env->CallStaticVoidMethodV(clazz, id, args); + va_end(args); + env.checkAndClearExceptions(); + } + } + } + + template <typename T> static T callStaticMethod(jclass clazz, const char *methodName) + { + assertJniPrimitiveType<T>(); + constexpr const char *signature = getTypeSignature<T>(); + return callStaticMethod<T>(clazz, methodName, QByteArray(signature).prepend("()").constData()); + } + + template <> + void callStaticMethod<void>(jclass clazz, const char *methodName) + { + callStaticMethod<void>(clazz, methodName, "()V"); + } template <typename T> - static QJniObject callStaticObjectMethod(const char *className, const char *methodName); - static QJniObject callStaticObjectMethod(const char *className, - const char *methodName, + static QJniObject callStaticObjectMethod(const char *className, const char *methodName) + { + assertJniObjectType<T>(); + constexpr const char *signature = getTypeSignature<T>(); + return callStaticObjectMethod(className, methodName, QByteArray(signature).prepend("()").constData()); + } + + static QJniObject callStaticObjectMethod(const char *className, const char *methodName, const char *signature, ...); template <typename T> - static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName); - static QJniObject callStaticObjectMethod(jclass clazz, - const char *methodName, + static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName) + { + assertJniObjectType<T>(); + constexpr const char *signature = getTypeSignature<T>(); + return callStaticObjectMethod(clazz, methodName, QByteArray(signature).prepend("()").constData()); + } + + static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName, const char *signature, ...); - template <typename T> - T getField(const char *fieldName) const; + template <typename T> T getField(const char *fieldName) const + { + assertJniPrimitiveType<T>(); + QJniEnvironment env; + T res{}; + constexpr const char *signature = getTypeSignature<T>(); + jfieldID id = getCachedFieldID(env.jniEnv(), fieldName, signature); + if (id) { + getFieldForType<T>(env.jniEnv(), res, object(), id); + if (env.checkAndClearExceptions()) + res = {}; + } + return res; + } template <typename T> - static T getStaticField(const char *className, const char *fieldName); + static T getStaticField(const char *className, const char *fieldName) + { + assertJniPrimitiveType<T>(); + QJniEnvironment env; + jclass clazz = QJniObject::loadClass(className, env.jniEnv()); + if (!clazz) + return 0; + + constexpr const char *signature = getTypeSignature<T>(); + jfieldID id = getCachedFieldID(env.jniEnv(), clazz, + QJniObject::toBinaryEncClassName(className), + fieldName, + signature, true); + if (!id) + return 0; + + T res{}; + getStaticFieldForType<T>(env.jniEnv(), res, clazz, id); + if (env.checkAndClearExceptions()) + res = {}; + return res; + } + template <typename T> - static T getStaticField(jclass clazz, const char *fieldName); + static T getStaticField(jclass clazz, const char *fieldName) + { + assertJniPrimitiveType<T>(); + QJniEnvironment env; + T res{}; + constexpr const char *signature = getTypeSignature<T>(); + jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, signature, true); + if (id) { + getStaticFieldForType<T>(env.jniEnv(), res, clazz, id); + if (env.checkAndClearExceptions()) + res = {}; + } + return res; + } template <typename T> - QJniObject getObjectField(const char *fieldName) const; + QJniObject getObjectField(const char *fieldName) const + { + assertJniObjectType<T>(); + constexpr const char *signature = getTypeSignature<T>(); + return getObjectField(fieldName, signature); + } + QJniObject getObjectField(const char *fieldName, const char *signature) const; template <typename T> - static QJniObject getStaticObjectField(const char *className, const char *fieldName); - static QJniObject getStaticObjectField(const char *className, - const char *fieldName, - const char *signature); - template <typename T> + static QJniObject getStaticObjectField(const char *className, const char *fieldName) + { + assertJniObjectType<T>(); + constexpr const char *signature = getTypeSignature<T>(); + return getStaticObjectField(className, fieldName, signature); + } + static QJniObject getStaticObjectField(const char *className, const char *fieldName, const char *signature); template <typename T> - static QJniObject getStaticObjectField(jclass clazz, const char *fieldName); - static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, - const char *signature); - template <typename T> + static QJniObject getStaticObjectField(jclass clazz, const char *fieldName) + { + assertJniObjectType<T>(); + constexpr const char *signature = getTypeSignature<T>(); + return getStaticObjectField(clazz, fieldName, signature); + } + static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, const char *signature); + template <typename T> void setField(const char *fieldName, T value) + { + assertJniType<T>(); + QJniEnvironment env; + constexpr const char *signature = getTypeSignature<T>(); + jfieldID id = getCachedFieldID(env.jniEnv(), fieldName, signature); + if (id) { + setFieldForType<T>(env, object(), id, value); + env.checkAndClearExceptions(); + } + } + template <typename T> - void setField(const char *fieldName, T value); - template <typename T> - void setField(const char *fieldName, const char *signature, T value); + void setField(const char *fieldName, const char *signature, T value) + { + assertJniType<T>(); + QJniEnvironment env; + jfieldID id = getCachedFieldID(env.jniEnv(), fieldName, signature); + if (id) { + setFieldForType<T>(env, object(), id, value); + env.checkAndClearExceptions(); + } + } + template <typename T> - static void setStaticField(const char *className, const char *fieldName, T value); + static void setStaticField(const char *className, const char *fieldName, T value) + { + assertJniType<T>(); + QJniEnvironment env; + jclass clazz = QJniObject::loadClass(className, env.jniEnv()); + if (!clazz) + return; + + constexpr const char *signature = getTypeSignature<T>(); + jfieldID id = getCachedFieldID(env.jniEnv(), clazz, className, fieldName, + signature, true); + if (!id) + return; + + setStaticFieldForType<T>(env, clazz, id, value); + env.checkAndClearExceptions(); + } + template <typename T> static void setStaticField(const char *className, const char *fieldName, - const char *signature, T value); + const char *signature, T value) + { + assertJniType<T>(); + QJniEnvironment env; + jclass clazz = QJniObject::loadClass(className, env.jniEnv()); + + if (!clazz) + return; + + jfieldID id = getCachedFieldID(env.jniEnv(), clazz, className, fieldName, + signature, true); + if (id) { + setStaticFieldForType<T>(env, clazz, id, value); + env.checkAndClearExceptions(); + } + } + template <typename T> static void setStaticField(jclass clazz, const char *fieldName, - const char *signature, T value); + const char *signature, T value) + { + assertJniType<T>(); + QJniEnvironment env; + jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, signature, true); + + if (id) { + setStaticFieldForType<T>(env, clazz, id, value); + env.checkAndClearExceptions(); + } + } template <typename T> - static void setStaticField(jclass clazz, const char *fieldName, T value); + static void setStaticField(jclass clazz, const char *fieldName, T value) + { + assertJniType<T>(); + QJniEnvironment env; + constexpr const char *signature = getTypeSignature<T>(); + jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, signature, true); + if (id) { + setStaticFieldForType<T>(env, clazz, id, value); + env.checkAndClearExceptions(); + } + } static QJniObject fromString(const QString &string); QString toString() const; @@ -153,39 +440,47 @@ public: // This function takes ownership of the jobject and releases the local ref. before returning. static QJniObject fromLocalRef(jobject lref); - template <typename T> QJniObject &operator=(T obj); + template <typename T> QJniObject &operator=(T obj) + { + assertJniType<T>(); + assign(static_cast<T>(obj)); + return *this; + } private: struct QVaListPrivate { operator va_list &() const { return m_args; } va_list &m_args; }; - QJniObject(const char *className, const char *signature, const QVaListPrivate &args); QJniObject(jclass clazz, const char *signature, const QVaListPrivate &args); - template <typename T> - T callMethodV(const char *methodName, const char *signature, va_list args) const; - QJniObject callObjectMethodV(const char *methodName, - const char *signature, + static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded = false); + static QByteArray toBinaryEncClassName(const QByteArray &className); + static QJniObject getCleanJniObject(jobject obj); + + static jfieldID getCachedFieldID(JNIEnv *env, jclass clazz, const QByteArray &className, + const char *name, const char *signature, + bool isStatic = false); + jfieldID getCachedFieldID(JNIEnv *env, const char *name, const char *signature, + bool isStatic = false) const; + static jmethodID getCachedMethodID(JNIEnv *env, jclass clazz, const QByteArray &className, + const char *name, const char *signature, + bool isStatic = false); + jmethodID getCachedMethodID(JNIEnv *env, const char *name, const char *signature, + bool isStatic = false) const; + + static jfieldID getFieldID(JNIEnv *env, jclass clazz, const char *name, + const char *signature, bool isStatic = false); + static jmethodID getMethodID(JNIEnv *env, jclass clazz, const char *name, + const char *signature, bool isStatic = false); + + void callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const; + QJniObject callObjectMethodV(const char *methodName, const char *signature, va_list args) const; - template <typename T> - static T callStaticMethodV(const char *className, - const char *methodName, - const char *signature, - va_list args); - template <typename T> - static T callStaticMethodV(jclass clazz, - const char *methodName, - const char *signature, - va_list args); - static QJniObject callStaticObjectMethodV(const char *className, - const char *methodName, - const char *signature, - va_list args); + static QJniObject callStaticObjectMethodV(const char *className, const char *methodName, + const char *signature, va_list args); - static QJniObject callStaticObjectMethodV(jclass clazz, - const char *methodName, - const char *signature, - va_list args); + static QJniObject callStaticObjectMethodV(jclass clazz, const char *methodName, + const char *signature, va_list args); bool isSameObject(jobject obj) const; bool isSameObject(const QJniObject &other) const; @@ -195,6 +490,249 @@ private: friend bool operator==(const QJniObject &, const QJniObject &); friend bool operator!=(const QJniObject&, const QJniObject&); + template<bool flag = false> + static void staticAssertTypeMismatch() + { + static_assert(flag, "The used type is not supported by this template call. " + "Use a JNI based type instead."); + } + + template<typename T> + static constexpr bool isJniPrimitiveType() + { + if constexpr(!std::is_same<T, jboolean>::value + && !std::is_same<T, jbyte>::value + && !std::is_same<T, jchar>::value + && !std::is_same<T, jshort>::value + && !std::is_same<T, jint>::value + && !std::is_same<T, jlong>::value + && !std::is_same<T, jfloat>::value + && !std::is_same<T, jdouble>::value) { + return false; + } + + return true; + } + + template<typename T> + static constexpr void assertJniPrimitiveType() + { + if constexpr(!isJniPrimitiveType<T>()) + staticAssertTypeMismatch(); + } + + template<typename T> + static constexpr void assertJniObjectType() + { + if constexpr(!std::is_convertible<T, jobject>::value) + staticAssertTypeMismatch(); + } + + template<typename T> + static constexpr void assertJniType() + { + if constexpr(!isJniPrimitiveType<T>() && !std::is_convertible<T, jobject>::value) + staticAssertTypeMismatch(); + } + + template<typename T> + static constexpr const char* getTypeSignature() + { + if constexpr(std::is_same<T, jobject>::value) + return "Ljava/lang/Object;"; + else if constexpr(std::is_same<T, jclass>::value) + return "Ljava/lang/Class;"; + else if constexpr(std::is_same<T, jstring>::value) + return "Ljava/lang/String;"; + else if constexpr(std::is_same<T, jobjectArray>::value) + return "[Ljava/lang/Object;"; + else if constexpr(std::is_same<T, jthrowable>::value) + return "Ljava/lang/Throwable;"; + else if constexpr(std::is_same<T, jbooleanArray>::value) + return "[Z"; + else if constexpr(std::is_same<T, jbyteArray>::value) + return "[B"; + else if constexpr(std::is_same<T, jshortArray>::value) + return "[S"; + else if constexpr(std::is_same<T, jintArray>::value) + return "[I"; + else if constexpr(std::is_same<T, jlongArray>::value) + return "[J"; + else if constexpr(std::is_same<T, jfloatArray>::value) + return "[F"; + else if constexpr(std::is_same<T, jdoubleArray>::value) + return "[D"; + else if constexpr(std::is_same<T, jcharArray>::value) + return "[C"; + else if constexpr(std::is_same<T, jboolean>::value) + return "Z"; + else if constexpr(std::is_same<T, jbyte>::value) + return "B"; + else if constexpr(std::is_same<T, jchar>::value) + return "C"; + else if constexpr(std::is_same<T, jshort>::value) + return "S"; + else if constexpr(std::is_same<T, jint>::value) + return "I"; + else if constexpr(std::is_same<T, jlong>::value) + return "J"; + else if constexpr(std::is_same<T, jfloat>::value) + return "F"; + else if constexpr(std::is_same<T, jdouble>::value) + return "D"; + else + staticAssertTypeMismatch(); + } + + template<typename T> + static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, + jmethodID id, va_list args) + { + if constexpr(std::is_same<T, jboolean>::value) + res = env->CallBooleanMethodV(obj, id, args); + else if constexpr(std::is_same<T, jbyte>::value) + res = env->CallByteMethodV(obj, id, args); + else if constexpr(std::is_same<T, jchar>::value) + res = env->CallCharMethodV(obj, id, args); + else if constexpr(std::is_same<T, jshort>::value) + res = env->CallShortMethodV(obj, id, args); + else if constexpr(std::is_same<T, jint>::value) + res = env->CallIntMethodV(obj, id, args); + else if constexpr(std::is_same<T, jlong>::value) + res = env->CallLongMethodV(obj, id, args); + else if constexpr(std::is_same<T, jfloat>::value) + res = env->CallFloatMethodV(obj, id, args); + else if constexpr(std::is_same<T, jdouble>::value) + res = env->CallDoubleMethodV(obj, id, args); + else + staticAssertTypeMismatch(); + } + + template<typename T> + static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz, + jmethodID id, va_list args) + { + if constexpr(std::is_same<T, jboolean>::value) + res = env->CallStaticBooleanMethodV(clazz, id, args); + else if constexpr(std::is_same<T, jbyte>::value) + res = env->CallStaticByteMethodV(clazz, id, args); + else if constexpr(std::is_same<T, jchar>::value) + res = env->CallStaticCharMethodV(clazz, id, args); + else if constexpr(std::is_same<T, jshort>::value) + res = env->CallStaticShortMethodV(clazz, id, args); + else if constexpr(std::is_same<T, jint>::value) + res = env->CallStaticIntMethodV(clazz, id, args); + else if constexpr(std::is_same<T, jlong>::value) + res = env->CallStaticLongMethodV(clazz, id, args); + else if constexpr(std::is_same<T, jfloat>::value) + res = env->CallStaticFloatMethodV(clazz, id, args); + else if constexpr(std::is_same<T, jdouble>::value) + res = env->CallStaticDoubleMethodV(clazz, id, args); + else + staticAssertTypeMismatch(); + } + + template<typename T> + static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, + jfieldID id) + { + if constexpr(std::is_same<T, jboolean>::value) + res = env->GetBooleanField(obj, id); + else if constexpr(std::is_same<T, jbyte>::value) + res = env->GetByteField(obj, id); + else if constexpr(std::is_same<T, jchar>::value) + res = env->GetCharField(obj, id); + else if constexpr(std::is_same<T, jshort>::value) + res = env->GetShortField(obj, id); + else if constexpr(std::is_same<T, jint>::value) + res = env->GetIntField(obj, id); + else if constexpr(std::is_same<T, jlong>::value) + res = env->GetLongField(obj, id); + else if constexpr(std::is_same<T, jfloat>::value) + res = env->GetFloatField(obj, id); + else if constexpr(std::is_same<T, jdouble>::value) + res = env->GetDoubleField(obj, id); + else + staticAssertTypeMismatch(); + } + + template<typename T> + static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, + jfieldID id) + { + if constexpr(std::is_same<T, jboolean>::value) + res = env->GetStaticBooleanField(clazz, id); + else if constexpr(std::is_same<T, jbyte>::value) + res = env->GetStaticByteField(clazz, id); + else if constexpr(std::is_same<T, jchar>::value) + res = env->GetStaticCharField(clazz, id); + else if constexpr(std::is_same<T, jshort>::value) + res = env->GetStaticShortField(clazz, id); + else if constexpr(std::is_same<T, jint>::value) + res = env->GetStaticIntField(clazz, id); + else if constexpr(std::is_same<T, jlong>::value) + res = env->GetStaticLongField(clazz, id); + else if constexpr(std::is_same<T, jfloat>::value) + res = env->GetStaticFloatField(clazz, id); + else if constexpr(std::is_same<T, jdouble>::value) + res = env->GetStaticDoubleField(clazz, id); + else + staticAssertTypeMismatch(); + } + + template<typename T> + static constexpr void setFieldForType(JNIEnv *env, jobject obj, + jfieldID id, T value) + { + if constexpr(std::is_same<T, jboolean>::value) + env->SetBooleanField(obj, id, value); + else if constexpr(std::is_same<T, jbyte>::value) + env->SetByteField(obj, id, value); + else if constexpr(std::is_same<T, jchar>::value) + env->SetCharField(obj, id, value); + else if constexpr(std::is_same<T, jshort>::value) + env->SetShortField(obj, id, value); + else if constexpr(std::is_same<T, jint>::value) + env->SetIntField(obj, id, value); + else if constexpr(std::is_same<T, jlong>::value) + env->SetLongField(obj, id, value); + else if constexpr(std::is_same<T, jfloat>::value) + env->SetFloatField(obj, id, value); + else if constexpr(std::is_same<T, jdouble>::value) + env->SetDoubleField(obj, id, value); + else if constexpr(std::is_convertible<T, jobject>::value) + env->SetObjectField(obj, id, value); + else + staticAssertTypeMismatch(); + } + + template<typename T> + static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz, + jfieldID id, T value) + { + if constexpr(std::is_same<T, jboolean>::value) + env->SetStaticBooleanField(clazz, id, value); + else if constexpr(std::is_same<T, jbyte>::value) + env->SetStaticByteField(clazz, id, value); + else if constexpr(std::is_same<T, jchar>::value) + env->SetStaticCharField(clazz, id, value); + else if constexpr(std::is_same<T, jshort>::value) + env->SetStaticShortField(clazz, id, value); + else if constexpr(std::is_same<T, jint>::value) + env->SetStaticIntField(clazz, id, value); + else if constexpr(std::is_same<T, jlong>::value) + env->SetStaticLongField(clazz, id, value); + else if constexpr(std::is_same<T, jfloat>::value) + env->SetStaticFloatField(clazz, id, value); + else if constexpr(std::is_same<T, jdouble>::value) + env->SetStaticDoubleField(clazz, id, value); + else if constexpr(std::is_convertible<T, jobject>::value) + env->SetStaticObjectField(clazz, id, value); + else + staticAssertTypeMismatch(); + } + + friend QJniObjectPrivate; QSharedPointer<QJniObjectPrivate> d; }; @@ -210,4 +748,6 @@ inline bool operator!=(const QJniObject &obj1, const QJniObject &obj2) QT_END_NAMESPACE +#endif + #endif // QJNIOBJECT_H diff --git a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp index 96637a72a6..7b5c60a7d7 100644 --- a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp +++ b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp @@ -26,6 +26,8 @@ ** ****************************************************************************/ +#include <jni.h> + #include <QString> #include <QtCore/QJniEnvironment> #include <QtCore/QJniObject> @@ -520,9 +522,9 @@ void tst_QJniObject::callStaticLongMethod() void tst_QJniObject::getStaticObjectFieldClassName() { { - QJniObject boolObject = QJniObject::getStaticObjectField<jobject>("java/lang/Boolean", - "FALSE", - "Ljava/lang/Boolean;"); + QJniObject boolObject = QJniObject::getStaticObjectField("java/lang/Boolean", + "FALSE", + "Ljava/lang/Boolean;"); QVERIFY(boolObject.isValid()); jboolean booleanValue = boolObject.callMethod<jboolean>("booleanValue"); @@ -530,9 +532,9 @@ void tst_QJniObject::getStaticObjectFieldClassName() } { - QJniObject boolObject = QJniObject::getStaticObjectField<jobject>("java/lang/Boolean", - "TRUE", - "Ljava/lang/Boolean;"); + QJniObject boolObject = QJniObject::getStaticObjectField("java/lang/Boolean", + "TRUE", + "Ljava/lang/Boolean;"); QVERIFY(boolObject.isValid()); jboolean booleanValue = boolObject.callMethod<jboolean>("booleanValue"); @@ -556,9 +558,9 @@ void tst_QJniObject::getStaticObjectField() QVERIFY(cls != 0); { - QJniObject boolObject = QJniObject::getStaticObjectField<jobject>(cls, - "FALSE", - "Ljava/lang/Boolean;"); + QJniObject boolObject = QJniObject::getStaticObjectField(cls, + "FALSE", + "Ljava/lang/Boolean;"); QVERIFY(boolObject.isValid()); jboolean booleanValue = boolObject.callMethod<jboolean>("booleanValue"); @@ -566,9 +568,9 @@ void tst_QJniObject::getStaticObjectField() } { - QJniObject boolObject = QJniObject::getStaticObjectField<jobject>(cls, - "TRUE", - "Ljava/lang/Boolean;"); + QJniObject boolObject = QJniObject::getStaticObjectField(cls, + "TRUE", + "Ljava/lang/Boolean;"); QVERIFY(boolObject.isValid()); jboolean booleanValue = boolObject.callMethod<jboolean>("booleanValue"); |