Add support for scoped JNI callbacks

This commit adds macros for declaring scoped native callbacks which are
in namespace or for example defined as static class member variables.

The existing macros don't allow this as they use QtJniMethods namespace
and the introduced callbacks' namespaces are not enclosed in that
namespace, yielding a compilation error.

Change-Id: I754560bea7e9a1b57c2661d1ee7236e78db39ba1
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit c5caab1f150dadc51219f3bbfb8d4fee7f23703f)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Juha Vuolle 2022-07-05 15:11:12 +03:00 committed by Qt Cherry-pick Bot
parent 49dd11fe34
commit d940c69884
3 changed files with 103 additions and 0 deletions

View File

@ -367,6 +367,20 @@ static const JNINativeMethod Method##_method = { \
#define Q_JNI_NATIVE_METHOD(Method) QtJniMethods::Method##_method
#define Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(...) \
QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE, __VA_ARGS__) \
#define QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(Method, Name) \
static inline constexpr auto Method##_signature = QtJniTypes::nativeMethodSignature(Method); \
static inline const JNINativeMethod Method##_method = { \
#Name, Method##_signature.data(), reinterpret_cast<void *>(Method) \
};
#define QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_1(Method) \
QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(Method, Method) \
#define Q_JNI_NATIVE_SCOPED_METHOD(Method, Scope) Scope::Method##_method
QT_END_NAMESPACE
#endif

View File

@ -7,6 +7,9 @@ public class QtJniEnvironmentTestClass
{
private static native void callbackFromJava(String message);
private static native void namedCallbackFromJava(String message);
private static native void memberCallbackFromJava(String message);
private static native void namedMemberCallbackFromJava(String message);
private static native void namespaceCallbackFromJava(String message);
private static native void intCallbackFromJava(int value);
public final int INT_FIELD = 123;
@ -24,6 +27,21 @@ public class QtJniEnvironmentTestClass
namedCallbackFromJava("From Java (named): " + message);
}
public static void memberAppendJavaToString(String message)
{
memberCallbackFromJava("From Java (member): " + message);
}
public static void namedMemberAppendJavaToString(String message)
{
namedMemberCallbackFromJava("From Java (named member): " + message);
}
public static void namespaceAppendJavaToString(String message)
{
namespaceCallbackFromJava("From Java (namespace): " + message);
}
public static void convertToInt(String message)
{
intCallbackFromJava(Integer.parseInt(message));

View File

@ -115,6 +115,34 @@ static void callbackFromJavaNoCtor(JNIEnv *env, jobject /*thiz*/, jstring value)
}
Q_DECLARE_JNI_NATIVE_METHOD(callbackFromJavaNoCtor);
class CallbackClass {
public:
static void memberCallbackFromJava(JNIEnv *env, jobject /*thiz*/, jstring value)
{
Q_UNUSED(env)
registerNativesString = QJniObject(value).toString();
}
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(memberCallbackFromJava)
static void tediouslyLongNamed_memberCallbackFromJava(JNIEnv *env, jobject /*thiz*/,
jstring value)
{
Q_UNUSED(env)
registerNativesString = QJniObject(value).toString();
}
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(tediouslyLongNamed_memberCallbackFromJava,
namedMemberCallbackFromJava)
};
namespace CallbackNamespace {
static void namespaceCallbackFromJava(JNIEnv *env, jobject /*thiz*/, jstring value)
{
Q_UNUSED(env)
registerNativesString = QJniObject(value).toString();
}
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(namespaceCallbackFromJava)
}
void tst_QJniEnvironment::registerNativeMethods()
{
QJniObject QtString = QJniObject::fromString(registerNativesString);
@ -147,6 +175,49 @@ void tst_QJniEnvironment::registerNativeMethods()
QVERIFY(registerNativesString == QStringLiteral("From Java (named): Qt"));
}
// Static class member as callback
{
QVERIFY(env.registerNativeMethods(javaTestClass, {
Q_JNI_NATIVE_SCOPED_METHOD(memberCallbackFromJava, CallbackClass)
}));
QJniObject::callStaticMethod<void>(javaTestClass,
"memberAppendJavaToString",
"(Ljava/lang/String;)V",
QtString.object<jstring>());
QTest::qWait(200);
QVERIFY(registerNativesString == QStringLiteral("From Java (member): Qt"));
}
// Static named class member as callback
{
QVERIFY(env.registerNativeMethods(javaTestClass, {
Q_JNI_NATIVE_SCOPED_METHOD(tediouslyLongNamed_memberCallbackFromJava,
CallbackClass)
}));
QJniObject::callStaticMethod<void>(javaTestClass,
"namedMemberAppendJavaToString",
"(Ljava/lang/String;)V",
QtString.object<jstring>());
QTest::qWait(200);
QVERIFY(registerNativesString == QStringLiteral("From Java (named member): Qt"));
}
// Function generally just in namespace as callback
{
QVERIFY(env.registerNativeMethods(javaTestClass, {
Q_JNI_NATIVE_SCOPED_METHOD(namespaceCallbackFromJava, CallbackNamespace)
}));
QJniObject::callStaticMethod<void>(javaTestClass,
"namespaceAppendJavaToString",
"(Ljava/lang/String;)V",
QtString.object<jstring>());
QTest::qWait(200);
QVERIFY(registerNativesString == QStringLiteral("From Java (namespace): Qt"));
}
// No default constructor in class
{
QVERIFY(env.registerNativeMethods(javaTestClassNoCtor, {