QJniArray: don't subclass QJniObject

QJniObject is not prepared for being subclassed (no virtual destructor),
and doing so is formally UB.

Instead of making QJniArray(Base) a QJniObject subclass, give it a
QJniObject member and make it convertible to/from QJniObject. Existing
code still works with this change, even though it removes all the
inherited QJniObject APIs for accessing fields and methods. However, as
the Java array classes have a very narrow and well-defined API anyway we
could, if needed, add those as C++ member functions instead of going
through calling-by-string.

Found during API review.

Task-number: QTBUG-119952
Change-Id: Ic4437116eed5e15226449bdabe48ab657cb14dc3
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit 101ab278913e3bacc7c0596ae0a5bf3c0fa2f922)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Volker Hilsheimer 2024-01-22 16:09:04 +01:00 committed by Qt Cherry-pick Bot
parent 0604ce57ea
commit 7f9e5ccd55
2 changed files with 17 additions and 8 deletions

View File

@ -69,7 +69,7 @@ private:
{}
};
class QJniArrayBase : public QJniObject
class QJniArrayBase
{
// for SFINAE'ing out the fromContainer named constructor
template <typename Container, typename = void> struct CanConvertHelper : std::false_type {};
@ -83,9 +83,15 @@ public:
using size_type = jsize;
using difference_type = size_type;
operator QJniObject() const { return m_object; }
template <typename T = jobject>
T object() const { return m_object.object<T>(); }
bool isValid() const { return m_object.isValid(); }
size_type size() const
{
if (jarray array = object<jarray>())
if (jarray array = m_object.object<jarray>())
return jniEnv()->GetArrayLength(array);
return 0;
}
@ -141,22 +147,25 @@ protected:
~QJniArrayBase() = default;
explicit QJniArrayBase(jarray array)
: QJniObject(static_cast<jobject>(array))
: m_object(static_cast<jobject>(array))
{
static_assert(sizeof(QJniArrayBase) == sizeof(QJniObject),
"QJniArrayBase must have the same size as QJniObject!");
}
explicit QJniArrayBase(const QJniObject &object)
: QJniObject(object)
: m_object(object)
{}
explicit QJniArrayBase(QJniObject &&object) noexcept
: QJniObject(std::move(object))
: m_object(std::move(object))
{}
JNIEnv *jniEnv() const noexcept { return QJniEnvironment::getJniEnv(); }
template <typename ElementType, typename List, typename NewFn, typename SetFn>
static auto makeArray(List &&list, NewFn &&newArray, SetFn &&setRegion);
template <typename List>
static auto makeObjectArray(List &&list);
private:
QJniObject m_object;
};
template <typename T>

View File

@ -102,7 +102,7 @@ static QString fetchFont(const QString &query)
HashSet innerSet;
Q_ASSERT(outerList.isValid() && innerSet.isValid());
for (QJniObject signature : signatures) {
for (const auto &signature : signatures) {
const QJniArray<jbyte> byteArray = signature.callMethod<jbyte[]>("toByteArray");
// add takes an Object, not an Array