QJniObject: add callStaticMethod overload that takes class as type

Equivalent to get/setStaticField.

Add a test, and tighten up the surrounding test code a bit.

Change-Id: Ic0993c5d6223f4de271cb01baf727459b5167f94
Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
Reviewed-by: Petri Virkkunen <petri.virkkunen@qt.io>
Reviewed-by: Zoltan Gera <zoltan.gera@qt.io>
This commit is contained in:
Volker Hilsheimer 2023-09-12 17:52:25 +02:00
parent e1a349983c
commit cf0bd543d6
3 changed files with 47 additions and 13 deletions

View File

@ -970,7 +970,7 @@ QByteArray QJniObject::className() const
\since 6.4
Calls the static method \a methodName on \a clazz and returns the value of type \c Ret
(unless c Ret is \c void). If \c Ret if a jobject type, then the returned value will
(unless \c Ret is \c void). If \c Ret is a jobject type, then the returned value will
be a QJniObject.
\code
@ -982,6 +982,18 @@ QByteArray QJniObject::className() const
The method signature is deduced at compile time from \c Ret and the types of \a args.
*/
/*!
\fn template <typename Klass, typename Ret, typename ...Args> auto QJniObject::callStaticMethod(const char *methodName, Args &&...args)
\since 6.7
Calls the static method \a methodName on the class \c Klass and returns the value of type
\c Ret (unless \c Ret is \c void). If \c Ret is a jobject type, then the returned value will
be a QJniObject.
The method signature is deduced at compile time from \c Ret and the types of \a args.
\c Klass needs to be a C++ type with a registered type mapping to a Java type.
*/
/*!
\fn QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const

View File

@ -127,7 +127,8 @@ public:
static auto callStaticMethod(jclass clazz, const char *methodName, const char *signature, Args &&...args)
{
QJniEnvironment env;
jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true);
jmethodID id = clazz ? getMethodID(env.jniEnv(), clazz, methodName, signature, true)
: 0;
return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...);
}
@ -181,6 +182,21 @@ public:
constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
return callStaticMethod<Ret>(clazz, methodName, signature.data(), std::forward<Args>(args)...);
}
template <typename Klass, typename Ret, typename ...Args
#ifndef Q_QDOC
, QtJniTypes::ValidSignatureTypes<Ret, Args...> = true
#endif
>
static auto callStaticMethod(const char *methodName, Args &&...args)
{
QJniEnvironment env;
const jclass clazz = QJniObject::loadClass(QtJniTypes::className<Klass>().data(),
env.jniEnv());
const jmethodID id = clazz ? getMethodID(env.jniEnv(), clazz, methodName,
QtJniTypes::methodSignature<Ret, Args...>().data(), true)
: 0;
return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...);
}
static QJniObject callStaticObjectMethod(const char *className, const char *methodName,
const char *signature, ...);
@ -547,6 +563,8 @@ private:
static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz,
jmethodID id, ...)
{
if (!clazz || !id)
return;
va_list args = {};
va_start(args, id);
if constexpr (std::is_same_v<T, jboolean>)
@ -572,6 +590,8 @@ private:
static void callStaticMethodForVoid(JNIEnv *env, jclass clazz, jmethodID id, ...)
{
if (!clazz || !id)
return;
va_list args;
va_start(args, id);
env->CallStaticVoidMethodV(clazz, id, args);

View File

@ -8,6 +8,8 @@
#include <QtCore/QJniObject>
#include <QtTest>
using namespace Qt::StringLiterals;
static const char testClassName[] = "org/qtproject/qt/android/testdatapackage/QtJniObjectTestClass";
Q_DECLARE_JNI_CLASS(QtJniObjectTestClass, testClassName)
@ -310,7 +312,8 @@ void tst_QJniObject::callStaticObjectMethod()
jclass cls = env->FindClass("java/lang/String");
QVERIFY(cls != 0);
QJniObject formatString = QJniObject::fromString(QLatin1String("test format"));
const QString string = u"test format"_s;
QJniObject formatString = QJniObject::fromString(string);
QVERIFY(formatString.isValid());
QJniObject returnValue = QJniObject::callStaticObjectMethod(cls,
@ -319,20 +322,14 @@ void tst_QJniObject::callStaticObjectMethod()
formatString.object<jstring>(),
jobjectArray(0));
QVERIFY(returnValue.isValid());
QString returnedString = returnValue.toString();
QCOMPARE(returnedString, QString::fromLatin1("test format"));
QCOMPARE(returnValue.toString(), string);
returnValue = QJniObject::callStaticObjectMethod<jstring>(cls,
"format",
formatString.object<jstring>(),
jobjectArray(0));
QVERIFY(returnValue.isValid());
returnedString = returnValue.toString();
QCOMPARE(returnedString, QString::fromLatin1("test format"));
QCOMPARE(returnValue.toString(), string);
// from 6.4 on we can use callStaticMethod
returnValue = QJniObject::callStaticMethod<jstring>(cls,
@ -340,10 +337,15 @@ void tst_QJniObject::callStaticObjectMethod()
formatString.object<jstring>(),
jobjectArray(0));
QVERIFY(returnValue.isValid());
QCOMPARE(returnValue.toString(), string);
returnedString = returnValue.toString();
// from 6.7 we can use callStaticMethod without specifying the class string
returnValue = QJniObject::callStaticMethod<jstring, jstring>("format",
formatString.object<jstring>(),
jobjectArray(0));
QVERIFY(returnValue.isValid());
QCOMPARE(returnValue.toString(), string);
QCOMPARE(returnedString, QString::fromLatin1("test format"));
}
void tst_QJniObject::callStaticObjectMethodById()