summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Solovev <ivan.solovev@qt.io>2021-04-30 11:49:08 +0200
committerIvan Solovev <ivan.solovev@qt.io>2021-05-03 18:09:23 +0200
commit34f72ca52e7312172f75c1f79da0d226d2d4583b (patch)
treef2aa824582a96d931b07220d11904652fd9c88a5
parent96d9cf8de40804690b98d06daf15f2067b527d32 (diff)
QJniEnvironment: extend API
This patch adds some convenience methods to QJniEnvironment API: * an overload of registerNativeMethods() that accepts jclass instead of const char *className. * a findMethod() function is added to query a methodID of a static or nonstatic method by its name and signature. Task-number: QTBUG-92952 Change-Id: Ib1bc892decea97e625c4822888b6183af6edd6dc Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io> Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
-rw-r--r--src/corelib/kernel/qjnienvironment.cpp75
-rw-r--r--src/corelib/kernel/qjnienvironment.h3
-rw-r--r--tests/auto/corelib/kernel/qjnienvironment/testdata/src/org/qtproject/qt/android/testdata/QtJniEnvironmentTestClass.java5
-rw-r--r--tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp69
4 files changed, 147 insertions, 5 deletions
diff --git a/src/corelib/kernel/qjnienvironment.cpp b/src/corelib/kernel/qjnienvironment.cpp
index f7a5fcb686..0e6cafcd91 100644
--- a/src/corelib/kernel/qjnienvironment.cpp
+++ b/src/corelib/kernel/qjnienvironment.cpp
@@ -198,6 +198,54 @@ jclass QJniEnvironment::findClass(const char *className)
}
/*!
+ Searches for an instance method of a class \a clazz. The method is specified
+ by its \a methodName and \a signature.
+
+ Returns the method ID or \c nullptr if the method is not found.
+
+ A usecase for this method is searching for class methods and caching their
+ IDs, so that they could later be used for calling the methods.
+*/
+jmethodID QJniEnvironment::findMethod(jclass clazz, const char *methodName, const char *signature)
+{
+ jmethodID id = d->jniEnv->GetMethodID(clazz, methodName, signature);
+ if (checkAndClearExceptions(d->jniEnv))
+ return nullptr;
+
+ return id;
+}
+
+/*!
+ Searches for a static method of a class \a clazz. The method is specified
+ by its \a methodName and \a signature.
+
+ Returns the method ID or \c nullptr if the method is not found.
+
+ A usecase for this method is searching for class methods and caching their
+ IDs, so that they could later be used for calling the methods.
+
+ \code
+ QJniEnvironment env;
+ jclass javaClass = env.findClass("org/qtproject/example/android/CustomClass");
+ jmethodID methodId = env.findStaticMethod(javaClass,
+ "staticJavaMethod",
+ "(Ljava/lang/String;)V");
+ QJniObject javaMessage = QJniObject::fromString("findStaticMethod example");
+ QJniObject::callStaticMethod<void>(javaClass,
+ methodId,
+ javaMessage.object<jstring>());
+ \endcode
+*/
+jmethodID QJniEnvironment::findStaticMethod(jclass clazz, const char *methodName, const char *signature)
+{
+ jmethodID id = d->jniEnv->GetStaticMethodID(clazz, methodName, signature);
+ if (checkAndClearExceptions(d->jniEnv))
+ return nullptr;
+
+ return id;
+}
+
+/*!
\fn JavaVM *QJniEnvironment::javaVM()
Returns the Java VM interface for the current process. Although it might
@@ -216,7 +264,7 @@ JavaVM *QJniEnvironment::javaVM()
which can call native C++ functions from class \a className. These methods
must be registered before any attempt to call them.
- Returns True if the registration is successful, otherwise False.
+ Returns \c true if the registration is successful, otherwise \c false.
Each element in the methods array consists of:
\list
@@ -240,14 +288,31 @@ bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMeth
return false;
jclass clazz = d->jniEnv->GetObjectClass(classObject.object());
+ const bool result = registerNativeMethods(clazz, methods, size);
+ d->jniEnv->DeleteLocalRef(clazz);
+
+ return result;
+}
+
+/*!
+ \overload
+
+ This overload uses a previously cached jclass instance \a clazz.
+
+ \code
+ JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)},
+ {"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}};
+ QJniEnvironment env;
+ jclass clazz = env.findClass("org/qtproject/android/TestJavaClass");
+ env.registerNativeMethods(clazz, methods, 2);
+ \endcode
+*/
+bool QJniEnvironment::registerNativeMethods(jclass clazz, JNINativeMethod methods[], int size)
+{
if (d->jniEnv->RegisterNatives(clazz, methods, size) < 0) {
checkAndClearExceptions();
- d->jniEnv->DeleteLocalRef(clazz);
return false;
}
-
- d->jniEnv->DeleteLocalRef(clazz);
-
return true;
}
diff --git a/src/corelib/kernel/qjnienvironment.h b/src/corelib/kernel/qjnienvironment.h
index 69a24cbe18..2053e0a50f 100644
--- a/src/corelib/kernel/qjnienvironment.h
+++ b/src/corelib/kernel/qjnienvironment.h
@@ -58,8 +58,11 @@ public:
JNIEnv &operator*() const;
JNIEnv *jniEnv() const;
jclass findClass(const char *className);
+ jmethodID findMethod(jclass clazz, const char *methodName, const char *signature);
+ jmethodID findStaticMethod(jclass clazz, const char *methodName, const char *signature);
static JavaVM *javaVM();
bool registerNativeMethods(const char *className, JNINativeMethod methods[], int size);
+ bool registerNativeMethods(jclass clazz, JNINativeMethod methods[], int size);
enum class OutputMode {
Silent,
diff --git a/tests/auto/corelib/kernel/qjnienvironment/testdata/src/org/qtproject/qt/android/testdata/QtJniEnvironmentTestClass.java b/tests/auto/corelib/kernel/qjnienvironment/testdata/src/org/qtproject/qt/android/testdata/QtJniEnvironmentTestClass.java
index d6c5be45cb..8f36dcc5fd 100644
--- a/tests/auto/corelib/kernel/qjnienvironment/testdata/src/org/qtproject/qt/android/testdata/QtJniEnvironmentTestClass.java
+++ b/tests/auto/corelib/kernel/qjnienvironment/testdata/src/org/qtproject/qt/android/testdata/QtJniEnvironmentTestClass.java
@@ -31,11 +31,16 @@ package org.qtproject.qt.android.testdatapackage;
public class QtJniEnvironmentTestClass
{
private static native void callbackFromJava(String message);
+ private static native void intCallbackFromJava(int value);
public static void appendJavaToString(String message)
{
callbackFromJava("From Java: " + message);
}
+ public static void convertToInt(String message)
+ {
+ intCallbackFromJava(Integer.parseInt(message));
+ }
}
diff --git a/tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp b/tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp
index 278554e496..41192e1f4b 100644
--- a/tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp
+++ b/tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp
@@ -36,6 +36,7 @@ static const char javaTestClass[] =
"org/qtproject/qt/android/testdatapackage/QtJniEnvironmentTestClass";
static QString registerNativesString = QStringLiteral("Qt");
+static int registerNativeInteger = 0;
class tst_QJniEnvironment : public QObject
{
@@ -45,6 +46,9 @@ private slots:
void jniEnv();
void javaVM();
void registerNativeMethods();
+ void registerNativeMethodsByJclass();
+ void findMethod();
+ void findStaticMethod();
};
void tst_QJniEnvironment::jniEnv()
@@ -134,6 +138,71 @@ void tst_QJniEnvironment::registerNativeMethods()
QVERIFY(registerNativesString == QStringLiteral("From Java: Qt"));
}
+static void intCallbackFromJava(JNIEnv *env, jobject /*thiz*/, jint value)
+{
+ Q_UNUSED(env)
+ registerNativeInteger = static_cast<int>(value);
+}
+
+void tst_QJniEnvironment::registerNativeMethodsByJclass()
+{
+ JNINativeMethod methods[] {
+ { "intCallbackFromJava", "(I)V", reinterpret_cast<void *>(intCallbackFromJava) }
+ };
+
+ QJniEnvironment env;
+ jclass clazz = env.findClass(javaTestClass);
+ QVERIFY(clazz != 0);
+ QVERIFY(env.registerNativeMethods(clazz, methods, 1));
+
+ QCOMPARE(registerNativeInteger, 0);
+
+ QJniObject parameter = QJniObject::fromString(QString("123"));
+ QJniObject::callStaticMethod<void>(clazz, "convertToInt", "(Ljava/lang/String;)V",
+ parameter.object<jstring>());
+ QTest::qWait(200);
+ QCOMPARE(registerNativeInteger, 123);
+}
+
+void tst_QJniEnvironment::findMethod()
+{
+ QJniEnvironment env;
+ jclass clazz = env.findClass("java/lang/Integer");
+ QVERIFY(clazz != nullptr);
+
+ // existing method
+ jmethodID methodId = env.findMethod(clazz, "toString", "()Ljava/lang/String;");
+ QVERIFY(methodId != nullptr);
+
+ // invalid signature
+ jmethodID invalid = env.findMethod(clazz, "unknown", "()I");
+ QVERIFY(invalid == nullptr);
+ // check that all exceptions are already cleared
+ QVERIFY(!env.checkAndClearExceptions());
+}
+
+void tst_QJniEnvironment::findStaticMethod()
+{
+ QJniEnvironment env;
+ jclass clazz = env.findClass("java/lang/Integer");
+ QVERIFY(clazz != nullptr);
+
+ // existing method
+ jmethodID staticMethodId = env.findStaticMethod(clazz, "parseInt", "(Ljava/lang/String;)I");
+ QVERIFY(staticMethodId != nullptr);
+
+ QJniObject parameter = QJniObject::fromString("123");
+ jint result = QJniObject::callStaticMethod<jint>(clazz, staticMethodId,
+ parameter.object<jstring>());
+ QCOMPARE(result, 123);
+
+ // invalid method
+ jmethodID invalid = env.findStaticMethod(clazz, "unknown", "()I");
+ QVERIFY(invalid == nullptr);
+ // check that all exceptions are already cleared
+ QVERIFY(!env.checkAndClearExceptions());
+}
+
QTEST_MAIN(tst_QJniEnvironment)
#include "tst_qjnienvironment.moc"