From 601dbd64993fcbbb2ce6aaa95ef153ffd4f852b9 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Sat, 23 Apr 2022 16:43:35 +0200 Subject: Add variadic template overloads for QJniObject/Environment methods This allows the compiler to deduce the template arguments based on the provided method parameters, which we can then pass to the methodSignature and fieldSignature helpers to generate the signature string completely at compile time. Since we can't partially specialize template member functions, replace the specializations for void methods with compile-time-if branches in the general templates. This variadic template now prevents implicit conversion from the LiteralStorage types to const char* signatures, so catch the case where such a type ends up in the parameter list. Due to overload resolution rules for constructors, we need to explicitly disable the constructor if any of the arguments is a string literal type, as we have to keep the old C-style variadic function working for such calls. Add variations that use the variadic templates to the unit tests. Change-Id: I8734664b38bae932369462330a9a03302254c33c Reviewed-by: Assam Boudjelthia --- src/corelib/kernel/qjniobject.h | 269 +++++++++++++++++----------------------- 1 file changed, 116 insertions(+), 153 deletions(-) (limited to 'src/corelib/kernel/qjniobject.h') diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h index 829823efec..56700ddcbf 100644 --- a/src/corelib/kernel/qjniobject.h +++ b/src/corelib/kernel/qjniobject.h @@ -57,8 +57,26 @@ public: QJniObject(); explicit QJniObject(const char *className); explicit QJniObject(const char *className, const char *signature, ...); + template>...>>* = nullptr +#endif + > + explicit QJniObject(const char *className, Args &&...args) + : QJniObject(className, QtJniTypes::constructorSignature().data(), + std::forward(args)...) + {} explicit QJniObject(jclass clazz); explicit QJniObject(jclass clazz, const char *signature, ...); + template>...>>* = nullptr +#endif + > + explicit QJniObject(jclass clazz, Args &&...args) + : QJniObject(clazz, QtJniTypes::constructorSignature().data(), + std::forward(args)...) + {} QJniObject(jobject globalRef); ~QJniObject(); @@ -72,206 +90,135 @@ public: jclass objectClass() const; QByteArray className() const; - template - T callMethod(const char *methodName, const char *signature, ...) const + template + Ret callMethod(const char *methodName, const char *signature, Args &&...args) const { - QtJniTypes::assertPrimitiveType(); + QtJniTypes::assertPrimitiveType(); QJniEnvironment env; - T res{}; jmethodID id = getCachedMethodID(env.jniEnv(), methodName, signature); if (id) { - va_list args; - va_start(args, signature); - callMethodForType(env.jniEnv(), res, object(), id, args); - va_end(args); - if (env.checkAndClearExceptions()) - res = {}; + if constexpr (std::is_same::value) { + callVoidMethodV(env.jniEnv(), id, std::forward(args)...); + env.checkAndClearExceptions(); + } else { + Ret res{}; + callMethodForType(env.jniEnv(), res, object(), id, std::forward(args)...); + if (env.checkAndClearExceptions()) + res = {}; + return res; + } } - return res; + if constexpr (!std::is_same::value) + return Ret{}; } - template <> - void callMethod(const char *methodName, const char *signature, ...) const + template + Ret callMethod(const char *methodName, Args &&...args) 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(); + constexpr auto signature = QtJniTypes::methodSignature(); + if constexpr (std::is_same::value) { + callMethod(methodName, signature.data(), std::forward(args)...); + } else { + QtJniTypes::assertPrimitiveType(); + return callMethod(methodName, signature.data(), std::forward(args)...); } } - template - T callMethod(const char *methodName) const - { - QtJniTypes::assertPrimitiveType(); - constexpr auto signature = QtJniTypes::methodSignature(); - return callMethod(methodName, signature); - } - - template - QJniObject callObjectMethod(const char *methodName) const + template + QJniObject callObjectMethod(const char *methodName, Args &&...args) const { - QtJniTypes::assertObjectType(); - constexpr auto signature = QtJniTypes::methodSignature(); - return callObjectMethod(methodName, signature); + QtJniTypes::assertObjectType(); + constexpr auto signature = QtJniTypes::methodSignature(); + return callObjectMethod(methodName, signature.data(), std::forward(args)...); } QJniObject callObjectMethod(const char *methodName, const char *signature, ...) const; - template - static T callStaticMethod(const char *className, const char *methodName, - const char *signature, ...) - { - QtJniTypes::assertPrimitiveType(); - 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(env.jniEnv(), res, clazz, id, args); - va_end(args); - if (env.checkAndClearExceptions()) - res = {}; - } - } - return res; - } - - template <> - void callStaticMethod(const char *className, const char *methodName, - const char *signature, ...) + template + static Ret callStaticMethod(const char *className, const char *methodName, const char *signature, Args &&...args) { + QtJniTypes::assertPrimitiveType(); 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 - static T callStaticMethod(const char *className, const char *methodName) - { - QtJniTypes::assertPrimitiveType(); - constexpr auto signature = QtJniTypes::methodSignature(); - return callStaticMethod(className, methodName, signature); + return callStaticMethod(clazz, methodName, signature, std::forward(args)...); } - template - static T callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...) + template + static Ret callStaticMethod(jclass clazz, const char *methodName, const char *signature, Args &&...args) { - QtJniTypes::assertPrimitiveType(); + QtJniTypes::assertPrimitiveType(); 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(env.jniEnv(), res, clazz, id, args); - va_end(args); - if (env.checkAndClearExceptions()) - res = {}; - } + return callStaticMethod(clazz, id, std::forward(args)...); } - return res; + if constexpr (!std::is_same::value) + return Ret{}; } - template <> - void callStaticMethod(jclass clazz, const char *methodName, - const char *signature, ...) + template + static Ret callStaticMethod(jclass clazz, jmethodID methodId, Args &&...args) { + QtJniTypes::assertPrimitiveType(); 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); + if (clazz && methodId) { + if constexpr (std::is_same::value) { + callStaticMethodForVoid(env.jniEnv(), clazz, methodId, std::forward(args)...); env.checkAndClearExceptions(); + } else { + Ret res{}; + callStaticMethodForType(env.jniEnv(), res, clazz, methodId, std::forward(args)...); + if (env.checkAndClearExceptions()) + res = {}; + return res; } } + if constexpr (!std::is_same::value) + return Ret{}; } - template - static T callStaticMethod(jclass clazz, jmethodID methodId, ...) - { - QtJniTypes::assertPrimitiveType(); - QJniEnvironment env; - T res{}; - if (clazz && methodId) { - va_list args; - va_start(args, methodId); - callStaticMethodForType(env.jniEnv(), res, clazz, methodId, args); - va_end(args); - if (env.checkAndClearExceptions()) - res = {}; - } - return res; - } - - template <> - void callStaticMethod(jclass clazz, jmethodID methodId, ...) + template + static Ret callStaticMethod(const char *className, const char *methodName, Args &&...args) { + QtJniTypes::assertPrimitiveType(); QJniEnvironment env; - if (clazz && methodId) { - va_list args; - va_start(args, methodId); - env->CallStaticVoidMethodV(clazz, methodId, args); - va_end(args); - env.checkAndClearExceptions(); - } - } - - template static T callStaticMethod(jclass clazz, const char *methodName) - { - QtJniTypes::assertPrimitiveType(); - constexpr auto signature = QtJniTypes::methodSignature(); - return callStaticMethod(clazz, methodName, signature); + jclass clazz = QJniObject::loadClass(className, env.jniEnv()); + return callStaticMethod(clazz, methodName, std::forward(args)...); } - template - static QJniObject callStaticObjectMethod(const char *className, const char *methodName) + template + static Ret callStaticMethod(jclass clazz, const char *methodName, Args &&...args) { - QtJniTypes::assertObjectType(); - constexpr auto signature = QtJniTypes::methodSignature(); - return callStaticObjectMethod(className, methodName, signature); + QtJniTypes::assertPrimitiveType(); + constexpr auto signature = QtJniTypes::methodSignature(); + return callStaticMethod(clazz, methodName, signature.data(), std::forward(args)...); } static QJniObject callStaticObjectMethod(const char *className, const char *methodName, const char *signature, ...); - template - static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName) - { - QtJniTypes::assertObjectType(); - constexpr auto signature = QtJniTypes::methodSignature(); - return callStaticObjectMethod(clazz, methodName, signature); - } - static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName, const char *signature, ...); static QJniObject callStaticObjectMethod(jclass clazz, jmethodID methodId, ...); + + template + static QJniObject callStaticObjectMethod(const char *className, const char *methodName, Args &&...args) + { + QtJniTypes::assertObjectType(); + constexpr auto signature = QtJniTypes::methodSignature(); + return callStaticObjectMethod(className, methodName, signature.data(), std::forward(args)...); + } + + template + static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName, Args &&...args) + { + QtJniTypes::assertObjectType(); + constexpr auto signature = QtJniTypes::methodSignature(); + return callStaticObjectMethod(clazz, methodName, signature.data(), std::forward(args)...); + } + template T getField(const char *fieldName) const { QtJniTypes::assertPrimitiveType(); @@ -490,7 +437,7 @@ private: 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; + void callVoidMethodV(JNIEnv *env, jmethodID id, ...) const; QJniObject callObjectMethodV(const char *methodName, const char *signature, va_list args) const; @@ -510,8 +457,11 @@ private: template static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, - jmethodID id, va_list args) + jmethodID id, ...) { + va_list args = {}; + va_start(args, id); + if constexpr(std::is_same::value) res = env->CallBooleanMethodV(obj, id, args); else if constexpr(std::is_same::value) @@ -530,12 +480,15 @@ private: res = env->CallDoubleMethodV(obj, id, args); else QtJniTypes::staticAssertTypeMismatch(); + va_end(args); } template static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz, - jmethodID id, va_list args) + jmethodID id, ...) { + va_list args = {}; + va_start(args, id); if constexpr(std::is_same::value) res = env->CallStaticBooleanMethodV(clazz, id, args); else if constexpr(std::is_same::value) @@ -554,8 +507,18 @@ private: res = env->CallStaticDoubleMethodV(clazz, id, args); else QtJniTypes::staticAssertTypeMismatch(); + va_end(args); + } + + static void callStaticMethodForVoid(JNIEnv *env, jclass clazz, jmethodID id, ...) + { + va_list args; + va_start(args, id); + env->CallStaticVoidMethodV(clazz, id, args); + va_end(args); } + template static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id) -- cgit v1.2.3