diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/kernel/qjnienvironment.cpp | 51 | ||||
-rw-r--r-- | src/corelib/kernel/qjnienvironment.h | 21 | ||||
-rw-r--r-- | src/corelib/kernel/qjniobject.cpp | 151 | ||||
-rw-r--r-- | src/corelib/kernel/qjniobject.h | 269 |
4 files changed, 301 insertions, 191 deletions
diff --git a/src/corelib/kernel/qjnienvironment.cpp b/src/corelib/kernel/qjnienvironment.cpp index 9766ff4d3b9..3eab31bbc26 100644 --- a/src/corelib/kernel/qjnienvironment.cpp +++ b/src/corelib/kernel/qjnienvironment.cpp @@ -232,6 +232,16 @@ jmethodID QJniEnvironment::findMethod(jclass clazz, const char *methodName, cons } /*! + \fn template<typename ...Args> jmethodId QJniEnvironment::findMethod(jclass clazz, const char *methodName) + \since 6.4 + + Searches for an instance method of a class \a clazz. The method is specified + by its \a methodName, the signature is deduced from the template parameters. + + Returns the method ID or \c nullptr if the method is not found. +*/ + +/*! Searches for a static method of a class \a clazz. The method is specified by its \a methodName and \a signature. @@ -265,9 +275,28 @@ jmethodID QJniEnvironment::findStaticMethod(jclass clazz, const char *methodName return nullptr; } +/*! + \fn template<typename ...Args> jmethodId QJniEnvironment::findStaticMethod(jclass clazz, const char *methodName) + \since 6.4 + + Searches for an instance method of a class \a clazz. The method is specified + by its \a methodName, the signature is deduced from the template parameters. + + Returns the method ID or \c nullptr if the method is not found. + + \code + QJniEnvironment env; + jclass javaClass = env.findClass("org/qtproject/example/android/CustomClass"); + jmethodID methodId = env.findStaticMethod<void, jstring>(javaClass, "staticJavaMethod"); + QJniObject javaMessage = QJniObject::fromString("findStaticMethod example"); + QJniObject::callStaticMethod<void>(javaClass, + methodId, + javaMessage.object<jstring>()); + \endcode +*/ /*! - Searches for an member field of a class \a clazz. The field is specified + Searches for a member field of a class \a clazz. The field is specified by its \a fieldName and \a signature. Returns the field ID or \c nullptr if the field is not found. @@ -289,6 +318,16 @@ jfieldID QJniEnvironment::findField(jclass clazz, const char *fieldName, const c } /*! + \fn template<typename T> jfieldID QJniEnvironment::findField(jclass clazz, const char *fieldName) + \since 6.4 + + Searches for a member field of a class \a clazz. The field is specified + by its \a fieldName. The signature of the field is deduced from the template parameter. + + Returns the field ID or \c nullptr if the field is not found. +*/ + +/*! Searches for a static field of a class \a clazz. The field is specified by its \a fieldName and \a signature. @@ -311,6 +350,16 @@ jfieldID QJniEnvironment::findStaticField(jclass clazz, const char *fieldName, c } /*! + \fn template<typename T> jfieldID QJniEnvironment::findStaticField(jclass clazz, const char *fieldName) + \since 6.4 + + Searches for a static field of a class \a clazz. The field is specified + by its \a fieldName. The signature of the field is deduced from the template parameter. + + Returns the field ID or \c nullptr if the field is not found. +*/ + +/*! \fn JavaVM *QJniEnvironment::javaVM() Returns the Java VM interface for the current process. Although it might diff --git a/src/corelib/kernel/qjnienvironment.h b/src/corelib/kernel/qjnienvironment.h index 16a6413d318..8263d04834d 100644 --- a/src/corelib/kernel/qjnienvironment.h +++ b/src/corelib/kernel/qjnienvironment.h @@ -44,6 +44,7 @@ #if defined(Q_QDOC) || defined(Q_OS_ANDROID) #include <jni.h> +#include <QtCore/qjnitypes.h> QT_BEGIN_NAMESPACE @@ -60,9 +61,29 @@ public: JNIEnv *jniEnv() const; jclass findClass(const char *className); jmethodID findMethod(jclass clazz, const char *methodName, const char *signature); + template<typename ...Args> + jmethodID findMethod(jclass clazz, const char *methodName) { + constexpr auto signature = QtJniTypes::methodSignature<Args...>(); + return findMethod(clazz, methodName, signature.data()); + } jmethodID findStaticMethod(jclass clazz, const char *methodName, const char *signature); + template<typename ...Args> + jmethodID findStaticMethod(jclass clazz, const char *methodName) { + constexpr auto signature = QtJniTypes::methodSignature<Args...>(); + return findStaticMethod(clazz, methodName, signature.data()); + } jfieldID findField(jclass clazz, const char *fieldName, const char *signature); + template<typename T> + jfieldID findField(jclass clazz, const char *fieldName) { + constexpr auto signature = QtJniTypes::fieldSignature<T>(); + return findField(clazz, fieldName, signature.data()); + } jfieldID findStaticField(jclass clazz, const char *fieldName, const char *signature); + template<typename T> + jfieldID findStaticField(jclass clazz, const char *fieldName) { + constexpr auto signature = QtJniTypes::fieldSignature<T>(); + return findStaticField(clazz, fieldName, signature.data()); + } static JavaVM *javaVM(); bool registerNativeMethods(const char *className, const JNINativeMethod methods[], int size); bool registerNativeMethods(jclass clazz, const JNINativeMethod methods[], int size); diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp index fcc4851c74c..e801aa958f3 100644 --- a/src/corelib/kernel/qjniobject.cpp +++ b/src/corelib/kernel/qjniobject.cpp @@ -76,55 +76,77 @@ using namespace Qt::StringLiterals; \section1 Method Signatures - For functions that take no arguments, QJniObject provides convenience functions that will use - the correct signature based on the provided template type. For example: + QJniObject provides convenience functions that will use the correct signature based on the + provided template types. For functions that only return and take \l {JNI types}, the + signature can be generate at compile time: \code jint x = QJniObject::callMethod<jint>("getSize"); QJniObject::callMethod<void>("touch"); + jint ret = jString1.callMethod<jint>("compareToIgnoreCase", jString2.object<jstring>()); \endcode - In other cases you will need to supply the signature yourself, and it is important that the - signature matches the function you want to call. The signature structure is - \c "(ArgumentsTypes)ReturnType". Array types in the signature must have the \c {[} prefix, - and the fully-qualified \c Object type names must have the \c L prefix and the \c ; suffix. + These functions are variadic templates, and the compiler will deduce the template arguments + from the actual argument types. In many situations, only the return type needs to be provided + explicitly. - The example below demonstrates how to call two different static functions: + For functions that take other argument types, you need to supply the signature yourself. It is + important that the signature matches the function you want to call. The example below + demonstrates how to call different static functions: \code // Java class package org.qtproject.qt; class TestClass { - static String fromNumber(int x) { ... } - static String[] stringArray(String s1, String s2) { ... } + static TestClass create() { ... } + static String fromNumber(int x) { ... } + static String[] stringArray(String s1, String s2) { ... } } \endcode - The signature for the first function is \c {"(I)Ljava/lang/String;"}: + The signature structure is \c "(ArgumentsTypes)ReturnType". Array types in the signature + must have the \c {[} prefix, and the fully-qualified \c Object type names must have the + \c L prefix and the \c ; suffix. The signature for the \c create function is + \c {"()Lorg/qtproject/qt/TestClass;}. The signatures for the second and third functions + are \c {"(I)Ljava/lang/String;"} and + \c {"(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"}, respectively. + + We can call the \c create() function like this: + + \code + // C++ code + QJniObject testClass = QJniObject::callStaticObjectMethod("org/qtproject/qt/TestClass", + "create", + "()Lorg/qtproject/qt/TestClass;"); + \endcode + + For the second and third function we can rely on QJniObject's template methods to create + the implicit signature string, but we can also pass the signature string explicitly: \code // C++ code QJniObject stringNumber = QJniObject::callStaticObjectMethod("org/qtproject/qt/TestClass", - "fromNumber" - "(I)Ljava/lang/String;", - 10); + "fromNumber", + "(I)Ljava/lang/String;", 10); \endcode - and the signature for the second function is - \c {"(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"}: + For the implicit signature creation to work we need to specify the return type explicitly: \code // C++ code QJniObject string1 = QJniObject::fromString("String1"); QJniObject string2 = QJniObject::fromString("String2"); - QJniObject stringArray = QJniObject::callStaticObjectMethod("org/qtproject/qt/TestClass", + QJniObject stringArray = QJniObject::callStaticObjectMethod<jstringArray>( + "org/qtproject/qt/TestClass", "stringArray" - "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;" string1.object<jstring>(), string2.object<jstring>()); \endcode + Note that while he first template parameter specifies the return type of the Java + function, the method will still return a QJniObject. + \section1 Handling Java Exception After calling Java functions that might throw exceptions, it is important @@ -403,9 +425,12 @@ jmethodID QJniObject::getMethodID(JNIEnv *env, return id; } -void QJniObject::callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const +void QJniObject::callVoidMethodV(JNIEnv *env, jmethodID id, ...) const { + va_list args; + va_start(args, id); env->CallVoidMethodV(d->m_jobject, id, args); + va_end(args); } jmethodID QJniObject::getCachedMethodID(JNIEnv *env, @@ -620,6 +645,22 @@ QJniObject::QJniObject(const char *className, const char *signature, ...) } } +/*! + \fn template<typename ...Args> QJniObject::QJniObject(const char *className, Args &&...args) + \since 6.4 + + Constructs a new JNI object by calling the constructor of \a className with + the arguments \a args. This constructor is only available if all \a args are + known \l {JNI Types}. + + \code + QJniEnvironment env; + char* str = "Hello"; + jstring myJStringArg = env->NewStringUTF(str); + QJniObject myNewJavaString("java/lang/String", myJStringArg); + \endcode +*/ + QJniObject::QJniObject(const char *className, const char *signature, const QVaListPrivate &args) : d(new QJniObjectPrivate()) { @@ -672,6 +713,21 @@ QJniObject::QJniObject(jclass clazz, const char *signature, ...) } /*! + \fn template<typename ...Args> QJniObject::QJniObject(jclass clazz, Args &&...args) + \since 6.4 + + Constructs a new JNI object from \a clazz by calling the constructor with + the arguments \a args. This constructor is only available if all \a args are + known \l {JNI Types}. + + \code + QJniEnvironment env; + jclass myClazz = env.findClass("org/qtproject/qt/TestClass"); + QJniObject(myClazz, 3); + \endcode +*/ + +/*! Constructs a new JNI object by calling the default constructor of \a clazz. \note The QJniObject will create a new reference to the class \a clazz @@ -883,10 +939,11 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz, } /*! - \fn template <typename T> T QJniObject::callMethod(const char *methodName, const char *signature, ...) const + \fn template <typename Ret, typename ...Args> Ret QJniObject::callMethod(const char *methodName, const char *signature, Args &&...args) const + \since 6.4 Calls the object's method \a methodName with \a signature specifying the types of any - subsequent arguments. + subsequent arguments \a args. \code QJniObject myJavaStrin("org/qtproject/qt/TestClass"); @@ -896,21 +953,25 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz, */ /*! - \fn template <typename T> T QJniObject::callMethod(const char *methodName) const + \fn template <typename Ret, typename ...Args> Ret QJniObject::callMethod(const char *methodName, Args &&...args) const + \since 6.4 - Calls the method \a methodName and returns the value. + Calls the method \a methodName with arguments \a args and returns the value. \code QJniObject myJavaStrin("org/qtproject/qt/TestClass"); jint size = myJavaString.callMethod<jint>("length"); \endcode + + The method signature is deduced at compile time from \c Ret and the types of \a args. */ /*! - \fn template <typename T> T QJniObject::callStaticMethod(const char *className, const char *methodName, const char *signature, ...) + \fn template <typename Ret, typename ...Args> Ret QJniObject::callStaticMethod(const char *className, const char *methodName, const char *signature, Args &&...args) + \since 6.4 Calls the static method \a methodName from class \a className with \a signature - specifying the types of any subsequent arguments. + specifying the types of any subsequent arguments \a args. \code jint a = 2; @@ -920,17 +981,21 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz, */ /*! - \fn template <typename T> T QJniObject::callStaticMethod(const char *className, const char *methodName) + \fn template <typename Ret, typename ...Args> Ret QJniObject::callStaticMethod(const char *className, const char *methodName, Args &&...args) + \since 6.4 - Calls the static method \a methodName on class \a className and returns the value. + Calls the static method \a methodName on class \a className with arguments \a args, + and returns the value of type \c Ret. \code jint value = QJniObject::callStaticMethod<jint>("MyClass", "staticMethod"); \endcode + + The method signature is deduced at compile time from \c Ret and the types of \a args. */ /*! - \fn template <typename T> T QJniObject::callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...) + \fn template <typename Ret, typename ...Args> Ret QJniObject::callStaticMethod(jclass clazz, const char *methodName, const char *signature, Args &&...args) Calls the static method \a methodName from \a clazz with \a signature specifying the types of any subsequent arguments. @@ -945,7 +1010,8 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz, */ /*! - \fn template <typename T> T QJniObject::callStaticMethod(jclass clazz, jmethodID methodId, ...) + \fn template <typename Ret, typename ...Args> Ret QJniObject::callStaticMethod(jclass clazz, jmethodID methodId, Args &&...args) + \since 6.4 Calls the static method identified by \a methodId from the class \a clazz with any subsequent arguments. Useful when \a clazz and \a methodId are @@ -964,7 +1030,8 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz, */ /*! - \fn template <typename T> T QJniObject::callStaticMethod(jclass clazz, const char *methodName) + \fn template <typename Ret, typename ...Args> Ret QJniObject::callStaticMethod(jclass clazz, const char *methodName, Args &&...args) + \since 6.4 Calls the static method \a methodName on \a clazz and returns the value. @@ -973,6 +1040,8 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz, jclass javaMathClass = env.findClass("java/lang/Math"); jdouble randNr = QJniObject::callStaticMethod<jdouble>(javaMathClass, "random"); \endcode + + The method signature is deduced at compile time from \c Ret and the types of \a args. */ /*! @@ -1090,32 +1159,40 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId, } /*! - \fn QJniObject QJniObject::callObjectMethod(const char *methodName) const + \fn template<typename Ret, typename ...Args> QJniObject QJniObject::callObjectMethod(const char *methodName, Args &&...args) const + \since 6.4 - Calls the Java objects method \a methodName and returns a new QJniObject for - the returned Java object. + Calls the Java objects method \a methodName with arguments \a args and returns a + new QJniObject for the returned Java object. \code QJniObject myJavaString = QJniObject::fromString("Hello, Java"); QJniObject myJavaString2 = myJavaString1.callObjectMethod<jstring>("toString"); \endcode + + The method signature is deduced at compile time from \c Ret and the types of \a args. */ /*! - \fn QJniObject QJniObject::callStaticObjectMethod(const char *className, const char *methodName) + \fn template<typename Ret, typename ...Args> QJniObject QJniObject::callStaticObjectMethod(const char *className, const char *methodName, Args &&...args) + \since 6.4 - Calls the static method with \a methodName on the class \a className. + Calls the static method with \a methodName on the class \a className, passing + arguments \a args, and returns a new QJniObject for the returned Java object. \code QJniObject string = QJniObject::callStaticObjectMethod<jstring>("CustomClass", "getClassName"); \endcode + + The method signature is deduced at compile time from \c Ret and the types of \a args. */ /*! - \fn QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodName) - - Calls the static method with \a methodName on \a clazz. + \fn template<typename Ret, typename ...Args> QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodName, Args &&...args) + \since 6.4 + Calls the static method with \a methodName on \a clazz, passing arguments \a args, + and returns a new QJniObject for the returned Java object. */ /*! diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h index 829823efecf..56700ddcbfa 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<typename ...Args +#ifndef Q_QDOC + , std::enable_if_t<!std::disjunction_v<QtJniTypes::IsStringType<std::decay_t<Args>>...>>* = nullptr +#endif + > + explicit QJniObject(const char *className, Args &&...args) + : QJniObject(className, QtJniTypes::constructorSignature<Args...>().data(), + std::forward<Args>(args)...) + {} explicit QJniObject(jclass clazz); explicit QJniObject(jclass clazz, const char *signature, ...); + template<typename ...Args +#ifndef Q_QDOC + , std::enable_if_t<!std::disjunction_v<QtJniTypes::IsStringType<std::decay_t<Args>>...>>* = nullptr +#endif + > + explicit QJniObject(jclass clazz, Args &&...args) + : QJniObject(clazz, QtJniTypes::constructorSignature<Args...>().data(), + std::forward<Args>(args)...) + {} QJniObject(jobject globalRef); ~QJniObject(); @@ -72,206 +90,135 @@ public: jclass objectClass() const; QByteArray className() const; - template <typename T> - T callMethod(const char *methodName, const char *signature, ...) const + template <typename Ret, typename ...Args> + Ret callMethod(const char *methodName, const char *signature, Args &&...args) const { - QtJniTypes::assertPrimitiveType<T>(); + QtJniTypes::assertPrimitiveType<Ret>(); 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 = {}; + if constexpr (std::is_same<Ret, void>::value) { + callVoidMethodV(env.jniEnv(), id, std::forward<Args>(args)...); + env.checkAndClearExceptions(); + } else { + Ret res{}; + callMethodForType<Ret>(env.jniEnv(), res, object(), id, std::forward<Args>(args)...); + if (env.checkAndClearExceptions()) + res = {}; + return res; + } } - return res; + if constexpr (!std::is_same<Ret, void>::value) + return Ret{}; } - template <> - void callMethod<void>(const char *methodName, const char *signature, ...) const + template <typename Ret, typename ...Args> + 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<Ret, Args...>(); + if constexpr (std::is_same<Ret, void>::value) { + callMethod<void>(methodName, signature.data(), std::forward<Args>(args)...); + } else { + QtJniTypes::assertPrimitiveType<Ret>(); + return callMethod<Ret>(methodName, signature.data(), std::forward<Args>(args)...); } } - template <typename T> - T callMethod(const char *methodName) const - { - QtJniTypes::assertPrimitiveType<T>(); - constexpr auto signature = QtJniTypes::methodSignature<T>(); - return callMethod<T>(methodName, signature); - } - - template <typename T> - QJniObject callObjectMethod(const char *methodName) const + template <typename Ret, typename ...Args> + QJniObject callObjectMethod(const char *methodName, Args &&...args) const { - QtJniTypes::assertObjectType<T>(); - constexpr auto signature = QtJniTypes::methodSignature<T>(); - return callObjectMethod(methodName, signature); + QtJniTypes::assertObjectType<Ret>(); + constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>(); + return callObjectMethod(methodName, signature.data(), std::forward<Args>(args)...); } QJniObject callObjectMethod(const char *methodName, const char *signature, ...) const; - template <typename T> - static T callStaticMethod(const char *className, const char *methodName, - const char *signature, ...) - { - QtJniTypes::assertPrimitiveType<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, ...) + template <typename Ret, typename ...Args> + static Ret callStaticMethod(const char *className, const char *methodName, const char *signature, Args &&...args) { + QtJniTypes::assertPrimitiveType<Ret>(); 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(const char *className, const char *methodName) - { - QtJniTypes::assertPrimitiveType<T>(); - constexpr auto signature = QtJniTypes::methodSignature<T>(); - return callStaticMethod<T>(className, methodName, signature); + return callStaticMethod<Ret>(clazz, methodName, signature, std::forward<Args>(args)...); } - template <typename T> - static T callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...) + template <typename Ret, typename ...Args> + static Ret callStaticMethod(jclass clazz, const char *methodName, const char *signature, Args &&...args) { - QtJniTypes::assertPrimitiveType<T>(); + QtJniTypes::assertPrimitiveType<Ret>(); 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 callStaticMethod<Ret, Args...>(clazz, id, std::forward<Args>(args)...); } - return res; + if constexpr (!std::is_same<Ret, void>::value) + return Ret{}; } - template <> - void callStaticMethod<void>(jclass clazz, const char *methodName, - const char *signature, ...) + template <typename Ret, typename ...Args> + static Ret callStaticMethod(jclass clazz, jmethodID methodId, Args &&...args) { + QtJniTypes::assertPrimitiveType<Ret>(); 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<Ret, void>::value) { + callStaticMethodForVoid(env.jniEnv(), clazz, methodId, std::forward<Args>(args)...); env.checkAndClearExceptions(); + } else { + Ret res{}; + callStaticMethodForType<Ret>(env.jniEnv(), res, clazz, methodId, std::forward<Args>(args)...); + if (env.checkAndClearExceptions()) + res = {}; + return res; } } + if constexpr (!std::is_same<Ret, void>::value) + return Ret{}; } - template <typename T> - static T callStaticMethod(jclass clazz, jmethodID methodId, ...) - { - QtJniTypes::assertPrimitiveType<T>(); - QJniEnvironment env; - T res{}; - if (clazz && methodId) { - va_list args; - va_start(args, methodId); - callStaticMethodForType<T>(env.jniEnv(), res, clazz, methodId, args); - va_end(args); - if (env.checkAndClearExceptions()) - res = {}; - } - return res; - } - - template <> - void callStaticMethod<void>(jclass clazz, jmethodID methodId, ...) + template <typename Ret, typename ...Args> + static Ret callStaticMethod(const char *className, const char *methodName, Args &&...args) { + QtJniTypes::assertPrimitiveType<Ret>(); QJniEnvironment env; - if (clazz && methodId) { - va_list args; - va_start(args, methodId); - env->CallStaticVoidMethodV(clazz, methodId, args); - va_end(args); - env.checkAndClearExceptions(); - } - } - - template <typename T> static T callStaticMethod(jclass clazz, const char *methodName) - { - QtJniTypes::assertPrimitiveType<T>(); - constexpr auto signature = QtJniTypes::methodSignature<T>(); - return callStaticMethod<T>(clazz, methodName, signature); + jclass clazz = QJniObject::loadClass(className, env.jniEnv()); + return callStaticMethod<Ret, Args...>(clazz, methodName, std::forward<Args>(args)...); } - template <typename T> - static QJniObject callStaticObjectMethod(const char *className, const char *methodName) + template <typename Ret, typename ...Args> + static Ret callStaticMethod(jclass clazz, const char *methodName, Args &&...args) { - QtJniTypes::assertObjectType<T>(); - constexpr auto signature = QtJniTypes::methodSignature<T>(); - return callStaticObjectMethod(className, methodName, signature); + QtJniTypes::assertPrimitiveType<Ret>(); + constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>(); + return callStaticMethod<Ret>(clazz, methodName, signature.data(), std::forward<Args>(args)...); } static QJniObject callStaticObjectMethod(const char *className, const char *methodName, const char *signature, ...); - template <typename T> - static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName) - { - QtJniTypes::assertObjectType<T>(); - constexpr auto signature = QtJniTypes::methodSignature<T>(); - return callStaticObjectMethod(clazz, methodName, signature); - } - static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName, const char *signature, ...); static QJniObject callStaticObjectMethod(jclass clazz, jmethodID methodId, ...); + + template <typename Ret, typename ...Args> + static QJniObject callStaticObjectMethod(const char *className, const char *methodName, Args &&...args) + { + QtJniTypes::assertObjectType<Ret>(); + constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>(); + return callStaticObjectMethod(className, methodName, signature.data(), std::forward<Args>(args)...); + } + + template <typename Ret, typename ...Args> + static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName, Args &&...args) + { + QtJniTypes::assertObjectType<Ret>(); + constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>(); + return callStaticObjectMethod(clazz, methodName, signature.data(), std::forward<Args>(args)...); + } + template <typename T> T getField(const char *fieldName) const { QtJniTypes::assertPrimitiveType<T>(); @@ -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<typename T> 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<T, jboolean>::value) res = env->CallBooleanMethodV(obj, id, args); else if constexpr(std::is_same<T, jbyte>::value) @@ -530,12 +480,15 @@ private: res = env->CallDoubleMethodV(obj, id, args); else QtJniTypes::staticAssertTypeMismatch(); + va_end(args); } template<typename T> 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<T, jboolean>::value) res = env->CallStaticBooleanMethodV(clazz, id, args); else if constexpr(std::is_same<T, jbyte>::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<typename T> static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id) |