diff options
Diffstat (limited to 'src/corelib/kernel/qjniobject.h')
-rw-r--r-- | src/corelib/kernel/qjniobject.h | 1175 |
1 files changed, 629 insertions, 546 deletions
diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h index 80568b2970..707d1ae28a 100644 --- a/src/corelib/kernel/qjniobject.h +++ b/src/corelib/kernel/qjniobject.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QJNIOBJECT_H #define QJNIOBJECT_H @@ -52,313 +16,391 @@ class QJniObjectPrivate; class Q_CORE_EXPORT QJniObject { + friend class QJniArrayBase; + + template <typename ...Args> + struct LocalFrame { + mutable JNIEnv *env; + bool hasFrame = false; + explicit LocalFrame(JNIEnv *env = nullptr) noexcept + : env(env) + { + } + ~LocalFrame() + { + if (hasFrame) + env->PopLocalFrame(nullptr); + } + template <typename T> + auto newLocalRef(jobject object) + { + if (!hasFrame) { + if (jniEnv()->PushLocalFrame(sizeof...(Args)) < 0) + return T{}; // JVM is out of memory, avoid making matters worse + hasFrame = true; + } + return static_cast<T>(jniEnv()->NewLocalRef(object)); + } + template <typename T> + auto newLocalRef(const QJniObject &object) + { + return newLocalRef<T>(object.template object<T>()); + } + JNIEnv *jniEnv() const + { + if (!env) + env = QJniEnvironment::getJniEnv(); + return env; + } + bool checkAndClearExceptions() + { + return env ? QJniEnvironment::checkAndClearExceptions(env) : false; + } + template <typename T> + auto convertToJni(T &&value); + template <typename T> + auto convertFromJni(QJniObject &&object); + }; public: QJniObject(); explicit QJniObject(const char *className); explicit QJniObject(const char *className, const char *signature, ...); - explicit QJniObject(jclass clazz); - explicit QJniObject(jclass clazz, const char *signature, ...); - QJniObject(jobject globalRef); - ~QJniObject(); - - jobject object() const; - template <typename T> T object() const + template<typename ...Args +#ifndef Q_QDOC + , std::enable_if_t<!std::disjunction_v<QtJniTypes::IsStringType<std::decay_t<Args>>...>>* = nullptr +#endif + > + explicit QJniObject(const char *className, Args &&...args) + : QJniObject(LocalFrame<Args...>{}, className, std::forward<Args>(args)...) { - assertJniObjectType<T>(); - return static_cast<T>(javaObject()); } - - jclass objectClass() const; - QByteArray className() const; - - template <typename T> - T callMethod(const char *methodName, const char *signature, ...) const +private: + template<typename ...Args> + explicit QJniObject(LocalFrame<Args...> localFrame, const char *className, Args &&...args) + : QJniObject(className, QtJniTypes::constructorSignature<Args...>().data(), + localFrame.convertToJni(std::forward<Args>(args))...) { - assertJniPrimitiveType<T>(); - QJniEnvironment env; - T res{}; - jmethodID id = getCachedMethodID(env.jniEnv(), methodName, signature); - if (id) { - va_list args; - va_start(args, signature); - callMethodForType<T>(env.jniEnv(), res, object(), id, args); - va_end(args); - if (env.checkAndClearExceptions()) - res = {}; - } - return res; } +public: + explicit QJniObject(jclass clazz); + explicit QJniObject(jclass clazz, const char *signature, ...); + template<typename ...Args +#ifndef Q_QDOC + , std::enable_if_t<!std::disjunction_v<QtJniTypes::IsStringType<std::decay_t<Args>>...>>* = nullptr +#endif + > + explicit QJniObject(jclass clazz, Args &&...args) + : QJniObject(clazz, QtJniTypes::constructorSignature<Args...>().data(), + std::forward<Args>(args)...) + {} + QJniObject(jobject globalRef); - template <> - void callMethod<void>(const char *methodName, const char *signature, ...) const - { - QJniEnvironment env; - jmethodID id = getCachedMethodID(env.jniEnv(), methodName, signature); - if (id) { - va_list args; - va_start(args, signature); - callVoidMethodV(env.jniEnv(), id, args); - va_end(args); - env.checkAndClearExceptions(); - } - } + QJniObject(const QJniObject &other) noexcept = default; + QJniObject(QJniObject &&other) noexcept = default; + QJniObject &operator=(const QJniObject &other) noexcept = default; + QJniObject &operator=(QJniObject &&other) noexcept = default; - template <typename T> - T callMethod(const char *methodName) const - { - assertJniPrimitiveType<T>(); - constexpr const char *signature = getTypeSignature<T>(); - return callMethod<T>(methodName, QByteArray(signature).prepend("()").constData()); - } + ~QJniObject(); - template <> - void callMethod<void>(const char *methodName) const + template<typename Class, typename ...Args> + static inline QJniObject construct(Args &&...args) { - callMethod<void>(methodName, "()V"); + LocalFrame<Args...> frame; + return QJniObject(QtJniTypes::Traits<Class>::className().data(), + QtJniTypes::constructorSignature<Args...>().data(), + frame.convertToJni(std::forward<Args>(args))...); } - template <typename T> - QJniObject callObjectMethod(const char *methodName) const + jobject object() const; + template <typename T> T object() const { - assertJniObjectType<T>(); - constexpr const char *signature = getTypeSignature<T>(); - return callObjectMethod(methodName, QByteArray(signature).prepend("()").constData()); + QtJniTypes::assertObjectType<T>(); + return static_cast<T>(javaObject()); } - QJniObject callObjectMethod(const char *methodName, const char *signature, ...) const; - - template <typename T> - static T callStaticMethod(const char *className, const char *methodName, - const char *signature, ...) - { - assertJniPrimitiveType<T>(); - QJniEnvironment env; - T res{}; - jclass clazz = QJniObject::loadClass(className, env.jniEnv()); - if (clazz) { - jmethodID id = getCachedMethodID(env.jniEnv(), clazz, - QJniObject::toBinaryEncClassName(className), - methodName, signature, true); - if (id) { - va_list args; - va_start(args, signature); - callStaticMethodForType<T>(env.jniEnv(), res, clazz, id, args); - va_end(args); - if (env.checkAndClearExceptions()) - res = {}; - } - } - return res; - } + jclass objectClass() const; + QByteArray className() const; - template <> - void callStaticMethod<void>(const char *className, const char *methodName, - const char *signature, ...) - { - QJniEnvironment env; - jclass clazz = QJniObject::loadClass(className, env.jniEnv()); - if (clazz) { - jmethodID id = getCachedMethodID(env.jniEnv(), clazz, - QJniObject::toBinaryEncClassName(className), - methodName, signature, true); + template <typename Ret, typename ...Args +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<Ret> = true +#endif + > + auto callMethod(const char *methodName, const char *signature, Args &&...args) const + { + LocalFrame<Args...> frame(jniEnv()); + if constexpr (QtJniTypes::isObjectType<Ret>()) { + return frame.template convertFromJni<Ret>(callObjectMethod(methodName, signature, + frame.convertToJni(std::forward<Args>(args))...)); + } else { + jmethodID id = getCachedMethodID(frame.jniEnv(), methodName, signature); if (id) { - va_list args; - va_start(args, signature); - env->CallStaticVoidMethodV(clazz, id, args); - va_end(args); - env.checkAndClearExceptions(); + if constexpr (std::is_same_v<Ret, void>) { + callVoidMethodV(frame.jniEnv(), id, + frame.convertToJni(std::forward<Args>(args))...); + frame.checkAndClearExceptions(); + } else { + Ret res{}; + callMethodForType<Ret>(frame.jniEnv(), res, object(), id, + frame.convertToJni(std::forward<Args>(args))...); + if (frame.checkAndClearExceptions()) + res = {}; + return res; + } } + if constexpr (!std::is_same_v<Ret, void>) + return Ret{}; } } - template <typename T> - static T callStaticMethod(const char *className, const char *methodName) + template <typename Ret, typename ...Args +#ifndef Q_QDOC + , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true +#endif + > + auto callMethod(const char *methodName, Args &&...args) const { - assertJniPrimitiveType<T>(); - constexpr const char *signature = getTypeSignature<T>(); - return callStaticMethod<T>(className, methodName, QByteArray(signature).prepend("()").constData()); + constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>(); + return callMethod<Ret>(methodName, signature.data(), std::forward<Args>(args)...); } - template <> - void callStaticMethod<void>(const char *className, const char *methodName) + template <typename Ret, typename ...Args +#ifndef Q_QDOC + , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true +#endif + > + QJniObject callObjectMethod(const char *methodName, Args &&...args) const { - callStaticMethod<void>(className, methodName, "()V"); + QtJniTypes::assertObjectType<Ret>(); + constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>(); + LocalFrame<Args...> frame(jniEnv()); + return frame.template convertFromJni<Ret>(callObjectMethod(methodName, signature, + frame.convertToJni(std::forward<Args>(args))...)); } - template <typename T> - static T callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...) - { - assertJniPrimitiveType<T>(); - QJniEnvironment env; - T res{}; - if (clazz) { - jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true); - if (id) { - va_list args; - va_start(args, signature); - callStaticMethodForType<T>(env.jniEnv(), res, clazz, id, args); - va_end(args); - if (env.checkAndClearExceptions()) - res = {}; - } - } - return res; - } + QJniObject callObjectMethod(const char *methodName, const char *signature, ...) const; - template <> - void callStaticMethod<void>(jclass clazz, const char *methodName, - const char *signature, ...) + template <typename Ret, typename ...Args> + static auto callStaticMethod(const char *className, const char *methodName, const char *signature, Args &&...args) { - QJniEnvironment env; - if (clazz) { - jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true); - if (id) { - va_list args; - va_start(args, signature); - env->CallStaticVoidMethodV(clazz, id, args); - va_end(args); - env.checkAndClearExceptions(); - } - } + JNIEnv *env = QJniEnvironment::getJniEnv(); + jclass clazz = QJniObject::loadClass(className, env); + return callStaticMethod<Ret>(clazz, methodName, signature, std::forward<Args>(args)...); } - template <typename T> - static T callStaticMethod(jclass clazz, jmethodID methodId, ...) + template <typename Ret, typename ...Args> + static auto callStaticMethod(jclass clazz, const char *methodName, const char *signature, Args &&...args) { - assertJniPrimitiveType<T>(); - QJniEnvironment env; - T res{}; - if (clazz && methodId) { - va_list args; - va_start(args, methodId); - callStaticMethodForType<T>(env.jniEnv(), res, clazz, methodId, args); - va_end(args); - if (env.checkAndClearExceptions()) - res = {}; - } - return res; + JNIEnv *env = QJniEnvironment::getJniEnv(); + jmethodID id = clazz ? getMethodID(env, clazz, methodName, signature, true) + : 0; + return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...); } - template <> - void callStaticMethod<void>(jclass clazz, jmethodID methodId, ...) - { - QJniEnvironment env; - if (clazz && methodId) { - va_list args; - va_start(args, methodId); - env->CallStaticVoidMethodV(clazz, methodId, args); - va_end(args); - env.checkAndClearExceptions(); + template <typename Ret, typename ...Args +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<Ret> = true +#endif + > + static auto callStaticMethod(jclass clazz, jmethodID methodId, Args &&...args) + { + LocalFrame<Args...> frame; + if constexpr (QtJniTypes::isObjectType<Ret>()) { + return frame.template convertFromJni<Ret>(callStaticObjectMethod(clazz, methodId, + frame.convertToJni(std::forward<Args>(args))...)); + } else { + if (clazz && methodId) { + if constexpr (std::is_same_v<Ret, void>) { + callStaticMethodForVoid(frame.jniEnv(), clazz, methodId, + frame.convertToJni(std::forward<Args>(args))...); + frame.checkAndClearExceptions(); + } else { + Ret res{}; + callStaticMethodForType<Ret>(frame.jniEnv(), res, clazz, methodId, + frame.convertToJni(std::forward<Args>(args))...); + if (frame.checkAndClearExceptions()) + res = {}; + return res; + } + } + if constexpr (!std::is_same_v<Ret, void>) + return Ret{}; } } - template <typename T> static T callStaticMethod(jclass clazz, const char *methodName) + template <typename Ret, typename ...Args +#ifndef Q_QDOC + , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true +#endif + > + static auto callStaticMethod(const char *className, const char *methodName, Args &&...args) { - assertJniPrimitiveType<T>(); - constexpr const char *signature = getTypeSignature<T>(); - return callStaticMethod<T>(clazz, methodName, QByteArray(signature).prepend("()").constData()); + JNIEnv *env = QJniEnvironment::getJniEnv(); + jclass clazz = QJniObject::loadClass(className, env); + const jmethodID id = clazz ? getMethodID(env, clazz, methodName, + QtJniTypes::methodSignature<Ret, Args...>().data(), true) + : 0; + return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...); } - template <> - void callStaticMethod<void>(jclass clazz, const char *methodName) + template <typename Ret, typename ...Args +#ifndef Q_QDOC + , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true +#endif + > + static auto callStaticMethod(jclass clazz, const char *methodName, Args &&...args) { - callStaticMethod<void>(clazz, methodName, "()V"); + constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>(); + return callStaticMethod<Ret>(clazz, methodName, signature.data(), std::forward<Args>(args)...); } - - template <typename T> - static QJniObject callStaticObjectMethod(const char *className, const char *methodName) + template <typename Klass, typename Ret, typename ...Args +#ifndef Q_QDOC + , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true +#endif + > + static auto callStaticMethod(const char *methodName, Args &&...args) { - assertJniObjectType<T>(); - constexpr const char *signature = getTypeSignature<T>(); - return callStaticObjectMethod(className, methodName, QByteArray(signature).prepend("()").constData()); + JNIEnv *env = QJniEnvironment::getJniEnv(); + const jclass clazz = QJniObject::loadClass(QtJniTypes::Traits<Klass>::className().data(), + env); + const jmethodID id = clazz ? getMethodID(env, clazz, methodName, + QtJniTypes::methodSignature<Ret, Args...>().data(), true) + : 0; + return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...); } static QJniObject callStaticObjectMethod(const char *className, const char *methodName, const char *signature, ...); - template <typename T> - static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName) - { - assertJniObjectType<T>(); - constexpr const char *signature = getTypeSignature<T>(); - return callStaticObjectMethod(clazz, methodName, QByteArray(signature).prepend("()").constData()); - } - static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName, const char *signature, ...); static QJniObject callStaticObjectMethod(jclass clazz, jmethodID methodId, ...); - template <typename T> T getField(const char *fieldName) const + + template <typename Ret, typename ...Args +#ifndef Q_QDOC + , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true +#endif + > + static QJniObject callStaticObjectMethod(const char *className, const char *methodName, Args &&...args) { - assertJniPrimitiveType<T>(); - QJniEnvironment env; - T res{}; - constexpr const char *signature = getTypeSignature<T>(); - jfieldID id = getCachedFieldID(env.jniEnv(), fieldName, signature); - if (id) { - getFieldForType<T>(env.jniEnv(), res, object(), id); - if (env.checkAndClearExceptions()) - res = {}; - } - return res; + QtJniTypes::assertObjectType<Ret>(); + constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>(); + LocalFrame<Args...> frame; + return frame.template convertFromJni<Ret>(callStaticObjectMethod(className, methodName, signature.data(), + frame.convertToJni(std::forward<Args>(args))...)); } - template <typename T> - static T getStaticField(const char *className, const char *fieldName) + template <typename Ret, typename ...Args +#ifndef Q_QDOC + , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true +#endif + > + static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName, Args &&...args) { - assertJniPrimitiveType<T>(); - QJniEnvironment env; - jclass clazz = QJniObject::loadClass(className, env.jniEnv()); - if (!clazz) - return 0; + QtJniTypes::assertObjectType<Ret>(); + constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>(); + LocalFrame<Args...> frame; + return frame.template convertFromJni<Ret>(callStaticObjectMethod(clazz, methodName, signature.data(), + frame.convertToJni(std::forward<Args>(args))...)); + } - constexpr const char *signature = getTypeSignature<T>(); - jfieldID id = getCachedFieldID(env.jniEnv(), clazz, - QJniObject::toBinaryEncClassName(className), - fieldName, - signature, true); - if (!id) - return 0; + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > + auto getField(const char *fieldName) const + { + LocalFrame<T> frame(jniEnv()); + if constexpr (QtJniTypes::isObjectType<T>()) { + return frame.template convertFromJni<T>(getObjectField<T>(fieldName)); + } else { + T res{}; + constexpr auto signature = QtJniTypes::fieldSignature<T>(); + jfieldID id = getCachedFieldID(frame.jniEnv(), fieldName, signature); + if (id) { + getFieldForType<T>(frame.jniEnv(), res, object(), id); + if (frame.checkAndClearExceptions()) + res = {}; + } + return res; + } + } - T res{}; - getStaticFieldForType<T>(env.jniEnv(), res, clazz, id); - if (env.checkAndClearExceptions()) - res = {}; - return res; + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > + static auto getStaticField(const char *className, const char *fieldName) + { + LocalFrame<T> frame; + if constexpr (QtJniTypes::isObjectType<T>()) { + return frame.template convertFromJni<T>(getStaticObjectField<T>(className, fieldName)); + } else { + jclass clazz = QJniObject::loadClass(className, frame.jniEnv()); + if (!clazz) + return T{}; + return getStaticField<T>(clazz, fieldName); + } } - template <typename T> - static T getStaticField(jclass clazz, const char *fieldName) - { - assertJniPrimitiveType<T>(); - QJniEnvironment env; - T res{}; - constexpr const char *signature = getTypeSignature<T>(); - jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, signature, true); - if (id) { - getStaticFieldForType<T>(env.jniEnv(), res, clazz, id); - if (env.checkAndClearExceptions()) - res = {}; + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > + static auto getStaticField(jclass clazz, const char *fieldName) + { + LocalFrame<T> frame; + if constexpr (QtJniTypes::isObjectType<T>()) { + return frame.template convertFromJni<T>(getStaticObjectField<T>(clazz, fieldName)); + } else { + T res{}; + constexpr auto signature = QtJniTypes::fieldSignature<T>(); + jfieldID id = getFieldID(frame.jniEnv(), clazz, fieldName, signature, true); + if (id) { + getStaticFieldForType<T>(frame.jniEnv(), res, clazz, id); + if (frame.checkAndClearExceptions()) + res = {}; + } + return res; } - return res; } - template <typename T> + template <typename Klass, typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > + static auto getStaticField(const char *fieldName) + { + return getStaticField<T>(QtJniTypes::Traits<Klass>::className(), fieldName); + } + + template <typename T +#ifndef Q_QDOC + , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true +#endif + > QJniObject getObjectField(const char *fieldName) const { - assertJniObjectType<T>(); - constexpr const char *signature = getTypeSignature<T>(); + constexpr auto signature = QtJniTypes::fieldSignature<T>(); return getObjectField(fieldName, signature); } QJniObject getObjectField(const char *fieldName, const char *signature) const; - template <typename T> + template <typename T +#ifndef Q_QDOC + , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true +#endif + > static QJniObject getStaticObjectField(const char *className, const char *fieldName) { - assertJniObjectType<T>(); - constexpr const char *signature = getTypeSignature<T>(); + constexpr auto signature = QtJniTypes::fieldSignature<T>(); return getStaticObjectField(className, fieldName, signature); } @@ -366,104 +408,128 @@ public: const char *fieldName, const char *signature); - template <typename T> + template <typename T +#ifndef Q_QDOC + , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true +#endif + > static QJniObject getStaticObjectField(jclass clazz, const char *fieldName) { - assertJniObjectType<T>(); - constexpr const char *signature = getTypeSignature<T>(); + constexpr auto signature = QtJniTypes::fieldSignature<T>(); return getStaticObjectField(clazz, fieldName, signature); } static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, const char *signature); - template <typename T> void setField(const char *fieldName, T value) + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > + void setField(const char *fieldName, T value) { - assertJniType<T>(); - QJniEnvironment env; - constexpr const char *signature = getTypeSignature<T>(); - jfieldID id = getCachedFieldID(env.jniEnv(), fieldName, signature); + constexpr auto signature = QtJniTypes::fieldSignature<T>(); + jfieldID id = getCachedFieldID(jniEnv(), fieldName, signature); if (id) { - setFieldForType<T>(env.jniEnv(), object(), id, value); - env.checkAndClearExceptions(); + setFieldForType<T>(jniEnv(), object(), id, value); + QJniEnvironment::checkAndClearExceptions(jniEnv()); } } - template <typename T> + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > void setField(const char *fieldName, const char *signature, T value) { - assertJniType<T>(); - QJniEnvironment env; - jfieldID id = getCachedFieldID(env.jniEnv(), fieldName, signature); + jfieldID id = getCachedFieldID(jniEnv(), fieldName, signature); if (id) { - setFieldForType<T>(env.jniEnv(), object(), id, value); - env.checkAndClearExceptions(); + setFieldForType<T>(jniEnv(), object(), id, value); + QJniEnvironment::checkAndClearExceptions(jniEnv()); } } - template <typename T> + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > static void setStaticField(const char *className, const char *fieldName, T value) { - assertJniType<T>(); - QJniEnvironment env; - jclass clazz = QJniObject::loadClass(className, env.jniEnv()); + LocalFrame<T> frame; + jclass clazz = QJniObject::loadClass(className, frame.jniEnv()); if (!clazz) return; - constexpr const char *signature = getTypeSignature<T>(); - jfieldID id = getCachedFieldID(env.jniEnv(), clazz, className, fieldName, + constexpr auto signature = QtJniTypes::fieldSignature<T>(); + jfieldID id = getCachedFieldID(frame.jniEnv(), clazz, className, fieldName, signature, true); if (!id) return; - setStaticFieldForType<T>(env.jniEnv(), clazz, id, value); - env.checkAndClearExceptions(); + setStaticFieldForType<T>(frame.jniEnv(), clazz, id, value); + frame.checkAndClearExceptions(); } - template <typename T> + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > static void setStaticField(const char *className, const char *fieldName, const char *signature, T value) { - assertJniType<T>(); - QJniEnvironment env; - jclass clazz = QJniObject::loadClass(className, env.jniEnv()); + JNIEnv *env = QJniEnvironment::getJniEnv(); + jclass clazz = QJniObject::loadClass(className, env); if (!clazz) return; - jfieldID id = getCachedFieldID(env.jniEnv(), clazz, className, fieldName, + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, signature, true); if (id) { - setStaticFieldForType<T>(env.jniEnv(), clazz, id, value); - env.checkAndClearExceptions(); + setStaticFieldForType<T>(env, clazz, id, value); + QJniEnvironment::checkAndClearExceptions(env); } } - template <typename T> + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > static void setStaticField(jclass clazz, const char *fieldName, const char *signature, T value) { - assertJniType<T>(); - QJniEnvironment env; - jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, signature, true); + JNIEnv *env = QJniEnvironment::getJniEnv(); + jfieldID id = getFieldID(env, clazz, fieldName, signature, true); if (id) { - setStaticFieldForType<T>(env.jniEnv(), clazz, id, value); - env.checkAndClearExceptions(); + setStaticFieldForType<T>(env, clazz, id, value); + QJniEnvironment::checkAndClearExceptions(env); } } - template <typename T> + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > static void setStaticField(jclass clazz, const char *fieldName, T value) { - assertJniType<T>(); - QJniEnvironment env; - constexpr const char *signature = getTypeSignature<T>(); - jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, signature, true); - if (id) { - setStaticFieldForType<T>(env.jniEnv(), clazz, id, value); - env.checkAndClearExceptions(); - } + setStaticField(clazz, fieldName, QtJniTypes::fieldSignature<T>(), value); + } + + template <typename Klass, typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > + static void setStaticField(const char *fieldName, T value) + { + setStaticField(QtJniTypes::Traits<Klass>::className(), fieldName, value); } static QJniObject fromString(const QString &string); @@ -475,21 +541,27 @@ public: // This function takes ownership of the jobject and releases the local ref. before returning. static QJniObject fromLocalRef(jobject lref); - template <typename T> QJniObject &operator=(T obj) + template <typename T, + std::enable_if_t<std::is_convertible_v<T, jobject>, bool> = true> + QJniObject &operator=(T obj) { - assertJniType<T>(); assign(static_cast<T>(obj)); return *this; } +protected: + QJniObject(Qt::Initialization) {} + JNIEnv *jniEnv() const noexcept; + private: - struct QVaListPrivate { operator va_list &() const { return m_args; } va_list &m_args; }; - QJniObject(const char *className, const char *signature, const QVaListPrivate &args); - QJniObject(jclass clazz, const char *signature, const QVaListPrivate &args); + static jclass loadClass(const QByteArray &className, JNIEnv *env); - static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded = false); +#if QT_CORE_REMOVED_SINCE(6, 7) + // these need to stay in the ABI as they were used in inline methods before 6.7 + static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded); static QByteArray toBinaryEncClassName(const QByteArray &className); - static QJniObject getCleanJniObject(jobject obj); + void callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const; +#endif static jfieldID getCachedFieldID(JNIEnv *env, jclass clazz, const QByteArray &className, const char *name, const char *signature, @@ -507,15 +579,7 @@ private: static jmethodID getMethodID(JNIEnv *env, jclass clazz, const char *name, const char *signature, bool isStatic = false); - void callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const; - QJniObject callObjectMethodV(const char *methodName, const char *signature, - va_list args) const; - - static QJniObject callStaticObjectMethodV(const char *className, const char *methodName, - const char *signature, va_list args); - - static QJniObject callStaticObjectMethodV(jclass clazz, const char *methodName, - const char *signature, va_list args); + void callVoidMethodV(JNIEnv *env, jmethodID id, ...) const; bool isSameObject(jobject obj) const; bool isSameObject(const QJniObject &other) const; @@ -525,262 +589,281 @@ private: friend bool operator==(const QJniObject &, const QJniObject &); friend bool operator!=(const QJniObject&, const QJniObject&); - template<bool flag = false> - static void staticAssertTypeMismatch() + template<typename T> + static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, jmethodID id, ...) { - static_assert(flag, "The used type is not supported by this template call. " - "Use a JNI based type instead."); + va_list args = {}; + va_start(args, id); + QtJniTypes::Caller<T>::callMethodForType(env, res, obj, id, args); + va_end(args); } template<typename T> - static constexpr bool isJniPrimitiveType() - { - if constexpr(!std::is_same<T, jboolean>::value - && !std::is_same<T, jbyte>::value - && !std::is_same<T, jchar>::value - && !std::is_same<T, jshort>::value - && !std::is_same<T, jint>::value - && !std::is_same<T, jlong>::value - && !std::is_same<T, jfloat>::value - && !std::is_same<T, jdouble>::value) { - return false; - } + static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz, + jmethodID id, ...) + { + if (!clazz || !id) + return; + va_list args = {}; + va_start(args, id); + QtJniTypes::Caller<T>::callStaticMethodForType(env, res, clazz, id, args); + va_end(args); + } - return true; + static void callStaticMethodForVoid(JNIEnv *env, jclass clazz, jmethodID id, ...) + { + if (!clazz || !id) + return; + va_list args; + va_start(args, id); + env->CallStaticVoidMethodV(clazz, id, args); + va_end(args); } + template<typename T> - static constexpr void assertJniPrimitiveType() + static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id) { - if constexpr(!isJniPrimitiveType<T>()) - staticAssertTypeMismatch(); + QtJniTypes::Caller<T>::getFieldForType(env, res, obj, id); } template<typename T> - static constexpr void assertJniObjectType() + static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, jfieldID id) { - if constexpr(!std::is_convertible<T, jobject>::value) - staticAssertTypeMismatch(); + QtJniTypes::Caller<T>::getStaticFieldForType(env, res, clazz, id); } template<typename T> - static constexpr void assertJniType() + static constexpr void setFieldForType(JNIEnv *env, jobject obj, jfieldID id, T value) { - if constexpr(!isJniPrimitiveType<T>() && !std::is_convertible<T, jobject>::value) - staticAssertTypeMismatch(); + if constexpr (QtJniTypes::isObjectType<T>()) { + LocalFrame<T> frame(env); + env->SetObjectField(obj, id, static_cast<jobject>(frame.convertToJni(value))); + } else { + QtJniTypes::Caller<T>::setFieldForType(env, obj, id, value); + } } template<typename T> - static constexpr const char* getTypeSignature() - { - if constexpr(std::is_same<T, jobject>::value) - return "Ljava/lang/Object;"; - else if constexpr(std::is_same<T, jclass>::value) - return "Ljava/lang/Class;"; - else if constexpr(std::is_same<T, jstring>::value) - return "Ljava/lang/String;"; - else if constexpr(std::is_same<T, jobjectArray>::value) - return "[Ljava/lang/Object;"; - else if constexpr(std::is_same<T, jthrowable>::value) - return "Ljava/lang/Throwable;"; - else if constexpr(std::is_same<T, jbooleanArray>::value) - return "[Z"; - else if constexpr(std::is_same<T, jbyteArray>::value) - return "[B"; - else if constexpr(std::is_same<T, jshortArray>::value) - return "[S"; - else if constexpr(std::is_same<T, jintArray>::value) - return "[I"; - else if constexpr(std::is_same<T, jlongArray>::value) - return "[J"; - else if constexpr(std::is_same<T, jfloatArray>::value) - return "[F"; - else if constexpr(std::is_same<T, jdoubleArray>::value) - return "[D"; - else if constexpr(std::is_same<T, jcharArray>::value) - return "[C"; - else if constexpr(std::is_same<T, jboolean>::value) - return "Z"; - else if constexpr(std::is_same<T, jbyte>::value) - return "B"; - else if constexpr(std::is_same<T, jchar>::value) - return "C"; - else if constexpr(std::is_same<T, jshort>::value) - return "S"; - else if constexpr(std::is_same<T, jint>::value) - return "I"; - else if constexpr(std::is_same<T, jlong>::value) - return "J"; - else if constexpr(std::is_same<T, jfloat>::value) - return "F"; - else if constexpr(std::is_same<T, jdouble>::value) - return "D"; - else - staticAssertTypeMismatch(); + static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz, jfieldID id, T value) + { + if constexpr (QtJniTypes::isObjectType<T>()) { + LocalFrame<T> frame(env); + env->SetStaticObjectField(clazz, id, static_cast<jobject>(frame.convertToJni(value))); + } else { + QtJniTypes::Caller<T>::setStaticFieldForType(env, clazz, id, value); + } } - template<typename T> - static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, - jmethodID id, va_list args) - { - if constexpr(std::is_same<T, jboolean>::value) - res = env->CallBooleanMethodV(obj, id, args); - else if constexpr(std::is_same<T, jbyte>::value) - res = env->CallByteMethodV(obj, id, args); - else if constexpr(std::is_same<T, jchar>::value) - res = env->CallCharMethodV(obj, id, args); - else if constexpr(std::is_same<T, jshort>::value) - res = env->CallShortMethodV(obj, id, args); - else if constexpr(std::is_same<T, jint>::value) - res = env->CallIntMethodV(obj, id, args); - else if constexpr(std::is_same<T, jlong>::value) - res = env->CallLongMethodV(obj, id, args); - else if constexpr(std::is_same<T, jfloat>::value) - res = env->CallFloatMethodV(obj, id, args); - else if constexpr(std::is_same<T, jdouble>::value) - res = env->CallDoubleMethodV(obj, id, args); - else - staticAssertTypeMismatch(); + friend QJniObjectPrivate; + QSharedPointer<QJniObjectPrivate> d; +}; + +inline bool operator==(const QJniObject &obj1, const QJniObject &obj2) +{ + return obj1.isSameObject(obj2); +} + +inline bool operator!=(const QJniObject &obj1, const QJniObject &obj2) +{ + return !obj1.isSameObject(obj2); +} + +namespace QtJniTypes { +struct QT_TECH_PREVIEW_API JObjectBase +{ + operator QJniObject() const { return m_object; } + + bool isValid() const { return m_object.isValid(); } + jclass objectClass() const { return m_object.objectClass(); } + QString toString() const { return m_object.toString(); } + + template <typename T = jobject> + T object() const { + return m_object.object<T>(); } - template<typename T> - static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz, - jmethodID id, va_list args) - { - if constexpr(std::is_same<T, jboolean>::value) - res = env->CallStaticBooleanMethodV(clazz, id, args); - else if constexpr(std::is_same<T, jbyte>::value) - res = env->CallStaticByteMethodV(clazz, id, args); - else if constexpr(std::is_same<T, jchar>::value) - res = env->CallStaticCharMethodV(clazz, id, args); - else if constexpr(std::is_same<T, jshort>::value) - res = env->CallStaticShortMethodV(clazz, id, args); - else if constexpr(std::is_same<T, jint>::value) - res = env->CallStaticIntMethodV(clazz, id, args); - else if constexpr(std::is_same<T, jlong>::value) - res = env->CallStaticLongMethodV(clazz, id, args); - else if constexpr(std::is_same<T, jfloat>::value) - res = env->CallStaticFloatMethodV(clazz, id, args); - else if constexpr(std::is_same<T, jdouble>::value) - res = env->CallStaticDoubleMethodV(clazz, id, args); - else - staticAssertTypeMismatch(); +protected: + JObjectBase() = default; + ~JObjectBase() = default; + + Q_IMPLICIT JObjectBase(jobject object) : m_object(object) {} + Q_IMPLICIT JObjectBase(const QJniObject &object) : m_object(object) {} + Q_IMPLICIT JObjectBase(QJniObject &&object) noexcept : m_object(std::move(object)) {} + + QJniObject m_object; +}; + +template<typename Type> +class QT_TECH_PREVIEW_API JObject : public JObjectBase +{ +public: + using Class = Type; + + JObject() + : JObjectBase{QJniObject(QtJniTypes::Traits<Class>::className())} + {} + Q_IMPLICIT JObject(jobject object) : JObjectBase(object) {} + Q_IMPLICIT JObject(const QJniObject &object) : JObjectBase(object) {} + Q_IMPLICIT JObject(QJniObject &&object) noexcept : JObjectBase(std::move(object)) {} + + // base class destructor is protected, so need to provide all SMFs + JObject(const JObject &other) = default; + JObject(JObject &&other) noexcept = default; + JObject &operator=(const JObject &other) = default; + JObject &operator=(JObject &&other) noexcept = default; + + ~JObject() = default; + + template<typename Arg, typename ...Args + , std::enable_if_t<!std::is_same_v<Arg, JObject>, bool> = true + , IfValidSignatureTypes<Arg, Args...> = true + > + explicit JObject(Arg && arg, Args &&...args) + : JObjectBase{QJniObject(QtJniTypes::Traits<Class>::className(), + std::forward<Arg>(arg), std::forward<Args>(args)...)} + {} + + // named constructors avoid ambiguities + static Type fromJObject(jobject object) { return Type(object); } + template <typename ...Args> + static Type construct(Args &&...args) { return Type(std::forward<Args>(args)...); } + static Type fromLocalRef(jobject lref) { return Type(QJniObject::fromLocalRef(lref)); } + + static bool registerNativeMethods(std::initializer_list<JNINativeMethod> methods) + { + QJniEnvironment env; + return env.registerNativeMethods<Class>(methods); } - template<typename T> - static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, - jfieldID id) - { - if constexpr(std::is_same<T, jboolean>::value) - res = env->GetBooleanField(obj, id); - else if constexpr(std::is_same<T, jbyte>::value) - res = env->GetByteField(obj, id); - else if constexpr(std::is_same<T, jchar>::value) - res = env->GetCharField(obj, id); - else if constexpr(std::is_same<T, jshort>::value) - res = env->GetShortField(obj, id); - else if constexpr(std::is_same<T, jint>::value) - res = env->GetIntField(obj, id); - else if constexpr(std::is_same<T, jlong>::value) - res = env->GetLongField(obj, id); - else if constexpr(std::is_same<T, jfloat>::value) - res = env->GetFloatField(obj, id); - else if constexpr(std::is_same<T, jdouble>::value) - res = env->GetDoubleField(obj, id); - else - staticAssertTypeMismatch(); + // public API forwarding to QJniObject, with the implicit Class template parameter + template <typename Ret, typename ...Args +#ifndef Q_QDOC + , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true +#endif + > + static auto callStaticMethod(const char *name, Args &&...args) + { + return QJniObject::callStaticMethod<Class, Ret, Args...>(name, + std::forward<Args>(args)...); + } + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > + static auto getStaticField(const char *field) + { + return QJniObject::getStaticField<Class, T>(field); + } + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > + static void setStaticField(const char *field, T &&value) + { + QJniObject::setStaticField<Class, T>(field, std::forward<T>(value)); } - template<typename T> - static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, - jfieldID id) - { - if constexpr(std::is_same<T, jboolean>::value) - res = env->GetStaticBooleanField(clazz, id); - else if constexpr(std::is_same<T, jbyte>::value) - res = env->GetStaticByteField(clazz, id); - else if constexpr(std::is_same<T, jchar>::value) - res = env->GetStaticCharField(clazz, id); - else if constexpr(std::is_same<T, jshort>::value) - res = env->GetStaticShortField(clazz, id); - else if constexpr(std::is_same<T, jint>::value) - res = env->GetStaticIntField(clazz, id); - else if constexpr(std::is_same<T, jlong>::value) - res = env->GetStaticLongField(clazz, id); - else if constexpr(std::is_same<T, jfloat>::value) - res = env->GetStaticFloatField(clazz, id); - else if constexpr(std::is_same<T, jdouble>::value) - res = env->GetStaticDoubleField(clazz, id); - else - staticAssertTypeMismatch(); + // keep only these overloads, the rest is made private + template <typename Ret, typename ...Args +#ifndef Q_QDOC + , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true +#endif + > + auto callMethod(const char *method, Args &&...args) const + { + return m_object.callMethod<Ret>(method, std::forward<Args>(args)...); + } + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > + auto getField(const char *fieldName) const + { + return m_object.getField<T>(fieldName); } - template<typename T> - static constexpr void setFieldForType(JNIEnv *env, jobject obj, - jfieldID id, T value) - { - if constexpr(std::is_same<T, jboolean>::value) - env->SetBooleanField(obj, id, value); - else if constexpr(std::is_same<T, jbyte>::value) - env->SetByteField(obj, id, value); - else if constexpr(std::is_same<T, jchar>::value) - env->SetCharField(obj, id, value); - else if constexpr(std::is_same<T, jshort>::value) - env->SetShortField(obj, id, value); - else if constexpr(std::is_same<T, jint>::value) - env->SetIntField(obj, id, value); - else if constexpr(std::is_same<T, jlong>::value) - env->SetLongField(obj, id, value); - else if constexpr(std::is_same<T, jfloat>::value) - env->SetFloatField(obj, id, value); - else if constexpr(std::is_same<T, jdouble>::value) - env->SetDoubleField(obj, id, value); - else if constexpr(std::is_convertible<T, jobject>::value) - env->SetObjectField(obj, id, value); - else - staticAssertTypeMismatch(); + template <typename T +#ifndef Q_QDOC + , QtJniTypes::IfValidFieldType<T> = true +#endif + > + void setField(const char *fieldName, T &&value) + { + m_object.setField(fieldName, std::forward<T>(value)); } - template<typename T> - static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz, - jfieldID id, T value) - { - if constexpr(std::is_same<T, jboolean>::value) - env->SetStaticBooleanField(clazz, id, value); - else if constexpr(std::is_same<T, jbyte>::value) - env->SetStaticByteField(clazz, id, value); - else if constexpr(std::is_same<T, jchar>::value) - env->SetStaticCharField(clazz, id, value); - else if constexpr(std::is_same<T, jshort>::value) - env->SetStaticShortField(clazz, id, value); - else if constexpr(std::is_same<T, jint>::value) - env->SetStaticIntField(clazz, id, value); - else if constexpr(std::is_same<T, jlong>::value) - env->SetStaticLongField(clazz, id, value); - else if constexpr(std::is_same<T, jfloat>::value) - env->SetStaticFloatField(clazz, id, value); - else if constexpr(std::is_same<T, jdouble>::value) - env->SetStaticDoubleField(clazz, id, value); - else if constexpr(std::is_convertible<T, jobject>::value) - env->SetStaticObjectField(clazz, id, value); - else - staticAssertTypeMismatch(); + QByteArray className() const { + return QtJniTypes::Traits<Class>::className().data(); } - friend QJniObjectPrivate; - QSharedPointer<QJniObjectPrivate> d; +private: + friend bool comparesEqual(const JObject &lhs, const JObject &rhs) noexcept + { return lhs.m_object == rhs.m_object; } + Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(JObject); }; +} -inline bool operator==(const QJniObject &obj1, const QJniObject &obj2) +// This cannot be included earlier as QJniArray is a QJniObject subclass, but it +// must be included so that we can implement QJniObject::LocalFrame conversion. +QT_END_NAMESPACE +#include <QtCore/qjniarray.h> +QT_BEGIN_NAMESPACE + +template <typename ...Args> +template <typename T> +auto QJniObject::LocalFrame<Args...>::convertToJni(T &&value) { - return obj1.isSameObject(obj2); + using Type = q20::remove_cvref_t<T>; + if constexpr (std::is_same_v<Type, QString>) { + return newLocalRef<jstring>(QJniObject::fromString(value)); + } else if constexpr (QtJniTypes::IsJniArray<Type>::value) { + return value.arrayObject(); + } else if constexpr (QJniArrayBase::canConvert<T>) { + using QJniArrayType = decltype(QJniArrayBase::fromContainer(std::forward<T>(value))); + using ArrayType = decltype(std::declval<QJniArrayType>().arrayObject()); + return newLocalRef<ArrayType>(QJniArrayBase::fromContainer(std::forward<T>(value)).template object<jobject>()); + } else if constexpr (std::is_base_of_v<QJniObject, Type> + || std::is_base_of_v<QtJniTypes::JObjectBase, Type>) { + return value.object(); + } else { + return std::forward<T>(value); + } } -inline bool operator!=(const QJniObject &obj1, const QJniObject &obj2) +template <typename ...Args> +template <typename T> +auto QJniObject::LocalFrame<Args...>::convertFromJni(QJniObject &&object) { - return !obj1.isSameObject(obj2); + using Type = q20::remove_cvref_t<T>; + if constexpr (std::is_same_v<Type, QString>) { + return object.toString(); + } else if constexpr (QtJniTypes::IsJniArray<Type>::value) { + return T(std::move(object)); + } else if constexpr (QJniArrayBase::canConvert<Type>) { + // if we were to create a QJniArray from Type... + using QJniArrayType = decltype(QJniArrayBase::fromContainer(std::declval<Type>())); + // then that QJniArray would have elements of type + using ElementType = typename QJniArrayType::Type; + // construct a QJniArray from a jobject pointer of that type + return QJniArray<ElementType>(object.template object<jarray>()).toContainer(); + } else if constexpr (std::is_array_v<Type>) { + using ElementType = std::remove_extent_t<Type>; + return QJniArray<ElementType>(std::move(object)); + } else if constexpr (std::is_base_of_v<QJniObject, Type> + && !std::is_same_v<QJniObject, Type>) { + return T{std::move(object)}; + } else if constexpr (std::is_base_of_v<QtJniTypes::JObjectBase, Type>) { + return T{std::move(object)}; + } else { + return std::move(object); + } } + QT_END_NAMESPACE #endif |