summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qjniobject.h
blob: c28149bdc5933a2ace15e1a25efaa6082dca3e69 (plain)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
// 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#include <QtCore/qsharedpointer.h>#if defined(Q_QDOC) || defined(Q_OS_ANDROID)#include <jni.h>#include <QtCore/qjnienvironment.h>#include <QtCore/qxptype_traits.h> QT_BEGIN_NAMESPACE class QJniObjectPrivate;class QJniObject;namespace QtJniTypes {namespace Detail {// any type with an "jobject object()" member function stores a global referencetemplate<typename T, typename =void>struct StoresGlobalRefTest :std::false_type {};template<typename T>struct StoresGlobalRefTest<T,std::void_t<decltype(std::declval<T>().object())>>:std::is_same<decltype(std::declval<T>().object()), jobject>{};template<typename ...Args>struct LocalFrame {mutable JNIEnv *env;bool hasFrame =false;explicitLocalFrame(JNIEnv *env =nullptr) noexcept :env(env){}~LocalFrame(){if(hasFrame) env->PopLocalFrame(nullptr);}boolensureFrame(){if(!hasFrame) hasFrame =jniEnv()->PushLocalFrame(sizeof...(Args)) ==0;return hasFrame;} JNIEnv *jniEnv()const{if(!env) env =QJniEnvironment::getJniEnv();return env;}boolcheckAndClearExceptions(){return env ?QJniEnvironment::checkAndClearExceptions(env) :false;}template<typename T>autoconvertToJni(T &&value){using Type =q20::remove_cvref_t<T>;using ResultType =decltype(QtJniTypes::Traits<Type>::convertToJni(jniEnv(),std::declval<T&&>()));ifconstexpr(std::is_base_of_v<std::remove_pointer_t<jobject>,std::remove_pointer_t<ResultType>>) {// Make sure the local frame is engaged if we create a jobject, unless// we know that the value stores a global reference that it returns.ifconstexpr(!qxp::is_detected_v<StoresGlobalRefTest, Type>) {if(!ensureFrame())return ResultType{};}}returnQtJniTypes::Traits<Type>::convertToJni(jniEnv(),std::forward<T>(value));}template<typename T>autoconvertFromJni(QJniObject &&object){using Type =q20::remove_cvref_t<T>;returnQtJniTypes::Traits<Type>::convertFromJni(std::move(object));}};}}class Q_CORE_EXPORT QJniObject {template<typename ...Args>using LocalFrame =QtJniTypes::Detail::LocalFrame<Args...>;public:QJniObject();explicitQJniObject(const char*className);explicitQJniObject(const char*className,const char*signature, ...);template<typename ...Args #ifndef Q_QDOC,std::enable_if_t<!std::disjunction_v<QtJniTypes::IsStringType<std::decay_t<Args>>...>>* =nullptr#endif>explicitQJniObject(const char*className, Args &&...args):QJniObject(LocalFrame<Args...>{}, className,std::forward<Args>(args)...){}private:template<typename ...Args>explicitQJniObject(LocalFrame<Args...> localFrame,const char*className, Args &&...args):QJniObject(className,QtJniTypes::constructorSignature<Args...>().data(), localFrame.convertToJni(std::forward<Args>(args))...){}public:explicitQJniObject(jclass clazz);explicitQJniObject(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>explicitQJniObject(jclass clazz, Args &&...args):QJniObject(clazz,QtJniTypes::constructorSignature<Args...>().data(),std::forward<Args>(args)...){}QJniObject(jobject globalRef);QJniObject(const QJniObject &other) noexcept =default;QJniObject(QJniObject &&other) noexcept =default; QJniObject &operator=(const QJniObject &other) noexcept =default; QJniObject &operator=(QJniObject &&other) noexcept =default;~QJniObject();voidswap(QJniObject &other) noexcept { d.swap(other.d); }template<typename Class, typename ...Args>staticinline QJniObject construct(Args &&...args){ LocalFrame<Args...> frame;returnQJniObject(QtJniTypes::Traits<Class>::className().data(),QtJniTypes::constructorSignature<Args...>().data(), frame.convertToJni(std::forward<Args>(args))...);} jobject object()const;template<typename T> T object()const{QtJniTypes::assertObjectType<T>();return static_cast<T>(javaObject());} jclass objectClass()const; QByteArray className()const;template<typename Ret =void, typename ...Args #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<Ret> =true#endif>autocallMethod(const char*methodName,const char*signature, Args &&...args)const{ LocalFrame<Args...>frame(jniEnv());ifconstexpr(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) {ifconstexpr(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;}}ifconstexpr(!std::is_same_v<Ret,void>)return Ret{};}}template<typename Ret =void, typename ...Args #ifndef Q_QDOC,QtJniTypes::IfValidSignatureTypes<Ret, Args...> =true#endif>autocallMethod(const char*methodName, Args &&...args)const{constexpr auto signature =QtJniTypes::methodSignature<Ret, Args...>();return callMethod<Ret>(methodName, signature.data(),std::forward<Args>(args)...);}template<typename Ret, typename ...Args #ifndef Q_QDOC,QtJniTypes::IfValidSignatureTypes<Ret, Args...> =true#endif> QJniObject callObjectMethod(const char*methodName, Args &&...args)const{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))...));} QJniObject callObjectMethod(const char*methodName,const char*signature, ...)const;template<typename Ret =void, typename ...Args>staticautocallStaticMethod(const char*className,const char*methodName,const char*signature, Args &&...args){ JNIEnv *env =QJniEnvironment::getJniEnv(); jclass clazz =QJniObject::loadClass(className, env);return callStaticMethod<Ret>(clazz, methodName, signature,std::forward<Args>(args)...);}template<typename Ret =void, typename ...Args>staticautocallStaticMethod(jclass clazz,const char*methodName,const char*signature, Args &&...args){ JNIEnv *env =QJniEnvironment::getJniEnv(); jmethodID id = clazz ?getMethodID(env, clazz, methodName, signature,true):0;return callStaticMethod<Ret>(clazz, id,std::forward<Args>(args)...);}template<typename Ret =void, typename ...Args #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<Ret> =true#endif>staticautocallStaticMethod(jclass clazz, jmethodID methodId, Args &&...args){ LocalFrame<Args...> frame;ifconstexpr(QtJniTypes::isObjectType<Ret>()) {return frame.template convertFromJni<Ret>(callStaticObjectMethod(clazz, methodId, frame.convertToJni(std::forward<Args>(args))...));}else{if(clazz && methodId) {ifconstexpr(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;}}ifconstexpr(!std::is_same_v<Ret,void>)return Ret{};}}template<typename Ret =void, typename ...Args #ifndef Q_QDOC,QtJniTypes::IfValidSignatureTypes<Ret, Args...> =true#endif>staticautocallStaticMethod(const char*className,const char*methodName, Args &&...args){ 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<typename Ret =void, typename ...Args #ifndef Q_QDOC,QtJniTypes::IfValidSignatureTypes<Ret, Args...> =true#endif>staticautocallStaticMethod(jclass clazz,const char*methodName, Args &&...args){constexpr auto signature =QtJniTypes::methodSignature<Ret, Args...>();return callStaticMethod<Ret>(clazz, methodName, signature.data(),std::forward<Args>(args)...);}template<typename Klass, typename Ret =void, typename ...Args #ifndef Q_QDOC,QtJniTypes::IfValidSignatureTypes<Ret, Args...> =true#endif>staticautocallStaticMethod(const char*methodName, Args &&...args){ 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, ...);static QJniObject callStaticObjectMethod(jclass clazz,const char*methodName,const char*signature, ...);static QJniObject callStaticObjectMethod(jclass clazz, jmethodID methodId, ...);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){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 Ret, typename ...Args #ifndef Q_QDOC,QtJniTypes::IfValidSignatureTypes<Ret, Args...> =true#endif>static QJniObject callStaticObjectMethod(jclass clazz,const char*methodName, Args &&...args){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))...));}template<typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>autogetField(const char*fieldName)const{ LocalFrame<T>frame(jniEnv());ifconstexpr(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;}}template<typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>staticautogetStaticField(const char*className,const char*fieldName){ LocalFrame<T> frame;ifconstexpr(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 #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>staticautogetStaticField(jclass clazz,const char*fieldName){ LocalFrame<T> frame;ifconstexpr(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;}}template<typename Klass, typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>staticautogetStaticField(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{constexpr auto signature =QtJniTypes::fieldSignature<T>();returngetObjectField(fieldName, signature);} QJniObject getObjectField(const char*fieldName,const char*signature)const;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){constexpr auto signature =QtJniTypes::fieldSignature<T>();returngetStaticObjectField(className, fieldName, signature);}static QJniObject getStaticObjectField(const char*className,const char*fieldName,const char*signature);template<typename T #ifndef Q_QDOC,std::enable_if_t<QtJniTypes::isObjectType<T>(),bool> =true#endif>static QJniObject getStaticObjectField(jclass clazz,const char*fieldName){constexpr auto signature =QtJniTypes::fieldSignature<T>();returngetStaticObjectField(clazz, fieldName, signature);}static QJniObject getStaticObjectField(jclass clazz,const char*fieldName,const char*signature);template<typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>voidsetField(const char*fieldName, T value){constexpr auto signature =QtJniTypes::fieldSignature<T>(); jfieldID id =getCachedFieldID(jniEnv(), fieldName, signature);if(id) { setFieldForType<T>(jniEnv(),object(), id, value);QJniEnvironment::checkAndClearExceptions(jniEnv());}}template<typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>voidsetField(const char*fieldName,const char*signature, T value){ jfieldID id =getCachedFieldID(jniEnv(), fieldName, signature);if(id) { setFieldForType<T>(jniEnv(),object(), id, value);QJniEnvironment::checkAndClearExceptions(jniEnv());}}template<typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>static voidsetStaticField(const char*className,const char*fieldName, T value){ LocalFrame<T> frame; jclass clazz =QJniObject::loadClass(className, frame.jniEnv());if(!clazz)return;constexpr auto signature =QtJniTypes::fieldSignature<T>(); jfieldID id =getCachedFieldID(frame.jniEnv(), clazz, className, fieldName, signature,true);if(!id)return; setStaticFieldForType<T>(frame.jniEnv(), clazz, id, value); frame.checkAndClearExceptions();}template<typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>static voidsetStaticField(const char*className,const char*fieldName,const char*signature, T value){ JNIEnv *env =QJniEnvironment::getJniEnv(); jclass clazz =QJniObject::loadClass(className, env);if(!clazz)return; jfieldID id =getCachedFieldID(env, clazz, className, fieldName, signature,true);if(id) { setStaticFieldForType<T>(env, clazz, id, value);QJniEnvironment::checkAndClearExceptions(env);}}template<typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>static voidsetStaticField(jclass clazz,const char*fieldName,const char*signature, T value){ JNIEnv *env =QJniEnvironment::getJniEnv(); jfieldID id =getFieldID(env, clazz, fieldName, signature,true);if(id) { setStaticFieldForType<T>(env, clazz, id, value);QJniEnvironment::checkAndClearExceptions(env);}}template<typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>static voidsetStaticField(jclass clazz,const char*fieldName, T value){setStaticField(clazz, fieldName,QtJniTypes::fieldSignature<T>(), value);}template<typename Klass, typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>static voidsetStaticField(const char*fieldName, T value){setStaticField(QtJniTypes::Traits<Klass>::className(), fieldName, value);}static QJniObject fromString(const QString &string); QString toString()const;static boolisClassAvailable(const char*className);boolisValid()const;// This function takes ownership of the jobject and releases the local ref. before returning.static QJniObject fromLocalRef(jobject lref);template<typename T,std::enable_if_t<std::is_convertible_v<T, jobject>,bool> =true> QJniObject &operator=(T obj){assign(static_cast<T>(obj));return*this;}protected:QJniObject(Qt::Initialization) {} JNIEnv *jniEnv()const noexcept;private:static jclass loadClass(const QByteArray &className, JNIEnv *env);#if QT_CORE_REMOVED_SINCE(6, 7)// these need to stay in the ABI as they were used in inline methods before 6.7static jclass loadClass(const QByteArray &className, JNIEnv *env,bool binEncoded);static QByteArray toBinaryEncClassName(const QByteArray &className);voidcallVoidMethodV(JNIEnv *env, jmethodID id,va_list args)const;#endifstatic jfieldID getCachedFieldID(JNIEnv *env, jclass clazz,const QByteArray &className,const char*name,const char*signature,bool isStatic =false); jfieldID getCachedFieldID(JNIEnv *env,const char*name,const char*signature,bool isStatic =false)const;static jmethodID getCachedMethodID(JNIEnv *env, jclass clazz,const QByteArray &className,const char*name,const char*signature,bool isStatic =false); jmethodID getCachedMethodID(JNIEnv *env,const char*name,const char*signature,bool isStatic =false)const;static jfieldID getFieldID(JNIEnv *env, jclass clazz,const char*name,const char*signature,bool isStatic =false);static jmethodID getMethodID(JNIEnv *env, jclass clazz,const char*name,const char*signature,bool isStatic =false);voidcallVoidMethodV(JNIEnv *env, jmethodID id, ...)const;boolisSameObject(jobject obj)const;boolisSameObject(const QJniObject &other)const;voidassign(jobject obj); jobject javaObject()const;friendbooloperator==(const QJniObject &,const QJniObject &);friendbooloperator!=(const QJniObject&,const QJniObject&);template<typename T>staticconstexprvoidcallMethodForType(JNIEnv *env, T &res, jobject obj, jmethodID id, ...){va_list args = {};va_start(args, id);QtJniTypes::Caller<T>::callMethodForType(env, res, obj, id, args);va_end(args);}template<typename T>staticconstexprvoidcallStaticMethodForType(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);}static voidcallStaticMethodForVoid(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>staticconstexprvoidgetFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id){QtJniTypes::Caller<T>::getFieldForType(env, res, obj, id);}template<typename T>staticconstexprvoidgetStaticFieldForType(JNIEnv *env, T &res, jclass clazz, jfieldID id){QtJniTypes::Caller<T>::getStaticFieldForType(env, res, clazz, id);}template<typename T>staticconstexprvoidsetFieldForType(JNIEnv *env, jobject obj, jfieldID id, T value){ifconstexpr(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>staticconstexprvoidsetStaticFieldForType(JNIEnv *env, jclass clazz, jfieldID id, T value){ifconstexpr(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);}}friend QJniObjectPrivate; QSharedPointer<QJniObjectPrivate> d;};inlinebooloperator==(const QJniObject &obj1,const QJniObject &obj2){return obj1.isSameObject(obj2);}inlinebooloperator!=(const QJniObject &obj1,const QJniObject &obj2){return!obj1.isSameObject(obj2);}namespace QtJniTypes {struct QT_TECH_PREVIEW_API JObjectBase {operatorQJniObject()const{return m_object; }boolisValid()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>();}protected:JObjectBase() =default;JObjectBase(const JObjectBase &) =default;JObjectBase(JObjectBase &&) =default; JObjectBase &operator=(const JObjectBase &) =default; JObjectBase &operator=(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 SMFs are protected, make them public: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<q20::remove_cvref_t<Arg>, JObject>,bool> =true, IfValidSignatureTypes<Arg, Args...> =true>explicitJObject(Arg && arg, Args &&...args): JObjectBase{QJniObject(QtJniTypes::Traits<Class>::className(),std::forward<Arg>(arg),std::forward<Args>(args)...)}{}// named constructors avoid ambiguitiesstatic JObject fromJObject(jobject object){returnJObject(object);}template<typename ...Args>static JObject construct(Args &&...args){returnJObject(std::forward<Args>(args)...);}static JObject fromLocalRef(jobject lref){returnJObject(QJniObject::fromLocalRef(lref));}static boolregisterNativeMethods(std::initializer_list<JNINativeMethod> methods){ QJniEnvironment env;return env.registerNativeMethods<Class>(methods);}// public API forwarding to QJniObject, with the implicit Class template parametertemplate<typename Ret =void, typename ...Args #ifndef Q_QDOC,QtJniTypes::IfValidSignatureTypes<Ret, Args...> =true#endif>staticautocallStaticMethod(const char*name, Args &&...args){returnQJniObject::callStaticMethod<Class, Ret, Args...>(name,std::forward<Args>(args)...);}template<typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>staticautogetStaticField(const char*field){returnQJniObject::getStaticField<Class, T>(field);}template<typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>static voidsetStaticField(const char*field, T &&value){QJniObject::setStaticField<Class, T>(field,std::forward<T>(value));}// keep only these overloads, the rest is made privatetemplate<typename Ret =void, typename ...Args #ifndef Q_QDOC,QtJniTypes::IfValidSignatureTypes<Ret, Args...> =true#endif>autocallMethod(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>autogetField(const char*fieldName)const{return m_object.getField<T>(fieldName);}template<typename T #ifndef Q_QDOC,QtJniTypes::IfValidFieldType<T> =true#endif>voidsetField(const char*fieldName, T &&value){ m_object.setField(fieldName,std::forward<T>(value));} QByteArray className()const{returnQtJniTypes::Traits<Class>::className().data();}private:friendboolcomparesEqual(const JObject &lhs,const JObject &rhs){return lhs.m_object == rhs.m_object; }Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(JObject);};template<typename T>struct Traits<JObject<T>> {staticconstexpr autosignature() {return Traits<T>::signature(); }staticconstexpr autoclassName() {return Traits<T>::className(); }staticautoconvertToJni(JNIEnv *,const JObject<T> &value){return value.object();}staticautoconvertFromJni(QJniObject &&object){return JObject<T>(std::move(object));}};template<>struct Traits<QJniObject>{staticconstexpr autoclassName(){returnCTString("java/lang/Object");}staticconstexpr autosignature(){returnCTString("Ljava/lang/Object;");}staticautoconvertToJni(JNIEnv *,const QJniObject &value){return value.object();}staticautoconvertFromJni(QJniObject &&object){returnstd::move(object);}};template<>struct Traits<QString>{staticconstexpr autoclassName(){returnCTString("java/lang/String");}staticconstexpr autosignature(){returnCTString("Ljava/lang/String;");}staticautoconvertToJni(JNIEnv *env,const QString &value){returnQtJniTypes::Detail::fromQString(value, env);}staticautoconvertFromJni(QJniObject &&object){return object.toString();}};} QT_END_NAMESPACE #endif#endif// QJNIOBJECT_H
close