diff options
author | Assam Boudjelthia <assam.boudjelthia@qt.io> | 2021-02-01 15:08:21 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-02-09 18:23:26 +0000 |
commit | 77b035aa6e73ce317242a21f181a8e5849a36bee (patch) | |
tree | 3a851742d6f269624ac8462821b8063cf9ac6da0 /src | |
parent | bbdcc86c52d806ab45fabf167526f9dcec291648 (diff) |
Documentation improvements to JNI API
Amends 4e60681c879a54cf5b34862a30e27c492ed36363.
Fixes: QTBUG-89632
Change-Id: I7856e9b63eea5ba68a5472575016540ae656ec5f
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
(cherry picked from commit 817f8ac03cd4e85b7813b45f8cabf5b679f28702)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/doc/snippets/jni/src_qjniobject.cpp | 21 | ||||
-rw-r--r-- | src/corelib/doc/src/external-resources.qdoc | 27 | ||||
-rw-r--r-- | src/corelib/kernel/qjnienvironment.cpp | 68 | ||||
-rw-r--r-- | src/corelib/kernel/qjniobject.cpp | 456 | ||||
-rw-r--r-- | src/corelib/kernel/qjniobject.h | 54 |
5 files changed, 362 insertions, 264 deletions
diff --git a/src/corelib/doc/snippets/jni/src_qjniobject.cpp b/src/corelib/doc/snippets/jni/src_qjniobject.cpp index f3433134db..b729987d4f 100644 --- a/src/corelib/doc/snippets/jni/src_qjniobject.cpp +++ b/src/corelib/doc/snippets/jni/src_qjniobject.cpp @@ -79,7 +79,7 @@ void functionScope() } //! [QJniObject scope] -//! [Registering native methods] +//! [C++ native methods] static void fromJavaOne(JNIEnv *env, jobject thiz, jint x) { Q_UNUSED(env); @@ -94,26 +94,19 @@ static void fromJavaTwo(JNIEnv *env, jobject thiz, jint x) qDebug() << x << ">= 100"; } -void registerNativeMethods() { +void foo() +{ + // register the native methods first, ideally it better be done with the app start JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)}, {"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}}; - - QJniObject javaClass("my/java/project/FooJavaClass"); QJniEnvironment env; - jclass objectClass = env->GetObjectClass(javaClass.object<jobject>()); - env->RegisterNatives(objectClass, - methods, - sizeof(methods) / sizeof(methods[0])); - env->DeleteLocalRef(objectClass); -} + env.registerNativeMethods("my/java/project/FooJavaClass", methods, 2); -void foo() -{ + // Call the java method which will calls back to the C++ functions QJniObject::callStaticMethod<void>("my/java/project/FooJavaClass", "foo", "(I)V", 10); // Output: 10 < 100 QJniObject::callStaticMethod<void>("my/java/project/FooJavaClass", "foo", "(I)V", 100); // Output: 100 >= 100 } - -//! [Registering native methods] +//! [C++ native methods] //! [Java native methods] class FooJavaClass diff --git a/src/corelib/doc/src/external-resources.qdoc b/src/corelib/doc/src/external-resources.qdoc index c3dc67a705..583e668be4 100644 --- a/src/corelib/doc/src/external-resources.qdoc +++ b/src/corelib/doc/src/external-resources.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -65,3 +65,28 @@ \externalpage https://marcmutz.wordpress.com/effective-qt/containers/ \title Understand the Qt Containers */ + +/*! + \externalpage https://developer.android.com/training/articles/perf-jni#javavm-and-jnienv + \title JNI tips: JavaVM and JNIEnv +*/ + +/*! + \externalpage https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html + \title Java Native Interface Specification +*/ + +/*! + \externalpage https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html + \title Oracle: JNI Functions +*/ + +/*! + \externalpage https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references + \title JNI Design Overview: Global and Local References +*/ + +/*! + \externalpage https://developer.android.com/training/articles/perf-jni#local-and-global-references + \title JNI tips: Local and global references +*/ diff --git a/src/corelib/kernel/qjnienvironment.cpp b/src/corelib/kernel/qjnienvironment.cpp index 4e52f33e0c..eea62116d6 100644 --- a/src/corelib/kernel/qjnienvironment.cpp +++ b/src/corelib/kernel/qjnienvironment.cpp @@ -49,11 +49,19 @@ QT_BEGIN_NAMESPACE /*! \class QJniEnvironment \inmodule QtCore - \brief The QJniEnvironment provides access to the JNI Environment. \since 6.1 + \brief The QJniEnvironment class provides access to the JNI Environment (JNIEnv). - \note This API has been tested and meant to be mainly used for Android and it hasn't been tested - for other platforms. + When using JNI, the \l {JNI tips: JavaVM and JNIEnv}{JNIEnv} class is a pointer to a function + table and a member function for each JNI function that indirects through the table. \c JNIEnv + provides most of the JNI functions. Every C++ native function receives a \c JNIEnv as the first + argument. The JNI environment cannot be shared between threads. + + Since \c JNIEnv doesn't do much error checking, such as exception checking and clearing, + QJniEnvironment allows you to do that easily. + + \note This API has been designed and tested for use with Android. + It has not been tested for other platforms. */ static const char qJniThreadName[] = "QtThread"; @@ -96,7 +104,7 @@ Q_GLOBAL_STATIC(QThreadStorage<QJniEnvironmentPrivateTLS *>, jniEnvTLS) /*! \fn QJniEnvironment::QJniEnvironment() - Constructs a new QJniEnvironment object and attaches the current thread to the Java VM. + Constructs a new JNI Environment object and attaches the current thread to the Java VM. */ QJniEnvironment::QJniEnvironment() : d(new QJniEnvironmentPrivate{}) @@ -120,6 +128,7 @@ QJniEnvironment::QJniEnvironment() \fn QJniEnvironment::~QJniEnvironment() Detaches the current thread from the Java VM and destroys the QJniEnvironment object. + This will clear any pending exception by calling exceptionCheckAndClear(). */ QJniEnvironment::~QJniEnvironment() { @@ -152,13 +161,13 @@ QJniEnvironment::operator JNIEnv* () const Searches for \a className using all available class loaders. Qt on Android uses a custom class loader to load all the .jar files and it must be used to find any classes that are created by that class loader because these - classes are not visible in the default class loader. + classes are not visible when using the default class loader. Returns the class pointer or null if is not found. A use case for this function is searching for a custom class then calling - its memeber method. The following code snippet create an instance of the - class \c CustomClass and then calls \c printFromJava() method: + its member method. The following code snippet creates an instance of the + class \c CustomClass and then calls the \c printFromJava() method: \code QJniEnvironment env; @@ -170,8 +179,6 @@ QJniEnvironment::operator JNIEnv* () const "(Ljava/lang/String;)V", javaMessage.object<jstring>()); \endcode - - \since Qt 6.1 */ jclass QJniEnvironment::findClass(const char *className) { @@ -181,9 +188,9 @@ jclass QJniEnvironment::findClass(const char *className) /*! \fn JavaVM *QJniEnvironment::javaVM() - Returns the Java VM interface. + Returns the Java VM interface for the current process. Although it might + be possible to have multiple Java VMs per process, Android allows only one. - \since Qt 6.1 */ JavaVM *QJniEnvironment::javaVM() { @@ -191,10 +198,11 @@ JavaVM *QJniEnvironment::javaVM() } /*! - \fn bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMethod methods[]) + \fn bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMethod methods[], int size) - Registers the Java methods \a methods that can call native C++ functions from class \a - className. These methods must be registered before any attempt to call them. + Registers the Java methods in the array \a methods of size \a size, each of + which can call native C++ functions from class \a className. These methods + must be registered before any attempt to call them. Returns True if the registration is successful, otherwise False. @@ -209,10 +217,8 @@ JavaVM *QJniEnvironment::javaVM() JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)}, {"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}}; QJniEnvironment env; - env.registerNativeMethods("org/qtproject/android/TestJavaClass", methods); + env.registerNativeMethods("org/qtproject/android/TestJavaClass", methods, 2); \endcode - - \since Qt 6.1 */ bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMethod methods[], int size) { @@ -233,18 +239,23 @@ bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMeth } /*! - \enum QJniExceptionCleaner::OutputMode + \enum QJniEnvironment::OutputMode - \value Silent the exceptions are cleaned silently - \value Verbose describes the exceptions before cleaning them + \value Silent The exceptions are cleaned silently + \value Verbose Prints the exceptions and their stack backtrace as an error + to \c stderr stream. */ /*! - \fn QJniEnvironment::exceptionCheckAndClear(OutputMode outputMode = OutputMode::Silent) + \fn QJniEnvironment::exceptionCheckAndClear(OutputMode outputMode = OutputMode::Verbose) - Cleans any pending exceptions either silently or with descriptions, depending on the \a outputMode. + Cleans any pending exceptions either silently or reporting stack backtrace, + depending on the \a outputMode. - \since 6.1 + In contrast to \l QJniObject, which handles exceptions internally, if you + make JNI calls directly via \c JNIEnv, you need to clear any potential + exceptions after the call using this function. For more information about + \c JNIEnv calls that can throw an exception, see \l {Oracle: JNI Functions}{JNI Functions}. */ bool QJniEnvironment::exceptionCheckAndClear(QJniEnvironment::OutputMode outputMode) { @@ -260,11 +271,16 @@ bool QJniEnvironment::exceptionCheckAndClear(QJniEnvironment::OutputMode outputM } /*! - \fn QJniEnvironment::exceptionCheckAndClear(JNIEnv *env, OutputMode outputMode = OutputMode::Silent) + \fn QJniEnvironment::exceptionCheckAndClear(JNIEnv *env, OutputMode outputMode = OutputMode::Verbose) - Cleans any pending exceptions for \a env, either silently or with descriptions, depending on the \a outputMode. + Cleans any pending exceptions for \a env, either silently or reporting + stack backtrace, depending on the \a outputMode. This is useful when you + already have a \c JNIEnv pointer such as in a native function implementation. - \since 6.1 + In contrast to \l QJniObject, which handles exceptions internally, if you + make JNI calls directly via \c JNIEnv, you need to clear any potential + exceptions after the call using this function. For more information about + \c JNIEnv calls that can throw an exception, see \l {Oracle: JNI Functions}{JNI Functions}. */ bool QJniEnvironment::exceptionCheckAndClear(JNIEnv *env, QJniEnvironment::OutputMode outputMode) { diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp index ba7d0af778..6059ad4bf7 100644 --- a/src/corelib/kernel/qjniobject.cpp +++ b/src/corelib/kernel/qjniobject.cpp @@ -49,22 +49,28 @@ QT_BEGIN_NAMESPACE /*! \class QJniObject \inmodule QtCore - \brief Provides a convenient set of APIs to call Java code from C++ using the Java Native Interface (JNI). \since 6.1 + \brief A convenience wrapper around the Java Native Interface (JNI). + + The QJniObject class wraps a reference to a Java object, ensuring it isn't + gargage-collected and providing access to most \c JNIEnv method calls + (member, static) and fields (setter, getter). It eliminates much + boiler-plate that would normally be needed, with direct JNI access, for + every operation, including exception-handling. + + \note This API has been designed and tested for use with Android. + It has not been tested for other platforms. \sa QJniEnvironment \section1 General Notes \list - \li Class names needs to contain the fully-qualified class name, for example: \b"java/lang/String". - \li Method signatures are written as \b"(Arguments)ReturnType" + \li Class names need to be fully-qualified, for example: \c "java/lang/String". + \li Method signatures are written as \c "(ArgumentsTypes)ReturnType", see \l {JNI Types}. \li All object types are returned as a QJniObject. \endlist - \note This API has been tested and meant to be mainly used for Android and it hasn't been tested - for other platforms. - \section1 Method Signatures For functions that take no arguments, QJniObject provides convenience functions that will use @@ -76,11 +82,12 @@ QT_BEGIN_NAMESPACE \endcode In other cases you will need to supply the signature yourself, and it is important that the - signature matches the function you want to call. The signature structure is \b \(A\)R, where \b A - is the type of the argument\(s\) and \b R is the return type. Array types in the signature must - have the \b\[ suffix and the fully-qualified type names must have the \b L prefix and \b ; suffix. + signature matches the function you want to call. The signature structure is + \c "(ArgumentsTypes)ReturnType". Array types in the signature must have the \c {[} prefix, + and the fully-qualified \c Object type names must have the \c L prefix and the \c ; suffix. + + The example below demonstrates how to call two different static functions: - The example below demonstrates how to call two different static functions. \code // Java class package org.qtproject.qt; @@ -91,45 +98,48 @@ QT_BEGIN_NAMESPACE } \endcode - The signature for the first function is \b"\(I\)Ljava/lang/String;" + The signature for the first function is \c {"\(I\)Ljava/lang/String;"}: \code // C++ code QJniObject stringNumber = QJniObject::callStaticObjectMethod("org/qtproject/qt/TestClass", - "fromNumber" - "(I)Ljava/lang/String;", - 10); + "fromNumber" + "(I)Ljava/lang/String;", + 10); \endcode - and the signature for the second function is \b"\(Ljava/lang/String;Ljava/lang/String;\)\[Ljava/lang/String;" + and the signature for the second function is + \c "\(Ljava/lang/String;Ljava/lang/String;\)\[Ljava/lang/String;": \code // C++ code QJniObject string1 = QJniObject::fromString("String1"); QJniObject string2 = QJniObject::fromString("String2"); QJniObject stringArray = QJniObject::callStaticObjectMethod("org/qtproject/qt/TestClass", - "stringArray" - "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;" - string1.object<jstring>(), - string2.object<jstring>()); + "stringArray" + "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;" + string1.object<jstring>(), + string2.object<jstring>()); \endcode - \section1 Handling Java Exception - When calling Java functions that might throw an exception, it is important that you check, handle - and clear out the exception before continuing. + After calling Java functions that might throw exceptions, it is important + to check for, handle and clear out any exception before continuing. All + QJniObject functions handle exceptions internally by reporting and clearing them, + saving client code the need to handle exceptions. - \note It is unsafe to make a JNI call when there are exceptions pending. For more information, - see QJniEnvironment::exceptionCheckAndClear(). + \note The user must handle exceptions manually when doing JNI calls using \c JNIEnv directly. + It is unsafe to make other JNI calls when exceptions are pending. For more information, see + QJniEnvironment::exceptionCheckAndClear(). \section1 Java Native Methods Java native methods makes it possible to call native code from Java, this is done by creating a - function declaration in Java and prefixing it with the \b native keyword. + function declaration in Java and prefixing it with the \c native keyword. Before a native function can be called from Java, you need to map the Java native function to a - native function in your code. Mapping functions can be done by calling the RegisterNatives() function - through the \l{QJniEnvironment}{JNI environment pointer}. + native function in your code. Mapping functions can be done by calling + QJniEnvironment::registerNativeMethods(). The example below demonstrates how this could be done. @@ -137,14 +147,25 @@ QT_BEGIN_NAMESPACE \snippet jni/src_qjniobject.cpp Java native methods C++ Implementation: - \snippet jni/src_qjniobject.cpp Registering native methods + \snippet jni/src_qjniobject.cpp C++ native methods \section1 The Lifetime of a Java Object - Most \l{Object types}{objects} received from Java will be local references and will only stay valid - in the scope you received them. After that, the object becomes eligible for garbage collection. If you - want to keep a Java object alive you need to either create a new global reference to the object and - release it when you are done, or construct a new QJniObject and let it manage the lifetime of the Java object. + Most \l{Object types}{objects} received from Java will be local references + and will only stay valid until you return from the native method. After that, + the object becomes eligible for garbage collection. If your code creates + many local references in a loop you should delete them manually with each + iteration, otherwise you might run out of memory. For more information, see + \l {JNI Design Overview: Global and Local References}. Local references + created outside a native method scope must be deleted manually, since + the garbage collector will not free them automatically because we are using + \c AttachCurrentThread. For more information, see + \l {JNI tips: Local and global references}. + + If you want to keep a Java object alive you need to either create a new global + reference to the object and release it when you are done, or construct a new + QJniObject and let it manage the lifetime of the Java object. + \sa object() \note The QJniObject only manages its own references, if you construct a QJniObject from a @@ -245,7 +266,7 @@ QT_BEGIN_NAMESPACE \li L\e<fully-qualified-name>; \endtable - For more information about JNI see: \l http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html + For more information about JNI, see \l {Java Native Interface Specification}. */ /*! @@ -338,11 +359,11 @@ Q_GLOBAL_STATIC(QReadWriteLock, cachedMethodIDLock) static inline jmethodID getMethodID(JNIEnv *env, jclass clazz, const char *name, - const char *sig, + const char *signature, bool isStatic = false) { - jmethodID id = isStatic ? env->GetStaticMethodID(clazz, name, sig) - : env->GetMethodID(clazz, name, sig); + jmethodID id = isStatic ? env->GetStaticMethodID(clazz, name, signature) + : env->GetMethodID(clazz, name, signature); if (QJniEnvironment::exceptionCheckAndClear(env)) return nullptr; @@ -354,13 +375,15 @@ static jmethodID getCachedMethodID(JNIEnv *env, jclass clazz, const QByteArray &className, const char *name, - const char *sig, + const char *signature, bool isStatic = false) { if (className.isEmpty()) - return getMethodID(env, clazz, name, sig, isStatic); + return getMethodID(env, clazz, name, signature, isStatic); - const QString key = keyBase().arg(QLatin1String(className), QLatin1String(name), QLatin1String(sig)); + const QString key = keyBase().arg(QLatin1String(className), + QLatin1String(name), + QLatin1String(signature)); QHash<QString, jmethodID>::const_iterator it; { @@ -376,7 +399,7 @@ static jmethodID getCachedMethodID(JNIEnv *env, if (it != cachedMethodID->constEnd()) return it.value(); - jmethodID id = getMethodID(env, clazz, name, sig, isStatic); + jmethodID id = getMethodID(env, clazz, name, signature, isStatic); cachedMethodID->insert(key, id); return id; @@ -390,11 +413,11 @@ Q_GLOBAL_STATIC(QReadWriteLock, cachedFieldIDLock) static inline jfieldID getFieldID(JNIEnv *env, jclass clazz, const char *name, - const char *sig, + const char *signature, bool isStatic = false) { - jfieldID id = isStatic ? env->GetStaticFieldID(clazz, name, sig) - : env->GetFieldID(clazz, name, sig); + jfieldID id = isStatic ? env->GetStaticFieldID(clazz, name, signature) + : env->GetFieldID(clazz, name, signature); if (QJniEnvironment::exceptionCheckAndClear(env)) return nullptr; @@ -406,13 +429,15 @@ static jfieldID getCachedFieldID(JNIEnv *env, jclass clazz, const QByteArray &className, const char *name, - const char *sig, + const char *signature, bool isStatic = false) { if (className.isNull()) - return getFieldID(env, clazz, name, sig, isStatic); + return getFieldID(env, clazz, name, signature, isStatic); - const QString key = keyBase().arg(QLatin1String(className), QLatin1String(name), QLatin1String(sig)); + const QString key = keyBase().arg(QLatin1String(className), + QLatin1String(name), + QLatin1String(signature)); QHash<QString, jfieldID>::const_iterator it; { @@ -428,7 +453,7 @@ static jfieldID getCachedFieldID(JNIEnv *env, if (it != cachedFieldID->constEnd()) return it.value(); - jfieldID id = getFieldID(env, clazz, name, sig, isStatic); + jfieldID id = getFieldID(env, clazz, name, signature, isStatic); cachedFieldID->insert(key, id); return id; @@ -491,7 +516,7 @@ public: /*! \fn QJniObject::QJniObject() - Constructs an invalid QJniObject. + Constructs an invalid JNI object. \sa isValid() */ @@ -503,7 +528,7 @@ QJniObject::QJniObject() /*! \fn QJniObject::QJniObject(const char *className) - Constructs a new QJniObject by calling the default constructor of \a className. + Constructs a new JNI object by calling the default constructor of \a className. \code QJniObject myJavaString("java/lang/String"); @@ -532,8 +557,8 @@ QJniObject::QJniObject(const char *className) /*! \fn QJniObject::QJniObject(const char *className, const char *signature, ...) - Constructs a new QJniObject by calling the constructor of \a className with \a signature - and arguments. + Constructs a new JNI object by calling the constructor of \a className with + \a signature specifying the types of any subsequent arguments. \code QJniEnvironment env; @@ -542,7 +567,7 @@ QJniObject::QJniObject(const char *className) QJniObject myNewJavaString("java/lang/String", "(Ljava/lang/String;)V", myJStringArg); \endcode */ -QJniObject::QJniObject(const char *className, const char *sig, ...) +QJniObject::QJniObject(const char *className, const char *signature, ...) : d(new QJniObjectPrivate()) { QJniEnvironment env; @@ -550,10 +575,10 @@ QJniObject::QJniObject(const char *className, const char *sig, ...) d->m_jclass = loadClass(d->m_className, env, true); d->m_own_jclass = false; if (d->m_jclass) { - jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "<init>", sig); + jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "<init>", signature); if (constructorId) { va_list args; - va_start(args, sig); + va_start(args, signature); jobject obj = env->NewObjectV(d->m_jclass, constructorId, args); va_end(args); if (obj) { @@ -564,7 +589,7 @@ QJniObject::QJniObject(const char *className, const char *sig, ...) } } -QJniObject::QJniObject(const char *className, const char *sig, const QVaListPrivate &args) +QJniObject::QJniObject(const char *className, const char *signature, const QVaListPrivate &args) : d(new QJniObjectPrivate()) { QJniEnvironment env; @@ -572,7 +597,7 @@ QJniObject::QJniObject(const char *className, const char *sig, const QVaListPriv d->m_jclass = loadClass(d->m_className, env, true); d->m_own_jclass = false; if (d->m_jclass) { - jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "<init>", sig); + jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "<init>", signature); if (constructorId) { jobject obj = env->NewObjectV(d->m_jclass, constructorId, args); if (obj) { @@ -586,8 +611,8 @@ QJniObject::QJniObject(const char *className, const char *sig, const QVaListPriv /*! \fn QJniObject::QJniObject(jclass clazz, const char *signature, ...) - Constructs a new QJniObject from \a clazz by calling the constructor with \a signature - and arguments. + Constructs a new JNI object from \a clazz by calling the constructor with + \a signature specifying the types of any subsequent arguments. \code QJniEnvironment env; @@ -595,17 +620,17 @@ QJniObject::QJniObject(const char *className, const char *sig, const QVaListPriv QJniObject(myClazz, "(I)V", 3); \endcode */ -QJniObject::QJniObject(jclass clazz, const char *sig, ...) +QJniObject::QJniObject(jclass clazz, const char *signature, ...) : d(new QJniObjectPrivate()) { QJniEnvironment env; if (clazz) { d->m_jclass = static_cast<jclass>(env->NewGlobalRef(clazz)); if (d->m_jclass) { - jmethodID constructorId = getMethodID(env, d->m_jclass, "<init>", sig); + jmethodID constructorId = getMethodID(env, d->m_jclass, "<init>", signature); if (constructorId) { va_list args; - va_start(args, sig); + va_start(args, signature); jobject obj = env->NewObjectV(d->m_jclass, constructorId, args); va_end(args); if (obj) { @@ -620,9 +645,9 @@ QJniObject::QJniObject(jclass clazz, const char *sig, ...) /*! \fn QJniObject::QJniObject(jclass clazz) - Constructs a new QJniObject by calling the default constructor of \a clazz. + Constructs a new JNI object by calling the default constructor of \a clazz. - Note: The QJniObject will create a new reference to the class \a clazz + \note The QJniObject will create a new reference to the class \a clazz and releases it again when it is destroyed. References to the class created outside the QJniObject need to be managed by the caller. */ @@ -645,14 +670,14 @@ QJniObject::QJniObject(jclass clazz) } } -QJniObject::QJniObject(jclass clazz, const char *sig, const QVaListPrivate &args) +QJniObject::QJniObject(jclass clazz, const char *signature, const QVaListPrivate &args) : d(new QJniObjectPrivate()) { QJniEnvironment env; if (clazz) { d->m_jclass = static_cast<jclass>(env->NewGlobalRef(clazz)); if (d->m_jclass) { - jmethodID constructorId = getMethodID(env, d->m_jclass, "<init>", sig); + jmethodID constructorId = getMethodID(env, d->m_jclass, "<init>", signature); if (constructorId) { jobject obj = env->NewObjectV(d->m_jclass, constructorId, args); if (obj) { @@ -667,7 +692,7 @@ QJniObject::QJniObject(jclass clazz, const char *sig, const QVaListPrivate &args /*! \fn QJniObject::QJniObject(jobject object) - Constructs a new QJniObject around the Java object \a object. + Constructs a new JNI object around the Java object \a object. \note The QJniObject will hold a reference to the Java object \a object and release it when destroyed. Any references to the Java object \a object @@ -694,43 +719,40 @@ QJniObject::QJniObject(jobject obj) /*! \fn QJniObject::~QJniObject() - Destroys the QJniObject and releases any references held by the QJniObject. + Destroys the JNI object and releases any references held by the JNI object. */ QJniObject::~QJniObject() {} /*! - \fn template <typename T> T QJniObject::object() const + \fn jobject QJniObject::object() const - Returns the object held by the QJniObject as type T. + Returns the object held by the QJniObject as jobject. \code - QJniObject string = QJniObject::fromString("Hello, JNI"); - jstring jstring = string.object<jstring>(); + jobject object = jniObject.object(); \endcode - \note The returned object is still owned by the QJniObject. If you want to keep the object valid - you should create a new QJniObject or make a new global reference to the object and - free it yourself. + \note The returned object is still kept live by this QJniObject. To keep the + object live beyond the lifetime of this QJniObject, for example to record it + for later use, the easiest approach is to store it in another QJniObject with + a suitable lifetime. Alternatively, you can make a new global reference to the + object and store it, taking care to free it when you are done with it. \snippet jni/src_qjniobject.cpp QJniObject scope - - \code - jobject object = jniObject.object(); - \endcode */ -Q_CORE_EXPORT jobject QJniObject::object() const +jobject QJniObject::object() const { return javaObject(); } QJniObject QJniObject::callObjectMethodV(const char *methodName, - const char *sig, + const char *signature, va_list args) const { QJniEnvironment env; jobject res = nullptr; - jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, signature); if (id) { res = env->CallObjectMethodV(d->m_jobject, id, args); if (env.exceptionCheckAndClear()) { @@ -746,14 +768,15 @@ QJniObject QJniObject::callObjectMethodV(const char *methodName, QJniObject QJniObject::callStaticObjectMethodV(const char *className, const char *methodName, - const char *sig, + const char *signature, va_list args) { QJniEnvironment env; jobject res = nullptr; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), + methodName, signature, true); if (id) { res = env->CallStaticObjectMethodV(clazz, id, args); if (env.exceptionCheckAndClear()) { @@ -770,12 +793,12 @@ QJniObject QJniObject::callStaticObjectMethodV(const char *className, QJniObject QJniObject::callStaticObjectMethodV(jclass clazz, const char *methodName, - const char *sig, + const char *signature, va_list args) { QJniEnvironment env; jobject res = nullptr; - jmethodID id = getMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, signature, true); if (id) { res = env->CallStaticObjectMethodV(clazz, id, args); if (env.exceptionCheckAndClear()) { @@ -790,24 +813,25 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz, } /*! - \fn template <typename T> T QJniObject::callMethod(const char *methodName, const char *sig, ...) const + \fn template <typename T> T QJniObject::callMethod(const char *methodName, const char *signature, ...) const - Calls the method \a methodName with a signature \a sig and returns the value. + Calls the object's method \a methodName with \a signature specifying the types of any + subsequent arguments. \code - QJniObject myJavaString = ...; + QJniObject myJavaStrin("org/qtproject/qt/TestClass"); jint index = myJavaString.callMethod<jint>("indexOf", "(I)I", 0x0051); \endcode */ template <> -Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName, const char *sig, ...) const +Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName, const char *signature, ...) const { QJniEnvironment env; - jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, signature); if (id) { va_list args; - va_start(args, sig); + va_start(args, signature); env->CallVoidMethodV(d->m_jobject, id, args); va_end(args); env.exceptionCheckAndClear(); @@ -820,7 +844,7 @@ Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName, const ch Calls the method \a methodName and returns the value. \code - QJniObject myJavaString = ...; + QJniObject myJavaStrin("org/qtproject/qt/TestClass"); jint size = myJavaString.callMethod<jint>("length"); \endcode */ @@ -833,30 +857,29 @@ Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName) const /*! \fn template <typename T> T QJniObject::callStaticMethod(const char *className, const char *methodName, const char *signature, ...) - Calls the static method with \a methodName with \a signature on class \a className with optional arguments. + Calls the static method \a methodName from class \a className with \a signature + specifying the types of any subsequent arguments. \code - ... jint a = 2; jint b = 4; jint max = QJniObject::callStaticMethod<jint>("java/lang/Math", "max", "(II)I", a, b); - ... \endcode */ template <> Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(const char *className, const char *methodName, - const char *sig, + const char *signature, ...) { QJniEnvironment env; jclass clazz = loadClass(className, env); if (clazz) { jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), - methodName, sig, true); + methodName, signature, true); if (id) { va_list args; - va_start(args, sig); + va_start(args, signature); env->CallStaticVoidMethodV(clazz, id, args); va_end(args); env.exceptionCheckAndClear(); @@ -882,29 +905,29 @@ Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(const char *className, con /*! \fn template <typename T> T QJniObject::callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...) - Calls the static method \a methodName with \a signature on \a clazz and returns the value. + Calls the static method \a methodName from \a clazz with \a signature + specifying the types of any subsequent arguments. \code - ... - jclass javaMathClass = ...; // ("java/lang/Math") + QJniEnvironment env; + jclass javaMathClass = env.findClass("java/lang/Math"); jint a = 2; jint b = 4; jint max = QJniObject::callStaticMethod<jint>(javaMathClass, "max", "(II)I", a, b); - ... \endcode */ template <> Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(jclass clazz, const char *methodName, - const char *sig, + const char *signature, ...) { QJniEnvironment env; if (clazz) { - jmethodID id = getMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, signature, true); if (id) { va_list args; - va_start(args, sig); + va_start(args, signature); env->CallStaticVoidMethodV(clazz, id, args); va_end(args); env.exceptionCheckAndClear(); @@ -915,7 +938,7 @@ Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(jclass clazz, template <> Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(const char *className, const char *methodName, - const char *sig, + const char *signature, va_list args) { QJniEnvironment env; @@ -923,7 +946,7 @@ Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(const char *className, if (clazz) { jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, - sig, true); + signature, true); if (id) { env->CallStaticVoidMethodV(clazz, id, args); env.exceptionCheckAndClear(); @@ -934,11 +957,11 @@ Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(const char *className, template <> Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(jclass clazz, const char *methodName, - const char *sig, + const char *signature, va_list args) { QJniEnvironment env; - jmethodID id = getMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, signature, true); if (id) { env->CallStaticVoidMethodV(clazz, id, args); env.exceptionCheckAndClear(); @@ -951,10 +974,9 @@ Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(jclass clazz, Calls the static method \a methodName on \a clazz and returns the value. \code - ... - jclass javaMathClass = ...; // ("java/lang/Math") + QJniEnvironment env; + jclass javaMathClass = env.findClass("java/lang/Math"); jdouble randNr = QJniObject::callStaticMethod<jdouble>(javaMathClass, "random"); - ... \endcode */ template <> @@ -964,11 +986,11 @@ Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(jclass clazz, const char * } template <> -Q_CORE_EXPORT void QJniObject::callMethodV<void>(const char *methodName, const char *sig, +Q_CORE_EXPORT void QJniObject::callMethodV<void>(const char *methodName, const char *signature, va_list args) const { QJniEnvironment env; - jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, signature); if (id) { env->CallVoidMethodV(d->m_jobject, id, args); env.exceptionCheckAndClear(); @@ -977,14 +999,14 @@ Q_CORE_EXPORT void QJniObject::callMethodV<void>(const char *methodName, const c #define MAKE_JNI_METHODS(MethodName, Type, Signature) \ template <> Q_CORE_EXPORT Type QJniObject::callMethod<Type>(const char *methodName, \ - const char *sig, ...) const \ + const char *signature, ...) const \ { \ QJniEnvironment env; \ Type res = 0; \ - jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); \ + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, signature); \ if (id) { \ va_list args; \ - va_start(args, sig); \ + va_start(args, signature); \ res = env->Call##MethodName##MethodV(d->m_jobject, id, args); \ va_end(args); \ if (env.exceptionCheckAndClear()) \ @@ -999,7 +1021,7 @@ template <> Q_CORE_EXPORT Type QJniObject::callMethod<Type>(const char *methodNa \ template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(const char *className, \ const char *methodName, \ - const char *sig, \ + const char *signature, \ ...) \ { \ QJniEnvironment env; \ @@ -1007,10 +1029,10 @@ template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(const char *cl jclass clazz = loadClass(className, env); \ if (clazz) { \ jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, \ - sig, true); \ + signature, true); \ if (id) { \ va_list args; \ - va_start(args, sig); \ + va_start(args, signature); \ res = env->CallStatic##MethodName##MethodV(clazz, id, args); \ va_end(args); \ if (env.exceptionCheckAndClear()) \ @@ -1027,16 +1049,16 @@ template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(const char *cl \ template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(jclass clazz, \ const char *methodName, \ - const char *sig, \ + const char *signature, \ ...) \ { \ QJniEnvironment env; \ Type res = 0; \ if (clazz) { \ - jmethodID id = getMethodID(env, clazz, methodName, sig, true); \ + jmethodID id = getMethodID(env, clazz, methodName, signature, true); \ if (id) { \ va_list args; \ - va_start(args, sig); \ + va_start(args, signature); \ res = env->CallStatic##MethodName##MethodV(clazz, id, args); \ va_end(args); \ if (env.exceptionCheckAndClear()) \ @@ -1051,12 +1073,12 @@ template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(jclass clazz, return callStaticMethod<Type>(clazz, methodName, Signature); \ }\ template <> \ -Q_CORE_EXPORT Type QJniObject::callMethodV<Type>(const char *methodName, const char *sig,\ +Q_CORE_EXPORT Type QJniObject::callMethodV<Type>(const char *methodName, const char *signature,\ va_list args) const\ {\ QJniEnvironment env;\ Type res = 0;\ - jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig);\ + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, signature);\ if (id) {\ res = env->Call##MethodName##MethodV(d->m_jobject, id, args);\ if (env.exceptionCheckAndClear()) \ @@ -1066,16 +1088,16 @@ Q_CORE_EXPORT Type QJniObject::callMethodV<Type>(const char *methodName, const c }\ template <>\ Q_CORE_EXPORT Type QJniObject::callStaticMethodV<Type>(const char *className,\ - const char *methodName,\ - const char *sig,\ - va_list args)\ + const char *methodName,\ + const char *signature,\ + va_list args)\ {\ QJniEnvironment env;\ Type res = 0;\ jclass clazz = loadClass(className, env);\ if (clazz) {\ jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName,\ - sig, true);\ + signature, true);\ if (id) {\ res = env->CallStatic##MethodName##MethodV(clazz, id, args);\ if (env.exceptionCheckAndClear()) \ @@ -1086,13 +1108,13 @@ Q_CORE_EXPORT Type QJniObject::callStaticMethodV<Type>(const char *className,\ }\ template <>\ Q_CORE_EXPORT Type QJniObject::callStaticMethodV<Type>(jclass clazz,\ - const char *methodName,\ - const char *sig,\ - va_list args)\ + const char *methodName,\ + const char *signature,\ + va_list args)\ {\ QJniEnvironment env;\ Type res = 0;\ - jmethodID id = getMethodID(env, clazz, methodName, sig, true);\ + jmethodID id = getMethodID(env, clazz, methodName, signature, true);\ if (id) {\ res = env->CallStatic##MethodName##MethodV(clazz, id, args);\ if (env.exceptionCheckAndClear()) \ @@ -1116,21 +1138,23 @@ DECLARE_JNI_METHODS(Double, jdouble, "()D") /*! \fn QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const - Calls the Java object's method \a methodName with the signature \a signature and arguments + Calls the Java object's method \a methodName with \a signature specifying + the types of any subsequent arguments. \code - QJniObject myJavaString; ==> "Hello, Java" - QJniObject mySubstring = myJavaString.callObjectMethod("substring", "(II)Ljava/lang/String;", 7, 10); + QJniObject myJavaString = QJniObject::fromString("Hello, Java"); + QJniObject mySubstring = myJavaString.callObjectMethod("substring", + "(II)Ljava/lang/String;", 7, 11); \endcode */ -QJniObject QJniObject::callObjectMethod(const char *methodName, const char *sig, ...) const +QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const { QJniEnvironment env; jobject res = nullptr; - jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, signature); if (id) { va_list args; - va_start(args, sig); + va_start(args, signature); res = env->CallObjectMethodV(d->m_jobject, id, args); va_end(args); if (env.exceptionCheckAndClear()) { @@ -1147,27 +1171,30 @@ QJniObject QJniObject::callObjectMethod(const char *methodName, const char *sig, /*! \fn QJniObject QJniObject::callStaticObjectMethod(const char *className, const char *methodName, const char *signature, ...) - Calls the static method with \a methodName and \a signature on the class \a className. + Calls the static method \a methodName from the class \a className with \a signature + specifying the types of any subsequent arguments. \code - QJniObject thread = QJniObject::callStaticObjectMethod("java/lang/Thread", "currentThread", "()Ljava/lang/Thread;"); - QJniObject string = QJniObject::callStaticObjectMethod("java/lang/String", "valueOf", "(I)Ljava/lang/String;", 10); + QJniObject thread = QJniObject::callStaticObjectMethod("java/lang/Thread", "currentThread", + "()Ljava/lang/Thread;"); + QJniObject string = QJniObject::callStaticObjectMethod("java/lang/String", "valueOf", + "(I)Ljava/lang/String;", 10); \endcode */ QJniObject QJniObject::callStaticObjectMethod(const char *className, const char *methodName, - const char *sig, + const char *signature, ...) { QJniEnvironment env; jobject res = nullptr; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, - sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), + methodName, signature, true); if (id) { va_list args; - va_start(args, sig); + va_start(args, signature); res = env->CallStaticObjectMethodV(clazz, id, args); va_end(args); if (env.exceptionCheckAndClear()) { @@ -1185,20 +1212,21 @@ QJniObject QJniObject::callStaticObjectMethod(const char *className, /*! \fn QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodName, const char *signature, ...) - Calls the static method with \a methodName and \a signature on class \a clazz. + Calls the static method \a methodName from class \a clazz with \a signature + specifying the types of any subsequent arguments. */ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodName, - const char *sig, + const char *signature, ...) { QJniEnvironment env; jobject res = nullptr; if (clazz) { - jmethodID id = getMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, signature, true); if (id) { va_list args; - va_start(args, sig); + va_start(args, signature); res = env->CallStaticObjectMethodV(clazz, id, args); va_end(args); if (env.exceptionCheckAndClear()) { @@ -1219,10 +1247,8 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, the returned Java object. \code - ... - QJniObject myJavaString1 = ...; + QJniObject myJavaString = QJniObject::fromString("Hello, Java"); QJniObject myJavaString2 = myJavaString1.callObjectMethod<jstring>("toString"); - ... \endcode */ @@ -1244,6 +1270,26 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, */ /*! + \fn template <typename T> T QJniObject::object() const + + Returns the object held by the QJniObject as type T. + T can be one of \l {Object Types}{JNI Object Types}. + + \code + QJniObject string = QJniObject::fromString("Hello, JNI"); + jstring jstring = string.object<jstring>(); + \endcode + + \note The returned object is still kept live by this QJniObject. To keep the + object live beyond the lifetime of this QJniObject, for example to record it + for later use, the easiest approach is to store it in another QJniObject with + a suitable lifetime. Alternatively, you can make a new global reference to the + object and store it, taking care to free it when you are done with it. + + \snippet jni/src_qjniobject.cpp QJniObject scope +*/ + +/*! \fn template <typename T> QJniObject &QJniObject::operator=(T object) Replace the current object with \a object. The old Java object will be released. @@ -1297,12 +1343,14 @@ DECLARE_JNI_OBJECT_METHODS(jthrowable, "()Ljava/lang/Throwable;") /*! \fn template <typename T> void QJniObject::setStaticField(const char *className, const char *fieldName, const char *signature, T value); - Sets the static field with \a fieldName and \a signature to \a value on class named \a className. + Sets the static field \a fieldName on the class \a className to \a value + using the setter with \a signature. + */ template <> Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(const char *className, const char *fieldName, - const char *sig, + const char *signature, jobject value) { QJniEnvironment env; @@ -1311,7 +1359,7 @@ Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(const char *className, if (!clazz) return; - jfieldID id = getCachedFieldID(env, clazz, className, fieldName, sig, true); + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, signature, true); if (id) { env->SetStaticObjectField(clazz, id, value); env.exceptionCheckAndClear(); @@ -1321,15 +1369,16 @@ Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(const char *className, /*! \fn template <typename T> void QJniObject::setStaticField(jclass clazz, const char *fieldName, const char *signature, T value); - Sets the static field with \a fieldName and \a signature to \a value on class \a clazz. + Sets the static field \a fieldName on the class \a clazz to \a value using + the setter with \a signature. */ template <> Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(jclass clazz, const char *fieldName, - const char *sig, + const char *signature, jobject value) { QJniEnvironment env; - jfieldID id = getFieldID(env, clazz, fieldName, sig, true); + jfieldID id = getFieldID(env, clazz, fieldName, signature, true); if (id) { env->SetStaticObjectField(clazz, id, value); @@ -1343,8 +1392,8 @@ template <> Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(jclass clazz, Retrieves the value of the field \a fieldName. \code - QJniObject volumeControl = ...; - jint fieldValue = volumeControl.getField<jint>("MAX_VOLUME"); + QJniObject volumeControl("org/qtproject/qt/TestClass"); + jint fieldValue = volumeControl.getField<jint>("FIELD_NAME"); \endcode */ @@ -1363,7 +1412,7 @@ template <> Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(jclass clazz, /*! \fn template <typename T> void QJniObject::setStaticField(const char *className, const char *fieldName, T value) - Sets the static field \a fieldName of the class named \a className to \a value. + Sets the static field \a fieldName of the class \a className to \a value. */ /*! @@ -1461,24 +1510,27 @@ DECLARE_JNI_PRIMITIVE_FIELDS(Double, jdouble, "D") /*! \fn QJniObject QJniObject::getStaticObjectField(const char *className, const char *fieldName, const char *signature) - Retrieves the object from the field with \a signature and \a fieldName on class \a className. + + Retrieves a JNI object from the field \a filedName with \a signature from + class \a className. \note This function can be used without a template type. \code - QJniObject jobj = QJniObject::getStaticObjectField("class/with/Fields", "FIELD_NAME", "Ljava/lang/String;"); + QJniObject jobj = QJniObject::getStaticObjectField("class/with/Fields", "FIELD_NAME", + "Ljava/lang/String;"); \endcode */ QJniObject QJniObject::getStaticObjectField(const char *className, const char *fieldName, - const char *sig) + const char *signature) { QJniEnvironment env; jclass clazz = loadClass(className, env); if (!clazz) return QJniObject(); jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, - sig, true); + signature, true); if (!id) return QJniObject(); @@ -1495,7 +1547,9 @@ QJniObject QJniObject::getStaticObjectField(const char *className, /*! \fn QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName, const char *signature) - Retrieves the object from the field with \a signature and \a fieldName on \a clazz. + + Retrieves a JNI object from the field \a fieldName with \a signature from + class \a clazz. \note This function can be used without a template type. @@ -1505,11 +1559,11 @@ QJniObject QJniObject::getStaticObjectField(const char *className, */ QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName, - const char *sig) + const char *signature) { QJniEnvironment env; jobject res = nullptr; - jfieldID id = getFieldID(env, clazz, fieldName, sig, true); + jfieldID id = getFieldID(env, clazz, fieldName, signature, true); if (id) { res = env->GetStaticObjectField(clazz, id); if (env.exceptionCheckAndClear()) { @@ -1526,53 +1580,57 @@ QJniObject QJniObject::getStaticObjectField(jclass clazz, /*! \fn QJniObject QJniObject::getStaticObjectField<jobject>(jclass clazz, const char *fieldName, const char *signature) - Retrieves the \a jobject from the field with \a signature and \a fieldName on \a clazz. + Retrieves a JNI object for \c jobject from the static field \a fieldName with + \a signature from \a clazz. */ template <> Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobject>(jclass clazz, const char *fieldName, - const char *sig) + const char *signature) { - return getStaticObjectField(clazz, fieldName, sig); + return getStaticObjectField(clazz, fieldName, signature); } /*! - \fn QJniObject QJniObject::getStaticObjectField<jobject>(jclass clazz, const char *fieldName, const char *signature) + \fn QJniObject QJniObject::getStaticObjectField<jobject>(const char *className, const char *fieldName, const char *signature) - Retrieves the jobject from the field with \a signature and \a fieldName on class named \a className. + Retrieves a JNI object for \c jobject from the static field \a fieldName with + \a signature from class \a className. */ template <> Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobject>(const char *className, const char *fieldName, - const char *sig) + const char *signature) { - return getStaticObjectField(className, fieldName, sig); + return getStaticObjectField(className, fieldName, signature); } /*! \fn QJniObject QJniObject::getStaticObjectField<jobjectArray>(jclass clazz, const char *fieldName, const char *signature) - Retrieves the jobjectArray from the field with \a signature and \a fieldName on \a clazz. + Retrieves a JNI object for \c jobjectArray from the static field \a fieldName + with \a signature from class \a clazz. */ template <> Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobjectArray>(jclass clazz, const char *fieldName, - const char *sig) + const char *signature) { - return getStaticObjectField(clazz, fieldName, sig); + return getStaticObjectField(clazz, fieldName, signature); } /*! - \fn QJniObject QJniObject::getStaticObjectField<jobjectArray>(jclass clazz, const char *fieldName, const char *signature) + \fn QJniObject QJniObject::getStaticObjectField<jobjectArray>(const char *className, const char *fieldName, const char *signature) - Retrieves the jobjectArray from the field with \a signature and \a fieldName on the class named \a className. + Retrieves a JNI object for \c jobjectArray from the static field \a fieldName + with \a signature from class \a className. */ template <> Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobjectArray>(const char *className, const char *fieldName, - const char *sig) + const char *signature) { - return getStaticObjectField(className, fieldName, sig); + return getStaticObjectField(className, fieldName, signature); } /*! @@ -1583,14 +1641,15 @@ Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobjectArray>(const ch \code QJniObject stringArray = ...; QJniObject obj = ...; - obj.setField<jobjectArray>("KEY_VALUES", "([Ljava/lang/String;)V", stringArray.object<jobjectArray>()) + obj.setField<jobjectArray>("KEY_VALUES", "([Ljava/lang/String;)V", + stringArray.object<jobjectArray>()) \endcode */ template <> Q_CORE_EXPORT -void QJniObject::setField<jobject>(const char *fieldName, const char *sig, jobject value) +void QJniObject::setField<jobject>(const char *fieldName, const char *signature, jobject value) { QJniEnvironment env; - jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, signature); if (id) { env->SetObjectField(d->m_jobject, id, value); env.exceptionCheckAndClear(); @@ -1598,10 +1657,12 @@ void QJniObject::setField<jobject>(const char *fieldName, const char *sig, jobje } template <> Q_CORE_EXPORT -void QJniObject::setField<jobjectArray>(const char *fieldName, const char *sig, jobjectArray value) +void QJniObject::setField<jobjectArray>(const char *fieldName, + const char *signature, + jobjectArray value) { QJniEnvironment env; - jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, signature); if (id) { env->SetObjectField(d->m_jobject, id, value); env.exceptionCheckAndClear(); @@ -1611,7 +1672,7 @@ void QJniObject::setField<jobjectArray>(const char *fieldName, const char *sig, /*! \fn QJniObject QJniObject::getObjectField(const char *fieldName) const - Retrieves the object of field \a fieldName. + Retrieves a JNI object from the field \a fieldName. \code QJniObject field = jniObject.getObjectField<jstring>("FIELD_NAME"); @@ -1621,7 +1682,7 @@ void QJniObject::setField<jobjectArray>(const char *fieldName, const char *sig, /*! \fn QJniObject QJniObject::getObjectField(const char *fieldName, const char *signature) const - Retrieves the object from the field with \a signature and \a fieldName. + Retrieves a JNI object from the field \a fieldName with \a signature. \note This function can be used without a template type. @@ -1629,11 +1690,11 @@ void QJniObject::setField<jobjectArray>(const char *fieldName, const char *sig, QJniObject field = jniObject.getObjectField("FIELD_NAME", "Ljava/lang/String;"); \endcode */ -QJniObject QJniObject::getObjectField(const char *fieldName, const char *sig) const +QJniObject QJniObject::getObjectField(const char *fieldName, const char *signature) const { QJniEnvironment env; jobject res = nullptr; - jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, signature); if (id) { res = env->GetObjectField(d->m_jobject, id); if (env.exceptionCheckAndClear()) { @@ -1653,12 +1714,10 @@ QJniObject QJniObject::getObjectField(const char *fieldName, const char *sig) co Sets the value of \a fieldName to \a value. \code - ... QJniObject obj; obj.setField<jint>("AN_INT_FIELD", 10); - jstring myString = ... + jstring myString = ...; obj.setField<jstring>("A_STRING_FIELD", myString); - ... \endcode */ @@ -1806,9 +1865,9 @@ bool QJniObject::isClassAvailable(const char *className) Returns true if this instance holds a valid Java object. \code - QJniObject qjniObject; ==> isValid() == false - QJniObject qjniObject(0) ==> isValid() == false - QJniObject qjniObject("could/not/find/Class") ==> isValid() == false + QJniObject qjniObject; // ==> isValid() == false + QJniObject qjniObject(0) // ==> isValid() == false + QJniObject qjniObject("could/not/find/Class") // ==> isValid() == false \endcode */ bool QJniObject::isValid() const @@ -1818,7 +1877,6 @@ bool QJniObject::isValid() const /*! \fn QJniObject QJniObject::fromLocalRef(jobject localRef) - \since 6.1 Creates a QJniObject from the local JNI reference \a localRef. This function takes ownership of \a localRef and frees it before returning. diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h index 2998c7b4e8..0f88695e73 100644 --- a/src/corelib/kernel/qjniobject.h +++ b/src/corelib/kernel/qjniobject.h @@ -58,9 +58,9 @@ class Q_CORE_EXPORT QJniObject public: QJniObject(); explicit QJniObject(const char *className); - explicit QJniObject(const char *className, const char *sig, ...); + explicit QJniObject(const char *className, const char *signature, ...); explicit QJniObject(jclass clazz); - explicit QJniObject(jclass clazz, const char *sig, ...); + explicit QJniObject(jclass clazz, const char *signature, ...); QJniObject(jobject globalRef); ~QJniObject(); @@ -69,19 +69,20 @@ public: jobject object() const; template <typename T> - T callMethod(const char *methodName, const char *sig, ...) const; + T callMethod(const char *methodName, const char *signature, ...) const; template <typename T> T callMethod(const char *methodName) const; template <typename T> QJniObject callObjectMethod(const char *methodName) const; - QJniObject callObjectMethod(const char *methodName, const char *sig, ...) const; + QJniObject callObjectMethod(const char *methodName, const char *signature, ...) const; template <typename T> - static T callStaticMethod(const char *className, const char *methodName, const char *sig, ...); + static T callStaticMethod(const char *className, const char *methodName, + const char *signature, ...); template <typename T> static T callStaticMethod(const char *className, const char *methodName); template <typename T> - static T callStaticMethod(jclass clazz, const char *methodName, const char *sig, ...); + static T callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...); template <typename T> static T callStaticMethod(jclass clazz, const char *methodName); @@ -89,13 +90,13 @@ public: static QJniObject callStaticObjectMethod(const char *className, const char *methodName); static QJniObject callStaticObjectMethod(const char *className, const char *methodName, - const char *sig, ...); + const char *signature, ...); template <typename T> static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName); static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName, - const char *sig, ...); + const char *signature, ...); template <typename T> T getField(const char *fieldName) const; @@ -107,35 +108,38 @@ public: template <typename T> QJniObject getObjectField(const char *fieldName) const; - QJniObject getObjectField(const char *fieldName, const char *sig) const; + QJniObject getObjectField(const char *fieldName, const char *signature) const; template <typename T> static QJniObject getStaticObjectField(const char *className, const char *fieldName); static QJniObject getStaticObjectField(const char *className, const char *fieldName, - const char *sig); + const char *signature); template <typename T> static QJniObject getStaticObjectField(const char *className, const char *fieldName, - const char *sig); + const char *signature); template <typename T> static QJniObject getStaticObjectField(jclass clazz, const char *fieldName); - static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, const char *sig); + static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, + const char *signature); template <typename T> - static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, const char *sig); + static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, + const char *signature); template <typename T> void setField(const char *fieldName, T value); template <typename T> - void setField(const char *fieldName, const char *sig, T value); + void setField(const char *fieldName, const char *signature, T value); template <typename T> static void setStaticField(const char *className, const char *fieldName, T value); template <typename T> static void setStaticField(const char *className, const char *fieldName, - const char *sig, T value); + const char *signature, T value); template <typename T> - static void setStaticField(jclass clazz, const char *fieldName, const char *sig, T value); + static void setStaticField(jclass clazz, const char *fieldName, + const char *signature, T value); template <typename T> static void setStaticField(jclass clazz, const char *fieldName, T value); @@ -154,31 +158,33 @@ public: private: struct QVaListPrivate { operator va_list &() const { return m_args; } va_list &m_args; }; - QJniObject(const char *className, const char *sig, const QVaListPrivate &args); - QJniObject(jclass clazz, const char *sig, const QVaListPrivate &args); + QJniObject(const char *className, const char *signature, const QVaListPrivate &args); + QJniObject(jclass clazz, const char *signature, const QVaListPrivate &args); template <typename T> - T callMethodV(const char *methodName, const char *sig, va_list args) const; - QJniObject callObjectMethodV(const char *methodName, const char *sig, va_list args) const; + T callMethodV(const char *methodName, const char *signature, va_list args) const; + QJniObject callObjectMethodV(const char *methodName, + const char *signature, + va_list args) const; template <typename T> static T callStaticMethodV(const char *className, const char *methodName, - const char *sig, + const char *signature, va_list args); template <typename T> static T callStaticMethodV(jclass clazz, const char *methodName, - const char *sig, + const char *signature, va_list args); static QJniObject callStaticObjectMethodV(const char *className, const char *methodName, - const char *sig, + const char *signature, va_list args); static QJniObject callStaticObjectMethodV(jclass clazz, const char *methodName, - const char *sig, + const char *signature, va_list args); bool isSameObject(jobject obj) const; |