diff --git a/src/corelib/kernel/qjniarray.h b/src/corelib/kernel/qjniarray.h index b1ebf3481ba..40b4f642878 100644 --- a/src/corelib/kernel/qjniarray.h +++ b/src/corelib/kernel/qjniarray.h @@ -132,42 +132,43 @@ public: "QJniArray::fromContainer", "Container is too large for a Java array"); using ElementType = typename std::remove_reference_t::value_type; - if constexpr (std::disjunction_v, - std::is_same, - std::is_same, - std::is_base_of - >) { + if constexpr (std::is_base_of_v, + std::remove_pointer_t>) { return makeObjectArray(std::forward(container)); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::disjunction_v, + std::is_same, + std::is_base_of + >) { + return QJniArray(makeObjectArray(std::forward(container))); + } else if constexpr (QtJniTypes::sameTypeForJni) { return makeArray(std::forward(container), &JNIEnv::NewFloatArray, &JNIEnv::SetFloatArrayRegion); - } else if constexpr (std::is_same_v) { + } else if constexpr (QtJniTypes::sameTypeForJni) { return makeArray(std::forward(container), &JNIEnv::NewDoubleArray, &JNIEnv::SetDoubleArrayRegion); - } else if constexpr (std::disjunction_v, - std::is_same>) { + } else if constexpr (QtJniTypes::sameTypeForJni) { return makeArray(std::forward(container), &JNIEnv::NewBooleanArray, &JNIEnv::SetBooleanArrayRegion); - } else if constexpr (std::disjunction_v, - std::is_same>) { + } else if constexpr (QtJniTypes::sameTypeForJni + || std::is_same_v) { return makeArray(std::forward(container), &JNIEnv::NewByteArray, &JNIEnv::SetByteArrayRegion); } else if constexpr (std::disjunction_v, std::is_same>) { return makeArray(std::forward(container), &JNIEnv::NewCharArray, &JNIEnv::SetCharArrayRegion); - } else if constexpr (std::is_same_v - || sizeof(ElementType) == sizeof(jshort)) { + } else if constexpr (QtJniTypes::sameTypeForJni) { return makeArray(std::forward(container), &JNIEnv::NewShortArray, &JNIEnv::SetShortArrayRegion); - } else if constexpr (std::is_same_v - || sizeof(ElementType) == sizeof(jint)) { + } else if constexpr (QtJniTypes::sameTypeForJni) { return makeArray(std::forward(container), &JNIEnv::NewIntArray, &JNIEnv::SetIntArrayRegion); - } else if constexpr (std::is_same_v - || sizeof(ElementType) == sizeof(jlong)) { + } else if constexpr (QtJniTypes::sameTypeForJni) { return makeArray(std::forward(container), &JNIEnv::NewLongArray, &JNIEnv::SetLongArrayRegion); + } else { + static_assert(QtPrivate::type_dependent_false(), + "Don't know how to make QJniArray for this element type"); } } @@ -205,6 +206,8 @@ class QJniArray : public QJniArrayBase template struct ToContainerHelper { using type = QList; }; template <> struct ToContainerHelper { using type = QStringList; }; template <> struct ToContainerHelper { using type = QByteArray; }; + template <> struct ToContainerHelper { using type = QByteArray; }; + template using ToContainerType = typename ToContainerHelper::type; @@ -255,21 +258,23 @@ public: { if constexpr (std::is_convertible_v) return object(); - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) + return object(); + else if constexpr (QtJniTypes::sameTypeForJni) return object(); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) return object(); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) return object(); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) return object(); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) return object(); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) return object(); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) return object(); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) return object(); else return object(); @@ -299,26 +304,33 @@ public: return T::fromLocalRef(element); else return T{element}; + } else if constexpr (std::is_same_v) { + jstring string = static_cast(env->GetObjectArrayElement(arrayObject(), i)); + const auto length = env->GetStringLength(string); + QString res(length, Qt::Uninitialized); + env->GetStringRegion(string, 0, length, reinterpret_cast(res.data())); + env->DeleteLocalRef(string); + return res; } else if constexpr (std::is_base_of_v, std::remove_pointer_t>) { // jstring, jclass etc return static_cast(env->GetObjectArrayElement(object(), i)); } else { T res = {}; - if constexpr (std::is_same_v) + if constexpr (QtJniTypes::sameTypeForJni) env->GetByteArrayRegion(object(), i, 1, &res); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) env->GetCharArrayRegion(object(), i, 1, &res); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) env->GetBooleanArrayRegion(object(), i, 1, &res); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) env->GetShortArrayRegion(object(), i, 1, &res); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) env->GetIntArrayRegion(object(), i, 1, &res); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) env->GetLongArrayRegion(object(), i, 1, &res); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) env->GetFloatArrayRegion(object(), i, 1, &res); - else if constexpr (std::is_same_v) + else if constexpr (QtJniTypes::sameTypeForJni) env->GetDoubleArrayRegion(object(), i, 1, &res); return res; } @@ -336,36 +348,40 @@ public: container.reserve(sz); if constexpr (std::is_same_v) { - for (auto element : *this) - container.emplace_back(QJniObject(element).toString()); + for (auto element : *this) { + if constexpr (std::is_same_v) + container.emplace_back(element); + else + container.emplace_back(QJniObject(element).toString()); + } } else if constexpr (std::is_base_of_v, std::remove_pointer_t>) { for (auto element : *this) container.emplace_back(element); } else if constexpr (QJniArrayBase::isContiguousContainer) { container.resize(sz); - if constexpr (std::is_same_v) { + if constexpr (QtJniTypes::sameTypeForJni) { env->GetByteArrayRegion(object(), 0, sz, reinterpret_cast(container.data())); - } else if constexpr (std::is_same_v) { + } else if constexpr (QtJniTypes::sameTypeForJni) { env->GetCharArrayRegion(object(), 0, sz, container.data()); - } else if constexpr (std::is_same_v) { + } else if constexpr (QtJniTypes::sameTypeForJni) { env->GetBooleanArrayRegion(object(), 0, sz, container.data()); - } else if constexpr (std::is_same_v) { + } else if constexpr (QtJniTypes::sameTypeForJni) { env->GetShortArrayRegion(object(), 0, sz, container.data()); - } else if constexpr (std::is_same_v) { + } else if constexpr (QtJniTypes::sameTypeForJni) { env->GetIntArrayRegion(object(), 0, sz, container.data()); - } else if constexpr (std::is_same_v) { + } else if constexpr (QtJniTypes::sameTypeForJni) { env->GetLongArrayRegion(object(), 0, sz, container.data()); - } else if constexpr (std::is_same_v) { + } else if constexpr (QtJniTypes::sameTypeForJni) { env->GetFloatArrayRegion(object(), 0, sz, container.data()); - } else if constexpr (std::is_same_v) { + } else if constexpr (QtJniTypes::sameTypeForJni) { env->GetDoubleArrayRegion(object(), 0, sz, container.data()); } else { diff --git a/src/corelib/kernel/qjniarray.qdoc b/src/corelib/kernel/qjniarray.qdoc index c909d4650af..a9ae15fa6ad 100644 --- a/src/corelib/kernel/qjniarray.qdoc +++ b/src/corelib/kernel/qjniarray.qdoc @@ -165,8 +165,14 @@ \li QJniArray \li QByteArray \row + \li QJniArray + \li QByteArray + \row \li QJniArray \li QStringList + \row + \li QJniArray + \li QStringList \endtable //! [type-mapping] diff --git a/tests/auto/corelib/kernel/qjniarray/tst_qjniarray.cpp b/tests/auto/corelib/kernel/qjniarray/tst_qjniarray.cpp index f56b2fe2b16..e1124bd0a51 100644 --- a/tests/auto/corelib/kernel/qjniarray/tst_qjniarray.cpp +++ b/tests/auto/corelib/kernel/qjniarray/tst_qjniarray.cpp @@ -76,21 +76,61 @@ VERIFY_RETURN_FOR_TYPE(QList, QList); VERIFY_RETURN_FOR_TYPE(QList, QList); VERIFY_RETURN_FOR_TYPE(QString, QString); +VERIFY_RETURN_FOR_TYPE(QJniArray, QJniArray); VERIFY_RETURN_FOR_TYPE(List, List); VERIFY_RETURN_FOR_TYPE(List[], QJniArray); VERIFY_RETURN_FOR_TYPE(QJniArray, QJniArray); #define VERIFY_CONTAINER_FOR_TYPE(In, Out) \ - static_assert(std::is_same_v().toContainer()), Out>) + static_assert(std::is_same_v().toContainer()), Out>); +#define VERIFY_ARRAY_FOR_CONTAINER(In, Out) \ + static_assert(std::is_same_v())), Out>); + +// primitive types, both JNI and C++ equivalent types VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); -VERIFY_CONTAINER_FOR_TYPE(QJniArray, QByteArray); -VERIFY_CONTAINER_FOR_TYPE(QJniArray, QStringList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); + +// jobject and derivatives +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); + +// QJniObject-ish classes VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); + +// Special case: jbyte, (u)char, and QByteArray +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QByteArray); +VERIFY_ARRAY_FOR_CONTAINER(QByteArray, QJniArray); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QByteArray); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QList); + +// Special case: jstring, QString, and QStringList +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QStringList); +VERIFY_ARRAY_FOR_CONTAINER(QStringList, QJniArray); +VERIFY_CONTAINER_FOR_TYPE(QJniArray, QStringList); +VERIFY_ARRAY_FOR_CONTAINER(QList, QJniArray); void tst_QJniArray::construct() { @@ -101,6 +141,8 @@ void tst_QJniArray::construct() strings << QString::number(i); QJniArray list(strings); QCOMPARE(list.size(), 10000); + QCOMPARE(list.at(500), QString::number(500)); + QCOMPARE(list.toContainer(), strings); } { QJniArray bytes = QJniArrayBase::fromContainer(QByteArray("abc")); diff --git a/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java b/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java index eb86a18034b..21a8884198d 100644 --- a/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java +++ b/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java @@ -152,6 +152,11 @@ public class QtJniObjectTestClass public Object[] reverseObjectArray(Object[] array) { return staticReverseObjectArray(array); } + // -------------------------------------------------------------------------------------------- + public static String[] staticStringArrayMethod() + { String[] array = { "First", "Second", "Third" }; return array; } + public String[] stringArrayMethod() { return staticStringArrayMethod(); } + // -------------------------------------------------------------------------------------------- public static boolean[] staticBooleanArrayMethod() { boolean[] array = { true, true, true }; return array; } diff --git a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp index 1da70b71276..dcc68e0283c 100644 --- a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp +++ b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp @@ -1563,6 +1563,26 @@ void tst_QJniObject::templateApiCheck() QCOMPARE(QJniObject::fromLocalRef(reverse.at(2)).toString(), u"one"_s); } + // jstringArray ------------------------------------------------------------------------------ + { + const QStringList strings{"First", "Second", "Third"}; + const auto array = TestClass::callStaticMethod>("staticStringArrayMethod"); + QVERIFY(array.isValid()); + QCOMPARE(array.size(), 3); + QCOMPARE(array.at(0).toString(), strings.first()); + QCOMPARE(array.toContainer(), strings); + } + + // jstringArray via implicit QString support ------------------------------------------------- + { + const QStringList strings{"First", "Second", "Third"}; + const auto array = TestClass::callStaticMethod>("staticStringArrayMethod"); + QVERIFY(array.isValid()); + QCOMPARE(array.size(), 3); + QCOMPARE(array.at(0), strings.first()); + QCOMPARE(array.toContainer(), strings); + } + // jbooleanArray ------------------------------------------------------------------------------ { QJniObject res = QJniObject::callStaticObjectMethod(testClassName,