summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2023-09-13 12:03:16 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2023-09-27 19:44:58 +0200
commit62cb5589b3723fe8162e190cd54d9c78929b98d2 (patch)
treeba2bd194e3e82cc830a7f5a7be6e1d9ef26a9da9 /tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
parent0bd3882acd15b33330210f05fd6bb528fde87197 (diff)
JNI: Make declared QtJniTypes classes proper QJniObjects
Instead of having a type that doesn't behave like a QJniObject, which includes not holding a proper reference on the Java object, make the QtJniTypes::Object type a QJniObject subclass that can be specialized via CRTP to provide type-specific constructor and static functions. QJniObject doesn't have a virtual destructor, but we subclass it only to add a typed interface, without adding any additional data members. Add versions of the static functions from QJniObjects to the QtJniTypes::Object so that they can be called without explicitly specifying the type or class name. This includes a constructor and named constructors. Constructing such objects means constructing a Java object of the class the object type represents, as per the Q_DECLARE_JNI_CLASS declaration. This is not without ambiguity, as constructing a type with a jobject parameter can mean that a type wrapping an existing jobject should be created, or that a Java object should be created with the provided jobject as the parameter to the constructor (e.g. a copy constructor). This ambiguity is for now inevitable; we need to be able to implicitly convert jobject to such types. However, named constructors are provided so that client code can avoid the ambiguity. To prevent unnecessary default constructed QJniObjects that are then replaced immediately with a properly constructed object, add a protected QJniObject constructor that creates an uninitialized object (e.g. with the d-pointer being nullptr), which we can then assign the constructed jobject to using the available assignment operator. Add the special copy and move constructor and assignment operators as explicit members for clarity, even though the can all be defaulted. Such QJniObject subclasses can then be transparently passed as arguments into JNI call functions that expect a jobject representation, with the QtJniTypes::Traits specialization from the type declaration providing the correct signature. QJniObject's API includes a lot of legacy overloads: with variadic arguments, a explicit signature string, and jclass/jmethodID parameters that are completely unused within Qt itself. In addition the explicit "Object" member functions to explicitly call the version that returns a jobject (and then a QJniObject). All this call-side complexity is taken care of by the compile-time signature generation, implicit class type, and template argument deduction. Overloads taking a jclass or jmethod are not used anywhere in Qt, which is perhaps an indicator that they, while nice to have, are too hard to use even for ourselves. For the modern QtJniTypes class instantiations, remove all the overhead and reduce the API to the small set of functions that are used all over the place, and that don't require an explicit signature, or class/method lookup. This is a source incompatible change, as now QJniTypes::Object is no longer a primitive type, and no longer binary equivalent to jobject. However, this is acceptable as the API has so far been undocumented, and is only used internally in Qt (and changes to adapt are largely already merged). Change-Id: I6d14c09c8165652095f30511f04dc17217245bf5 Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
Diffstat (limited to 'tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp')
-rw-r--r--tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp32
1 files changed, 32 insertions, 0 deletions
diff --git a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
index 856368355c..0ce2295092 100644
--- a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
+++ b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
@@ -5,6 +5,8 @@
#include <QtCore/qjnitypes.h>
+using namespace Qt::StringLiterals;
+
class tst_QJniTypes : public QObject
{
Q_OBJECT
@@ -15,6 +17,7 @@ public:
private slots:
void initTestCase();
void nativeMethod();
+ void construct();
};
struct QtJavaWrapper {};
@@ -159,6 +162,35 @@ void tst_QJniTypes::nativeMethod()
QCOMPARE(method.signature, "(ILjava/lang/String;J)Z");
}
+void tst_QJniTypes::construct()
+{
+ using namespace QtJniTypes;
+
+ const QString text = u"Java String"_s;
+ String str(text);
+ QVERIFY(str.isValid());
+ QCOMPARE(str.toString(), text);
+
+ jobject jref = nullptr; // must be jobject, not jstring
+ {
+ // if jref would be a jstring, then this would call the
+ // Java String copy constructor!
+ String jstr(jref);
+ QVERIFY(!jstr.isValid());
+ }
+ jref = str.object<jstring>();
+ {
+ String jstr(jref);
+ QVERIFY(jstr.isValid());
+ QCOMPARE(jstr.toString(), text);
+ }
+
+ String str2 = str;
+ QCOMPARE(str.toString(), text);
+ String str3 = std::move(str2);
+ QCOMPARE(str3.toString(), text);
+}
+
QTEST_MAIN(tst_QJniTypes)
#include "tst_qjnitypes.moc"