JNI: use conversion function from Traits in QJniArray

Remove the special handling for various object-types, use the Traits
specialization instead when the type we want is an object type.

Change-Id: Ia7f3c3a11b5687d2fb8a6c3ab0cea15963dacea5
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
Volker Hilsheimer 2025-01-03 17:44:40 +01:00
parent 5342046ff8
commit 129b914051
2 changed files with 20 additions and 38 deletions

View File

@ -573,8 +573,7 @@ protected:
std::is_same<ElementType, QString>, std::is_same<ElementType, QString>,
std::is_base_of<QtJniTypes::JObjectBase, ElementType> std::is_base_of<QtJniTypes::JObjectBase, ElementType>
>) { >) {
using ResultType = decltype(std::declval<QtJniTypes::Detail::LocalFrame<void>>() using ResultType = decltype(QtJniTypes::Traits<ElementType>::convertToJni(nullptr, {}));
.convertToJni(std::declval<ElementType>()));
const auto className = QtJniTypes::Traits<ResultType>::className(); const auto className = QtJniTypes::Traits<ResultType>::className();
jclass elementClass = env.findClass(className); jclass elementClass = env.findClass(className);
if (!elementClass) { if (!elementClass) {
@ -694,9 +693,7 @@ public:
auto arrayObject() const auto arrayObject() const
{ {
if constexpr (std::is_convertible_v<jobject, T>) if constexpr (QtJniTypes::isObjectType<T>())
return object<jobjectArray>();
else if constexpr (std::is_same_v<T, QString>)
return object<jobjectArray>(); return object<jobjectArray>();
else if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>) else if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>)
return object<jbyteArray>(); return object<jbyteArray>();
@ -741,26 +738,12 @@ public:
const_reference at(size_type i) const const_reference at(size_type i) const
{ {
JNIEnv *env = jniEnv(); JNIEnv *env = jniEnv();
if constexpr (std::is_convertible_v<jobject, T>) { if constexpr (QtJniTypes::isObjectType<T>()) {
jobject element = env->GetObjectArrayElement(object<jobjectArray>(), i); jobject element = env->GetObjectArrayElement(object<jobjectArray>(), i);
if constexpr (std::is_base_of_v<QJniObject, T>) if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>)
return QJniObject::fromLocalRef(element); return static_cast<T>(element);
else if constexpr (std::is_base_of_v<QtJniTypes::JObjectBase, T>)
return T::fromLocalRef(element);
else else
return T{element}; return QtJniTypes::Traits<T>::convertFromJni(QJniObject::fromLocalRef(element));
} else if constexpr (std::is_same_v<QString, T>) {
jstring string = static_cast<jstring>(env->GetObjectArrayElement(arrayObject(), i));
if (string) {
QString res = QtJniTypes::Detail::toQString(string, env);
env->DeleteLocalRef(string);
return res;
} else {
return QString();
}
} else if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>) {
// jstring, jclass etc
return static_cast<T>(env->GetObjectArrayElement(object<jobjectArray>(), i));
} else { } else {
T res = {}; T res = {};
if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>) if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>)
@ -787,15 +770,10 @@ public:
{ {
JNIEnv *env = jniEnv(); JNIEnv *env = jniEnv();
if constexpr (std::disjunction_v<std::is_base_of<QtJniTypes::JObjectBase, T>, if constexpr (QtJniTypes::isObjectType<T>()) {
std::is_same<QJniObject, T>>) { QtJniTypes::Detail::LocalFrame<T> frame(env);
env->SetObjectArrayElement(object<jobjectArray>(), i, val.object()); jobject element = frame.template convertToJni(val);
} else if constexpr (std::is_same_v<QString, T>) { env->SetObjectArrayElement(object<jobjectArray>(), i, element);
env->SetObjectArrayElement(object<jobjectArray>(), i,
QJniObject::fromString(val).template object<jstring>());
} else if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>) {
// jstring, jclass etc
env->SetObjectArrayElement(object<jobjectArray>(), i, val);
} else { // primitive types } else { // primitive types
if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>) if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>)
env->SetByteArrayRegion(object<jbyteArray>(), i, 1, &val); env->SetByteArrayRegion(object<jbyteArray>(), i, 1, &val);
@ -918,8 +896,8 @@ template <typename List>
auto QJniArrayBase::makeObjectArray(List &&list) auto QJniArrayBase::makeObjectArray(List &&list)
{ {
using ElementType = typename q20::remove_cvref_t<List>::value_type; using ElementType = typename q20::remove_cvref_t<List>::value_type;
using ResultType = QJniArray<decltype(std::declval<QtJniTypes::Detail::LocalFrame<>>() using ResultType = QJniArray<decltype(QtJniTypes::Traits<ElementType>::convertToJni(nullptr,
.convertToJni(std::declval<ElementType>()))>; {}))>;
if (std::size(list) == 0) if (std::size(list) == 0)
return ResultType(); return ResultType();
@ -945,8 +923,6 @@ auto QJniArrayBase::makeObjectArray(List &&list)
} }
// explicitly manage the frame for local references in chunks of 100 // explicitly manage the frame for local references in chunks of 100
QtJniTypes::Detail::LocalFrame frame(env);
frame.hasFrame = true;
constexpr jint frameCapacity = 100; constexpr jint frameCapacity = 100;
qsizetype i = 0; qsizetype i = 0;
for (const auto &element : std::as_const(list)) { for (const auto &element : std::as_const(list)) {
@ -956,13 +932,12 @@ auto QJniArrayBase::makeObjectArray(List &&list)
if (env->PushLocalFrame(frameCapacity) != 0) if (env->PushLocalFrame(frameCapacity) != 0)
return ResultType{}; return ResultType{};
} }
jobject object = frame.convertToJni(element); jobject object = QtJniTypes::Traits<ElementType>::convertToJni(env, element);
env->SetObjectArrayElement(localArray, i, object); env->SetObjectArrayElement(localArray, i, object);
++i; ++i;
} }
if (i) if (i)
env->PopLocalFrame(nullptr); env->PopLocalFrame(nullptr);
frame.hasFrame = false;
return ResultType(QJniObject::fromLocalRef(localArray)); return ResultType(QJniObject::fromLocalRef(localArray));
} }

View File

@ -148,6 +148,13 @@ void tst_QJniArray::construct()
QCOMPARE(list.at(500), QString::number(500)); QCOMPARE(list.at(500), QString::number(500));
QCOMPARE(list.toContainer(), strings); QCOMPARE(list.toContainer(), strings);
} }
{
constexpr qsizetype size = 5;
const QJniArray<jstring> list(size);
const QStringList strings = list.toContainer();
QCOMPARE(strings.at(0), QString());
QCOMPARE(strings.size(), size);
}
{ {
QJniArray bytes = QJniArrayBase::fromContainer(QByteArray("abc")); QJniArray bytes = QJniArrayBase::fromContainer(QByteArray("abc"));
static_assert(std::is_same_v<decltype(bytes)::value_type, jbyte>); static_assert(std::is_same_v<decltype(bytes)::value_type, jbyte>);