summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qjniobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qjniobject.cpp')
-rw-r--r--src/corelib/kernel/qjniobject.cpp1498
1 files changed, 518 insertions, 980 deletions
diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp
index 43840052ae..8244a4390f 100644
--- a/src/corelib/kernel/qjniobject.cpp
+++ b/src/corelib/kernel/qjniobject.cpp
@@ -1,52 +1,22 @@
-/****************************************************************************
-**
-** 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) 2021 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
#include "qjniobject.h"
-#include "qjnienvironment.h"
#include "qjnihelpers_p.h"
-#include <QtCore/QReadWriteLock>
-#include <QtCore/QHash>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qreadwritelock.h>
+#include <QtCore/qloggingcategory.h>
+
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcJniThreadCheck, "qt.core.jni.threadcheck")
+
+using namespace Qt::StringLiterals;
+
/*!
\class QJniObject
\inmodule QtCore
@@ -54,7 +24,7 @@ QT_BEGIN_NAMESPACE
\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
+ garbage-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.
@@ -74,55 +44,77 @@ QT_BEGIN_NAMESPACE
\section1 Method Signatures
- For functions that take no arguments, QJniObject provides convenience functions that will use
- the correct signature based on the provided template type. For example:
+ QJniObject provides convenience functions that will use the correct signature based on the
+ provided template types. For functions that only return and take \l {JNI types}, the
+ signature can be generate at compile time:
\code
jint x = QJniObject::callMethod<jint>("getSize");
QJniObject::callMethod<void>("touch");
+ jint ret = jString1.callMethod<jint>("compareToIgnoreCase", jString2.object<jstring>());
\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
- \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.
+ These functions are variadic templates, and the compiler will deduce the template arguments
+ from the actual argument types. In many situations, only the return type needs to be provided
+ explicitly.
- The example below demonstrates how to call two different static functions:
+ For functions that take other argument types, you need to supply the signature yourself. It is
+ important that the signature matches the function you want to call. The example below
+ demonstrates how to call different static functions:
\code
// Java class
package org.qtproject.qt;
class TestClass
{
- static String fromNumber(int x) { ... }
- static String[] stringArray(String s1, String s2) { ... }
+ static TestClass create() { ... }
+ static String fromNumber(int x) { ... }
+ static String[] stringArray(String s1, String s2) { ... }
}
\endcode
- The signature for the first function is \c {"(I)Ljava/lang/String;"}:
+ 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 signature for the \c create function is
+ \c {"()Lorg/qtproject/qt/TestClass;}. The signatures for the second and third functions
+ are \c {"(I)Ljava/lang/String;"} and
+ \c {"(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"}, respectively.
+
+ We can call the \c create() function like this:
+
+ \code
+ // C++ code
+ QJniObject testClass = QJniObject::callStaticObjectMethod("org/qtproject/qt/TestClass",
+ "create",
+ "()Lorg/qtproject/qt/TestClass;");
+ \endcode
+
+ For the second and third function we can rely on QJniObject's template methods to create
+ the implicit signature string, but we can also pass the signature string explicitly:
\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
- \c {"(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"}:
+ For the implicit signature creation to work we need to specify the return type explicitly:
\code
// C++ code
QJniObject string1 = QJniObject::fromString("String1");
QJniObject string2 = QJniObject::fromString("String2");
- QJniObject stringArray = QJniObject::callStaticObjectMethod("org/qtproject/qt/TestClass",
+ QJniObject stringArray = QJniObject::callStaticObjectMethod<jstringArray>(
+ "org/qtproject/qt/TestClass",
"stringArray"
- "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"
string1.object<jstring>(),
string2.object<jstring>());
\endcode
+ Note that while the first template parameter specifies the return type of the Java
+ function, the method will still return a QJniObject.
+
\section1 Handling Java Exception
After calling Java functions that might throw exceptions, it is important
@@ -132,7 +124,7 @@ QT_BEGIN_NAMESPACE
\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().
+ QJniEnvironment::checkAndClearExceptions().
\section1 Java Native Methods
@@ -160,7 +152,7 @@ QT_BEGIN_NAMESPACE
\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 {Java: AttachCurrentThread}{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
@@ -286,106 +278,192 @@ QT_BEGIN_NAMESPACE
Returns true if \a o1 holds a reference to a different object than \a o2.
*/
-static inline QLatin1String keyBase()
+class QJniObjectPrivate
{
- return QLatin1String("%1%2:%3");
-}
+public:
+ QJniObjectPrivate()
+ {
+ }
+ ~QJniObjectPrivate() {
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ if (m_jobject)
+ env->DeleteGlobalRef(m_jobject);
+ if (m_jclass && m_own_jclass)
+ env->DeleteGlobalRef(m_jclass);
+ }
-static QString qt_convertJString(jstring string)
+ template <typename ...Args>
+ void construct(const char *signature = nullptr, Args &&...args)
+ {
+ if (m_jclass) {
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ // get default constructor
+ jmethodID constructorId = QJniObject::getCachedMethodID(env, m_jclass, m_className, "<init>",
+ signature ? signature : "()V");
+ if (constructorId) {
+ jobject obj = nullptr;
+ if constexpr (sizeof...(Args) == 0)
+ obj = env->NewObject(m_jclass, constructorId);
+ else
+ obj = env->NewObjectV(m_jclass, constructorId, std::forward<Args>(args)...);
+ if (obj) {
+ m_jobject = env->NewGlobalRef(obj);
+ env->DeleteLocalRef(obj);
+ }
+ }
+ }
+ }
+
+ QByteArray m_className;
+ jobject m_jobject = nullptr;
+ jclass m_jclass = nullptr;
+ bool m_own_jclass = true;
+};
+
+template <typename ...Args>
+static inline QByteArray cacheKey(Args &&...args)
{
- QJniEnvironment env;
- int strLength = env->GetStringLength(string);
- QString res(strLength, Qt::Uninitialized);
- env->GetStringRegion(string, 0, strLength, reinterpret_cast<jchar *>(res.data()));
- return res;
+ return (QByteArrayView(":") + ... + QByteArrayView(args));
}
-typedef QHash<QString, jclass> JClassHash;
+typedef QHash<QByteArray, jclass> JClassHash;
Q_GLOBAL_STATIC(JClassHash, cachedClasses)
Q_GLOBAL_STATIC(QReadWriteLock, cachedClassesLock)
-static QByteArray toBinaryEncClassName(const QByteArray &className)
+static jclass getCachedClass(const QByteArray &className)
{
- return QByteArray(className).replace('/', '.');
+ QReadLocker locker(cachedClassesLock);
+ const auto &it = cachedClasses->constFind(className);
+ return it != cachedClasses->constEnd() ? it.value() : nullptr;
}
-static jclass getCachedClass(const QByteArray &classBinEnc, bool *isCached = nullptr)
-{
- QReadLocker locker(cachedClassesLock);
- const QHash<QString, jclass>::const_iterator &it = cachedClasses->constFind(QString::fromLatin1(classBinEnc));
- const bool found = (it != cachedClasses->constEnd());
+/*!
+ \internal
- if (isCached)
- *isCached = found;
+ Get a JNI object from a jobject variant and do the necessary
+ exception clearing and delete the local reference before returning.
+ The JNI object can be null if there was an exception.
+*/
+static QJniObject getCleanJniObject(jobject object, JNIEnv *env)
+{
+ if (QJniEnvironment::checkAndClearExceptions(env) || !object) {
+ if (object)
+ env->DeleteLocalRef(object);
+ return QJniObject();
+ }
- return found ? it.value() : 0;
+ QJniObject res(object);
+ env->DeleteLocalRef(object);
+ return res;
}
-inline static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded = false)
+/*!
+ \internal
+ \a className must be slash-encoded
+*/
+jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env)
{
- const QByteArray &binEncClassName = binEncoded ? className : toBinaryEncClassName(className);
-
- bool isCached = false;
- jclass clazz = getCachedClass(binEncClassName, &isCached);
- if (clazz || isCached)
+ Q_ASSERT(env);
+ QByteArray classNameArray(className);
+#ifdef QT_DEBUG
+ if (classNameArray.contains('.')) {
+ qWarning("QtAndroidPrivate::findClass: className '%s' should use slash separators!",
+ className);
+ }
+#endif
+ classNameArray.replace('.', '/');
+ jclass clazz = getCachedClass(classNameArray);
+ if (clazz)
return clazz;
- QJniObject classLoader(QtAndroidPrivate::classLoader());
- if (!classLoader.isValid())
- return nullptr;
-
QWriteLocker locker(cachedClassesLock);
- // did we lose the race?
- const QLatin1String key(binEncClassName);
- const QHash<QString, jclass>::const_iterator &it = cachedClasses->constFind(key);
+ // Check again; another thread might have added the class to the cache after
+ // our call to getCachedClass and before we acquired the lock.
+ const auto &it = cachedClasses->constFind(classNameArray);
if (it != cachedClasses->constEnd())
return it.value();
- QJniObject stringName = QJniObject::fromString(key);
- QJniObject classObject = classLoader.callObjectMethod("loadClass",
- "(Ljava/lang/String;)Ljava/lang/Class;",
- stringName.object());
+ // JNIEnv::FindClass wants "a fully-qualified class name or an array type signature"
+ // which is a slash-separated class name.
+ jclass localClazz = env->FindClass(classNameArray.constData());
+ if (localClazz) {
+ clazz = static_cast<jclass>(env->NewGlobalRef(localClazz));
+ env->DeleteLocalRef(localClazz);
+ } else {
+ // Clear the exception silently; we are going to try the ClassLoader next,
+ // so no need for warning unless that fails as well.
+ env->ExceptionClear();
+ }
- if (!QJniEnvironment::exceptionCheckAndClear(env) && classObject.isValid())
- clazz = static_cast<jclass>(env->NewGlobalRef(classObject.object()));
+ if (!clazz) {
+ // Wrong class loader, try our own
+ QJniObject classLoader(QtAndroidPrivate::classLoader());
+ if (!classLoader.isValid())
+ return nullptr;
+
+ // ClassLoader::loadClass on the other hand wants the binary name of the class,
+ // e.g. dot-separated. In testing it works also with /, but better to stick to
+ // the specification.
+ const QString binaryClassName = QString::fromLatin1(className).replace(u'/', u'.');
+ jstring classNameObject = env->NewString(reinterpret_cast<const jchar*>(binaryClassName.constData()),
+ binaryClassName.length());
+ QJniObject classObject = classLoader.callMethod<jclass>("loadClass", classNameObject);
+ env->DeleteLocalRef(classNameObject);
+
+ if (!QJniEnvironment::checkAndClearExceptions(env) && classObject.isValid())
+ clazz = static_cast<jclass>(env->NewGlobalRef(classObject.object()));
+ }
+
+ if (clazz)
+ cachedClasses->insert(classNameArray, clazz);
- cachedClasses->insert(key, clazz);
return clazz;
}
-typedef QHash<QString, jmethodID> JMethodIDHash;
+jclass QJniObject::loadClass(const QByteArray &className, JNIEnv *env)
+{
+ return QtAndroidPrivate::findClass(className, env);
+}
+
+typedef QHash<QByteArray, jmethodID> JMethodIDHash;
Q_GLOBAL_STATIC(JMethodIDHash, cachedMethodID)
Q_GLOBAL_STATIC(QReadWriteLock, cachedMethodIDLock)
-static inline jmethodID getMethodID(JNIEnv *env,
+jmethodID QJniObject::getMethodID(JNIEnv *env,
jclass clazz,
const char *name,
const char *signature,
- bool isStatic = false)
+ bool isStatic)
{
jmethodID id = isStatic ? env->GetStaticMethodID(clazz, name, signature)
: env->GetMethodID(clazz, name, signature);
- if (QJniEnvironment::exceptionCheckAndClear(env))
+ if (QJniEnvironment::checkAndClearExceptions(env))
return nullptr;
return id;
}
-static jmethodID getCachedMethodID(JNIEnv *env,
- jclass clazz,
- const QByteArray &className,
- const char *name,
- const char *signature,
- bool isStatic = false)
+void QJniObject::callVoidMethodV(JNIEnv *env, jmethodID id, ...) const
+{
+ va_list args;
+ va_start(args, id);
+ env->CallVoidMethodV(d->m_jobject, id, args);
+ va_end(args);
+}
+
+jmethodID QJniObject::getCachedMethodID(JNIEnv *env,
+ jclass clazz,
+ const QByteArray &className,
+ const char *name,
+ const char *signature,
+ bool isStatic)
{
if (className.isEmpty())
return getMethodID(env, clazz, name, signature, isStatic);
- const QString key = keyBase().arg(QLatin1String(className),
- QLatin1String(name),
- QLatin1String(signature));
- QHash<QString, jmethodID>::const_iterator it;
+ const QByteArray key = cacheKey(className, name, signature);
+ QHash<QByteArray, jmethodID>::const_iterator it;
{
QReadLocker locker(cachedMethodIDLock);
@@ -407,39 +485,43 @@ static jmethodID getCachedMethodID(JNIEnv *env,
}
}
-typedef QHash<QString, jfieldID> JFieldIDHash;
+jmethodID QJniObject::getCachedMethodID(JNIEnv *env, const char *name,
+ const char *signature, bool isStatic) const
+{
+ return QJniObject::getCachedMethodID(env, d->m_jclass, d->m_className, name, signature, isStatic);
+}
+
+typedef QHash<QByteArray, jfieldID> JFieldIDHash;
Q_GLOBAL_STATIC(JFieldIDHash, cachedFieldID)
Q_GLOBAL_STATIC(QReadWriteLock, cachedFieldIDLock)
-static inline jfieldID getFieldID(JNIEnv *env,
- jclass clazz,
- const char *name,
- const char *signature,
- bool isStatic = false)
+jfieldID QJniObject::getFieldID(JNIEnv *env,
+ jclass clazz,
+ const char *name,
+ const char *signature,
+ bool isStatic)
{
jfieldID id = isStatic ? env->GetStaticFieldID(clazz, name, signature)
: env->GetFieldID(clazz, name, signature);
- if (QJniEnvironment::exceptionCheckAndClear(env))
+ if (QJniEnvironment::checkAndClearExceptions(env))
return nullptr;
return id;
}
-static jfieldID getCachedFieldID(JNIEnv *env,
- jclass clazz,
- const QByteArray &className,
- const char *name,
- const char *signature,
- bool isStatic = false)
+jfieldID QJniObject::getCachedFieldID(JNIEnv *env,
+ jclass clazz,
+ const QByteArray &className,
+ const char *name,
+ const char *signature,
+ bool isStatic)
{
if (className.isNull())
return getFieldID(env, clazz, name, signature, isStatic);
- const QString key = keyBase().arg(QLatin1String(className),
- QLatin1String(name),
- QLatin1String(signature));
- QHash<QString, jfieldID>::const_iterator it;
+ const QByteArray key = cacheKey(className, name, signature);
+ QHash<QByteArray, jfieldID>::const_iterator it;
{
QReadLocker locker(cachedFieldIDLock);
@@ -461,59 +543,14 @@ static jfieldID getCachedFieldID(JNIEnv *env,
}
}
-jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env)
+jfieldID QJniObject::getCachedFieldID(JNIEnv *env,
+ const char *name,
+ const char *signature,
+ bool isStatic) const
{
- const QByteArray &classDotEnc = toBinaryEncClassName(className);
- bool isCached = false;
- jclass clazz = getCachedClass(classDotEnc, &isCached);
-
- const bool found = clazz || (!clazz && isCached);
-
- if (found)
- return clazz;
-
- const QLatin1String key(classDotEnc);
- if (env) { // We got an env. pointer (We expect this to be the right env. and call FindClass())
- QWriteLocker locker(cachedClassesLock);
- const QHash<QString, jclass>::const_iterator &it = cachedClasses->constFind(key);
- // Did we lose the race?
- if (it != cachedClasses->constEnd())
- return it.value();
-
- jclass fclazz = env->FindClass(className);
- if (!QJniEnvironment::exceptionCheckAndClear(env)) {
- clazz = static_cast<jclass>(env->NewGlobalRef(fclazz));
- env->DeleteLocalRef(fclazz);
- }
-
- if (clazz)
- cachedClasses->insert(key, clazz);
- }
-
- if (!clazz) // We didn't get an env. pointer or we got one with the WRONG class loader...
- clazz = loadClass(classDotEnc, QJniEnvironment(), true);
-
- return clazz;
+ return QJniObject::getCachedFieldID(env, d->m_jclass, d->m_className, name, signature, isStatic);
}
-class QJniObjectPrivate
-{
-public:
- QJniObjectPrivate() = default;
- ~QJniObjectPrivate() {
- QJniEnvironment env;
- if (m_jobject)
- env->DeleteGlobalRef(m_jobject);
- if (m_jclass && m_own_jclass)
- env->DeleteGlobalRef(m_jclass);
- }
-
- jobject m_jobject = nullptr;
- jclass m_jclass = nullptr;
- bool m_own_jclass = true;
- QByteArray m_className;
-};
-
/*!
\fn QJniObject::QJniObject()
@@ -538,21 +575,11 @@ QJniObject::QJniObject()
QJniObject::QJniObject(const char *className)
: d(new QJniObjectPrivate())
{
- QJniEnvironment env;
- d->m_className = toBinaryEncClassName(className);
- d->m_jclass = loadClass(d->m_className, env, true);
+ d->m_className = className;
+ d->m_jclass = loadClass(d->m_className, jniEnv());
d->m_own_jclass = false;
- if (d->m_jclass) {
- // get default constructor
- jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "<init>", "()V");
- if (constructorId) {
- jobject obj = env->NewObject(d->m_jclass, constructorId);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
+
+ d->construct();
}
/*!
@@ -571,47 +598,33 @@ QJniObject::QJniObject(const char *className)
QJniObject::QJniObject(const char *className, const char *signature, ...)
: d(new QJniObjectPrivate())
{
- QJniEnvironment env;
- d->m_className = toBinaryEncClassName(className);
- d->m_jclass = loadClass(d->m_className, env, true);
+ d->m_className = className;
+ d->m_jclass = loadClass(d->m_className, jniEnv());
d->m_own_jclass = false;
- if (d->m_jclass) {
- jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "<init>", signature);
- if (constructorId) {
- va_list args;
- va_start(args, signature);
- jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
- va_end(args);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
-}
-QJniObject::QJniObject(const char *className, const char *signature, const QVaListPrivate &args)
- : d(new QJniObjectPrivate())
-{
- QJniEnvironment env;
- d->m_className = toBinaryEncClassName(className);
- 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>", signature);
- if (constructorId) {
- jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
+ va_list args;
+ va_start(args, signature);
+ d->construct(signature, args);
+ va_end(args);
}
/*!
- \fn QJniObject::QJniObject(jclass clazz, const char *signature, ...)
+ \fn template<typename ...Args> QJniObject::QJniObject(const char *className, Args &&...args)
+ \since 6.4
+ Constructs a new JNI object by calling the constructor of \a className with
+ the arguments \a args. This constructor is only available if all \a args are
+ known \l {JNI Types}.
+
+ \code
+ QJniEnvironment env;
+ char* str = "Hello";
+ jstring myJStringArg = env->NewStringUTF(str);
+ QJniObject myNewJavaString("java/lang/String", myJStringArg);
+ \endcode
+*/
+
+/*!
Constructs a new JNI object from \a clazz by calling the constructor with
\a signature specifying the types of any subsequent arguments.
@@ -624,28 +637,31 @@ QJniObject::QJniObject(const char *className, const char *signature, const QVaLi
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>", signature);
- if (constructorId) {
- va_list args;
- va_start(args, signature);
- jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
- va_end(args);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
+ d->m_jclass = static_cast<jclass>(jniEnv()->NewGlobalRef(clazz));
+ va_list args;
+ va_start(args, signature);
+ d->construct(signature, args);
+ va_end(args);
}
}
/*!
- \fn QJniObject::QJniObject(jclass clazz)
+ \fn template<typename ...Args> QJniObject::QJniObject(jclass clazz, Args &&...args)
+ \since 6.4
+ Constructs a new JNI object from \a clazz by calling the constructor with
+ the arguments \a args. This constructor is only available if all \a args are
+ known \l {JNI Types}.
+
+ \code
+ QJniEnvironment env;
+ jclass myClazz = env.findClass("org/qtproject/qt/TestClass");
+ QJniObject(myClazz, 3);
+ \endcode
+*/
+
+/*!
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
@@ -654,45 +670,11 @@ QJniObject::QJniObject(jclass clazz, const char *signature, ...)
*/
QJniObject::QJniObject(jclass clazz)
- : d(new QJniObjectPrivate())
+ : QJniObject(clazz, "()V")
{
- QJniEnvironment env;
- d->m_jclass = static_cast<jclass>(env->NewGlobalRef(clazz));
- if (d->m_jclass) {
- // get default constructor
- jmethodID constructorId = getMethodID(env, d->m_jclass, "<init>", "()V");
- if (constructorId) {
- jobject obj = env->NewObject(d->m_jclass, constructorId);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
-}
-
-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>", signature);
- if (constructorId) {
- jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
- }
}
/*!
- \fn QJniObject::QJniObject(jobject 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
@@ -704,39 +686,33 @@ QJniObject::QJniObject(jclass clazz, const char *signature, const QVaListPrivate
\sa fromLocalRef()
*/
-QJniObject::QJniObject(jobject obj)
+QJniObject::QJniObject(jobject object)
: d(new QJniObjectPrivate())
{
- if (!obj)
+ if (!object)
return;
- QJniEnvironment env;
- d->m_jobject = env->NewGlobalRef(obj);
- jclass cls = env->GetObjectClass(obj);
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ d->m_jobject = env->NewGlobalRef(object);
+ jclass cls = env->GetObjectClass(object);
d->m_jclass = static_cast<jclass>(env->NewGlobalRef(cls));
env->DeleteLocalRef(cls);
}
/*!
- \brief Get a JNI object from a jobject variant and do the necessary
- exception clearing and delete the local reference before returning.
- The JNI object can be null if there was an exception.
-*/
-inline static QJniObject getCleanJniObject(jobject obj)
-{
- if (!obj)
- return QJniObject();
+ \fn template<typename Class, typename ...Args> static inline QJniObject QJniObject::construct(Args &&...args)
+ \since 6.4
- QJniEnvironment env;
- if (env.exceptionCheckAndClear()) {
- env->DeleteLocalRef(obj);
- return QJniObject();
- }
+ Constructs an instance of the Java class that is the equivalent of \c Class and
+ returns a QJniObject containing the JNI object. The arguments in \a args are
+ passed to the Java constructor.
- QJniObject res(obj);
- env->DeleteLocalRef(obj);
- return res;
-}
+ \code
+ QJniObject javaString = QJniObject::construct<jstring>();
+ \endcode
+
+ This function is only available if all \a args are known \l {JNI Types}.
+*/
/*!
\fn QJniObject::~QJniObject()
@@ -746,19 +722,51 @@ inline static QJniObject getCleanJniObject(jobject obj)
QJniObject::~QJniObject()
{}
+namespace {
+QByteArray getClassNameHelper(JNIEnv *env, const QJniObjectPrivate *d)
+{
+ if (env->PushLocalFrame(3) != JNI_OK) // JVM out of memory
+ return QByteArray();
+
+ jmethodID mid = env->GetMethodID(d->m_jclass, "getClass", "()Ljava/lang/Class;");
+ jobject classObject = env->CallObjectMethod(d->m_jobject, mid);
+ jclass classObjectClass = env->GetObjectClass(classObject);
+ mid = env->GetMethodID(classObjectClass, "getName", "()Ljava/lang/String;");
+ jstring stringObject = static_cast<jstring>(env->CallObjectMethod(classObject, mid));
+ const jsize length = env->GetStringUTFLength(stringObject);
+ const char* nameString = env->GetStringUTFChars(stringObject, NULL);
+ const QByteArray result = QByteArray::fromRawData(nameString, length).replace('.', '/');
+ env->ReleaseStringUTFChars(stringObject, nameString);
+ env->PopLocalFrame(nullptr);
+ return result;
+}
+}
+
+/*! \internal
+
+ Returns the JNIEnv of the calling thread.
+*/
+JNIEnv *QJniObject::jniEnv() const noexcept
+{
+ return QJniEnvironment::getJniEnv();
+}
+
/*!
\fn jobject QJniObject::object() const
+ \fn template <typename T> T QJniObject::object() const
- Returns the object held by the QJniObject as jobject.
+ Returns the object held by the QJniObject either as jobject or as type T.
+ T can be one of \l {Object Types}{JNI Object Types}.
\code
- jobject object = jniObject.object();
+ 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
+ \note The returned object is still kept alive by this QJniObject. To keep the
+ object alive 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
+ a suitable lifetime. Alternatively, you may create 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
@@ -768,111 +776,78 @@ jobject QJniObject::object() const
return javaObject();
}
-QJniObject QJniObject::callObjectMethodV(const char *methodName,
- const char *signature,
- va_list args) const
-{
- QJniEnvironment env;
- jobject res = nullptr;
- 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()) {
- env->DeleteLocalRef(res);
- res = nullptr;
- }
- }
+/*!
+ \fn jclass QJniObject::objectClass() const
- QJniObject obj(res);
- env->DeleteLocalRef(res);
- return obj;
-}
+ Returns the class object held by the QJniObject as a \c jclass.
-QJniObject QJniObject::callStaticObjectMethodV(const char *className,
- const char *methodName,
- 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, signature, true);
- if (id) {
- res = env->CallStaticObjectMethodV(clazz, id, args);
- if (env.exceptionCheckAndClear()) {
- env->DeleteLocalRef(res);
- res = nullptr;
- }
- }
- }
+ \note The returned object is still kept alive by this QJniObject. To keep the
+ object alive 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 may create a new global reference to the
+ object and store it, taking care to free it when you are done with it.
- QJniObject obj(res);
- env->DeleteLocalRef(res);
- return obj;
+ \since 6.2
+*/
+jclass QJniObject::objectClass() const
+{
+ return d->m_jclass;
}
-QJniObject QJniObject::callStaticObjectMethodV(jclass clazz,
- const char *methodName,
- const char *signature,
- va_list args)
-{
- QJniEnvironment env;
- jmethodID id = getMethodID(env, clazz, methodName, signature, true);
- if (!id)
- return QJniObject();
+/*!
+ \fn QByteArray QJniObject::className() const
- return getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args));
+ Returns the name of the class object held by the QJniObject as a \c QByteArray.
+
+ \since 6.2
+*/
+QByteArray QJniObject::className() const
+{
+ if (d->m_className.isEmpty() && d->m_jclass && d->m_jobject) {
+ JNIEnv *env = jniEnv();
+ d->m_className = getClassNameHelper(env, d.get());
+ }
+ return d->m_className;
}
/*!
- \fn template <typename T> T QJniObject::callMethod(const char *methodName, const char *signature, ...) const
+ \fn template <typename Ret, typename ...Args> auto QJniObject::callMethod(const char *methodName, const char *signature, Args &&...args) const
+ \since 6.4
Calls the object's method \a methodName with \a signature specifying the types of any
- subsequent arguments.
+ subsequent arguments \a args, and returns the value (unless \c Ret is \c void). If \c Ret
+ is a jobject type, then the returned value will be a QJniObject.
\code
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 *signature, ...) const
-{
- QJniEnvironment env;
- jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, signature);
- if (id) {
- va_list args;
- va_start(args, signature);
- env->CallVoidMethodV(d->m_jobject, id, args);
- va_end(args);
- env.exceptionCheckAndClear();
- }
-}
/*!
- \fn template <typename T> T QJniObject::callMethod(const char *methodName) const
+ \fn template <typename Ret, typename ...Args> auto QJniObject::callMethod(const char *methodName, Args &&...args) const
+ \since 6.4
- Calls the method \a methodName and returns the value.
+ Calls the method \a methodName with arguments \a args and returns the value
+ (unless \c Ret is \c void). If \c Ret is a jobject type, then the returned value
+ will be a QJniObject.
\code
QJniObject myJavaStrin("org/qtproject/qt/TestClass");
jint size = myJavaString.callMethod<jint>("length");
\endcode
+
+ The method signature is deduced at compile time from \c Ret and the types of \a args.
*/
-template <>
-Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName) const
-{
- callMethod<void>(methodName, "()V");
-}
/*!
- \fn template <typename T> T QJniObject::callStaticMethod(const char *className, const char *methodName, const char *signature, ...)
+ \fn template <typename Ret, typename ...Args> auto QJniObject::callStaticMethod(const char *className, const char *methodName, const char *signature, Args &&...args)
+ \since 6.4
Calls the static method \a methodName from class \a className with \a signature
- specifying the types of any subsequent arguments.
+ specifying the types of any subsequent arguments \a args. Returns the result of
+ the method (unless \c Ret is \c void). If \c Ret is a jobject type, then the
+ returned value will be a QJniObject.
\code
jint a = 2;
@@ -880,47 +855,29 @@ Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName) const
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 *signature,
- ...)
-{
- QJniEnvironment env;
- jclass clazz = loadClass(className, env);
- if (clazz) {
- jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className),
- methodName, signature, true);
- if (id) {
- va_list args;
- va_start(args, signature);
- env->CallStaticVoidMethodV(clazz, id, args);
- va_end(args);
- env.exceptionCheckAndClear();
- }
- }
-}
/*!
- \fn template <typename T> T QJniObject::callStaticMethod(const char *className, const char *methodName)
+ \fn template <typename Ret, typename ...Args> auto QJniObject::callStaticMethod(const char *className, const char *methodName, Args &&...args)
+ \since 6.4
- Calls the static method \a methodName on class \a className and returns the value.
+ Calls the static method \a methodName on class \a className with arguments \a args,
+ and returns the value of type \c Ret (unless \c Ret is \c void). If \c Ret
+ is a jobject type, then the returned value will be a QJniObject.
\code
jint value = QJniObject::callStaticMethod<jint>("MyClass", "staticMethod");
\endcode
+
+ The method signature is deduced at compile time from \c Ret and the types of \a args.
*/
-template <>
-Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(const char *className, const char *methodName)
-{
- callStaticMethod<void>(className, methodName, "()V");
-}
/*!
- \fn template <typename T> T QJniObject::callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...)
+ \fn template <typename Ret, typename ...Args> auto QJniObject::callStaticMethod(jclass clazz, const char *methodName, const char *signature, Args &&...args)
Calls the static method \a methodName from \a clazz with \a signature
- specifying the types of any subsequent arguments.
+ specifying the types of any subsequent arguments. Returns the result of
+ the method (unless \c Ret is \c void). If \c Ret is a jobject type, then the
+ returned value will be a QJniObject.
\code
QJniEnvironment env;
@@ -930,224 +887,58 @@ Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(const char *className, con
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 *signature,
- ...)
-{
- QJniEnvironment env;
- if (clazz) {
- jmethodID id = getMethodID(env, clazz, methodName, signature, true);
- if (id) {
- va_list args;
- va_start(args, signature);
- env->CallStaticVoidMethodV(clazz, id, args);
- va_end(args);
- env.exceptionCheckAndClear();
- }
- }
-}
-template <>
-Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(const char *className,
- const char *methodName,
- const char *signature,
- va_list args)
-{
- QJniEnvironment env;
- jclass clazz = loadClass(className, env);
- if (clazz) {
- jmethodID id = getCachedMethodID(env, clazz,
- toBinaryEncClassName(className), methodName,
- signature, true);
- if (id) {
- env->CallStaticVoidMethodV(clazz, id, args);
- env.exceptionCheckAndClear();
- }
- }
-}
+/*!
+ \fn template <typename Ret, typename ...Args> auto QJniObject::callStaticMethod(jclass clazz, jmethodID methodId, Args &&...args)
+ \since 6.4
-template <>
-Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(jclass clazz,
- const char *methodName,
- const char *signature,
- va_list args)
-{
+ Calls the static method identified by \a methodId from the class \a clazz
+ with any subsequent arguments, and returns the value of type \c Ret (unless
+ \c Ret is \c void). If \c Ret is a jobject type, then the returned value will
+ be a QJniObject.
+
+ Useful when \a clazz and \a methodId are already cached from previous operations.
+
+ \code
QJniEnvironment env;
- jmethodID id = getMethodID(env, clazz, methodName, signature, true);
- if (id) {
- env->CallStaticVoidMethodV(clazz, id, args);
- env.exceptionCheckAndClear();
+ jclass javaMathClass = env.findClass("java/lang/Math");
+ jmethodID methodId = env.findStaticMethod(javaMathClass, "max", "(II)I");
+ if (methodId != 0) {
+ jint a = 2;
+ jint b = 4;
+ jint max = QJniObject::callStaticMethod<jint>(javaMathClass, methodId, a, b);
}
-}
+ \endcode
+*/
/*!
- \fn template <typename T> T QJniObject::callStaticMethod(jclass clazz, const char *methodName)
+ \fn template <typename Ret, typename ...Args> auto QJniObject::callStaticMethod(jclass clazz, const char *methodName, Args &&...args)
+ \since 6.4
- Calls the static method \a methodName on \a clazz and returns the value.
+ Calls the static method \a methodName on \a clazz and returns the value of type \c Ret
+ (unless \c Ret is \c void). If \c Ret is a jobject type, then the returned value will
+ be a QJniObject.
\code
QJniEnvironment env;
jclass javaMathClass = env.findClass("java/lang/Math");
jdouble randNr = QJniObject::callStaticMethod<jdouble>(javaMathClass, "random");
\endcode
+
+ The method signature is deduced at compile time from \c Ret and the types of \a args.
*/
-template <>
-Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(jclass clazz, const char *methodName)
-{
- callStaticMethod<void>(clazz, methodName, "()V");
-}
-template <>
-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, signature);
- if (id) {
- env->CallVoidMethodV(d->m_jobject, id, args);
- env.exceptionCheckAndClear();
- }
-}
+/*!
+ \fn template <typename Klass, typename Ret, typename ...Args> auto QJniObject::callStaticMethod(const char *methodName, Args &&...args)
+ \since 6.7
-#define MAKE_JNI_METHODS(MethodName, Type, Signature) \
-template <> Q_CORE_EXPORT Type QJniObject::callMethod<Type>(const char *methodName, \
- const char *signature, ...) const \
-{ \
- QJniEnvironment env; \
- Type res = 0; \
- jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, signature); \
- if (id) { \
- va_list args; \
- va_start(args, signature); \
- res = env->Call##MethodName##MethodV(d->m_jobject, id, args); \
- va_end(args); \
- if (env.exceptionCheckAndClear()) \
- res = 0; \
- } \
- return res; \
-}\
-template <> Q_CORE_EXPORT Type QJniObject::callMethod<Type>(const char *methodName) const \
-{ \
- return callMethod<Type>(methodName, Signature); \
-} \
-\
-template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(const char *className, \
- const char *methodName, \
- const char *signature, \
- ...) \
-{ \
- QJniEnvironment env; \
- Type res = 0; \
- jclass clazz = loadClass(className, env); \
- if (clazz) { \
- jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, \
- signature, true); \
- if (id) { \
- va_list args; \
- va_start(args, signature); \
- res = env->CallStatic##MethodName##MethodV(clazz, id, args); \
- va_end(args); \
- if (env.exceptionCheckAndClear()) \
- res = 0; \
- } \
- } \
- return res; \
-} \
-template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(const char *className, \
- const char *methodName) \
-{ \
- return callStaticMethod<Type>(className, methodName, Signature); \
-}\
-\
-template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(jclass clazz, \
- const char *methodName, \
- const char *signature, \
- ...) \
-{ \
- QJniEnvironment env; \
- Type res = 0; \
- if (clazz) { \
- jmethodID id = getMethodID(env, clazz, methodName, signature, true); \
- if (id) { \
- va_list args; \
- va_start(args, signature); \
- res = env->CallStatic##MethodName##MethodV(clazz, id, args); \
- va_end(args); \
- if (env.exceptionCheckAndClear()) \
- res = 0; \
- } \
- } \
- return res; \
-} \
-template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(jclass clazz, \
- const char *methodName) \
-{ \
- return callStaticMethod<Type>(clazz, methodName, Signature); \
-}\
-template <> \
-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, signature);\
- if (id) {\
- res = env->Call##MethodName##MethodV(d->m_jobject, id, args);\
- if (env.exceptionCheckAndClear()) \
- res = 0; \
- }\
- return res;\
-}\
-template <>\
-Q_CORE_EXPORT Type QJniObject::callStaticMethodV<Type>(const char *className,\
- 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,\
- signature, true);\
- if (id) {\
- res = env->CallStatic##MethodName##MethodV(clazz, id, args);\
- if (env.exceptionCheckAndClear()) \
- res = 0; \
- }\
- }\
- return res;\
-}\
-template <>\
-Q_CORE_EXPORT Type QJniObject::callStaticMethodV<Type>(jclass clazz,\
- const char *methodName,\
- const char *signature,\
- va_list args)\
-{\
- QJniEnvironment env;\
- Type res = 0;\
- jmethodID id = getMethodID(env, clazz, methodName, signature, true);\
- if (id) {\
- res = env->CallStatic##MethodName##MethodV(clazz, id, args);\
- if (env.exceptionCheckAndClear()) \
- res = 0; \
- }\
- return res;\
-}
+ Calls the static method \a methodName on the class \c Klass and returns the value of type
+ \c Ret (unless \c Ret is \c void). If \c Ret is a jobject type, then the returned value will
+ be a QJniObject.
-#define DECLARE_JNI_METHODS(MethodName, Type, Signature) MAKE_JNI_METHODS(MethodName, \
- Type, \
- Signature)
-DECLARE_JNI_METHODS(Boolean, jboolean, "()Z")
-DECLARE_JNI_METHODS(Byte, jbyte, "()B")
-DECLARE_JNI_METHODS(Char, jchar, "()C")
-DECLARE_JNI_METHODS(Short, jshort, "()S")
-DECLARE_JNI_METHODS(Int, jint, "()I")
-DECLARE_JNI_METHODS(Long, jlong, "()J")
-DECLARE_JNI_METHODS(Float, jfloat, "()F")
-DECLARE_JNI_METHODS(Double, jdouble, "()D")
+ The method signature is deduced at compile time from \c Ret and the types of \a args.
+ \c Klass needs to be a C++ type with a registered type mapping to a Java type.
+*/
/*!
\fn QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const
@@ -1163,12 +954,11 @@ DECLARE_JNI_METHODS(Double, jdouble, "()D")
*/
QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const
{
- QJniEnvironment env;
- jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, signature);
+ jmethodID id = getCachedMethodID(jniEnv(), methodName, signature);
if (id) {
va_list args;
va_start(args, signature);
- QJniObject res = getCleanJniObject(env->CallObjectMethodV(d->m_jobject, id, args));
+ QJniObject res = getCleanJniObject(jniEnv()->CallObjectMethodV(d->m_jobject, id, args), jniEnv());
va_end(args);
return res;
}
@@ -1189,20 +979,19 @@ QJniObject QJniObject::callObjectMethod(const char *methodName, const char *sign
"(I)Ljava/lang/String;", 10);
\endcode
*/
-QJniObject QJniObject::callStaticObjectMethod(const char *className,
- const char *methodName,
- const char *signature,
- ...)
+QJniObject QJniObject::callStaticObjectMethod(const char *className, const char *methodName,
+ const char *signature, ...)
{
- QJniEnvironment env;
- jclass clazz = loadClass(className, env);
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jclass clazz = QJniObject::loadClass(className, env);
if (clazz) {
- jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className),
+ jmethodID id = QJniObject::getCachedMethodID(env, clazz,
+ className,
methodName, signature, true);
if (id) {
va_list args;
va_start(args, signature);
- QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args));
+ QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args), env);
va_end(args);
return res;
}
@@ -1217,18 +1006,16 @@ QJniObject QJniObject::callStaticObjectMethod(const char *className,
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 *signature,
- ...)
+QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodName,
+ const char *signature, ...)
{
- QJniEnvironment env;
if (clazz) {
- jmethodID id = getMethodID(env, clazz, methodName, signature, true);
+ QJniEnvironment env;
+ jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true);
if (id) {
va_list args;
va_start(args, signature);
- QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args));
+ QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args), env.jniEnv());
va_end(args);
return res;
}
@@ -1238,104 +1025,76 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz,
}
/*!
- \fn QJniObject QJniObject::callObjectMethod(const char *methodName) const
+ \fn QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId, ...)
- Calls the Java objects method \a methodName and returns a new QJniObject for
- the returned Java object.
+ Calls the static method identified by \a methodId from the class \a clazz
+ with any subsequent arguments. Useful when \a clazz and \a methodId are
+ already cached from previous operations.
\code
- QJniObject myJavaString = QJniObject::fromString("Hello, Java");
- QJniObject myJavaString2 = myJavaString1.callObjectMethod<jstring>("toString");
+ QJniEnvironment env;
+ jclass clazz = env.findClass("java/lang/String");
+ jmethodID methodId = env.findStaticMethod(clazz, "valueOf", "(I)Ljava/lang/String;");
+ if (methodId != 0)
+ QJniObject str = QJniObject::callStaticObjectMethod(clazz, methodId, 10);
\endcode
*/
+QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId, ...)
+{
+ if (clazz && methodId) {
+ QJniEnvironment env;
+ va_list args;
+ va_start(args, methodId);
+ QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, methodId, args), env.jniEnv());
+ va_end(args);
+ return res;
+ }
+
+ return QJniObject();
+}
/*!
- \fn QJniObject QJniObject::callStaticObjectMethod(const char *className, const char *methodName)
+ \fn template<typename Ret, typename ...Args> QJniObject QJniObject::callObjectMethod(const char *methodName, Args &&...args) const
+ \since 6.4
- Calls the static method with \a methodName on the class \a className.
+ Calls the Java objects method \a methodName with arguments \a args and returns a
+ new QJniObject for the returned Java object.
\code
- QJniObject string = QJniObject::callStaticObjectMethod<jstring>("CustomClass", "getClassName");
+ QJniObject myJavaString = QJniObject::fromString("Hello, Java");
+ QJniObject myJavaString2 = myJavaString1.callObjectMethod<jstring>("toString");
\endcode
-*/
-
-/*!
- \fn QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodName)
-
- Calls the static method with \a methodName on \a clazz.
+ The method signature is deduced at compile time from \c Ret and the types of \a args.
*/
/*!
- \fn template <typename T> T QJniObject::object() const
+ \fn template<typename Ret, typename ...Args> QJniObject QJniObject::callStaticObjectMethod(const char *className, const char *methodName, Args &&...args)
+ \since 6.4
- Returns the object held by the QJniObject as type T.
- T can be one of \l {Object Types}{JNI Object Types}.
+ Calls the static method with \a methodName on the class \a className, passing
+ arguments \a args, and returns a new QJniObject for the returned Java object.
\code
- QJniObject string = QJniObject::fromString("Hello, JNI");
- jstring jstring = string.object<jstring>();
+ QJniObject string = QJniObject::callStaticObjectMethod<jstring>("CustomClass", "getClassName");
\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.
+ The method signature is deduced at compile time from \c Ret and the types of \a args.
+*/
- \snippet jni/src_qjniobject.cpp QJniObject scope
+/*!
+ \fn template<typename Ret, typename ...Args> QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodName, Args &&...args)
+ \since 6.4
+
+ Calls the static method with \a methodName on \a clazz, passing arguments \a args,
+ and returns a new QJniObject for the returned Java object.
*/
/*!
- \fn template <typename T> QJniObject &QJniObject::operator=(T object)
+ \fn template <typename T, std::enable_if_t<std::is_convertible_v<T, jobject>, bool> = true> QJniObject &QJniObject::operator=(T object)
Replace the current object with \a object. The old Java object will be released.
*/
-#define MAKE_JNI_OBJECT_METHODS(Type, Signature) \
-template <> \
-Q_CORE_EXPORT QJniObject QJniObject::callObjectMethod<Type>(const char *methodName) const \
-{ \
- return callObjectMethod(methodName, Signature); \
-} \
-template <> \
-Q_CORE_EXPORT QJniObject QJniObject::callStaticObjectMethod<Type>(const char *className, \
- const char *methodName) \
-{ \
- return callStaticObjectMethod(className, methodName, Signature); \
-} \
-template <> \
-Q_CORE_EXPORT QJniObject QJniObject::callStaticObjectMethod<Type>(jclass clazz, \
- const char *methodName) \
-{ \
- return callStaticObjectMethod(clazz, methodName, Signature); \
-}\
-template <>\
-Q_CORE_EXPORT Type QJniObject::object<Type>() const\
-{\
- return static_cast<Type>(javaObject());\
-}\
-template <>\
-Q_CORE_EXPORT QJniObject &QJniObject::operator=(Type obj)\
-{\
- assign(static_cast<jobject>(obj));\
- return *this;\
-}
-
-#define DECLARE_JNI_OBJECT_METHODS(Type, Signature) MAKE_JNI_OBJECT_METHODS(Type, Signature)
-
-DECLARE_JNI_OBJECT_METHODS(jobject, "()Ljava/lang/Object;")
-DECLARE_JNI_OBJECT_METHODS(jclass, "()Ljava/lang/Class;")
-DECLARE_JNI_OBJECT_METHODS(jstring, "()Ljava/lang/String;")
-DECLARE_JNI_OBJECT_METHODS(jobjectArray, "()[Ljava/lang/Object;")
-DECLARE_JNI_OBJECT_METHODS(jbooleanArray, "()[Z")
-DECLARE_JNI_OBJECT_METHODS(jbyteArray, "()[B")
-DECLARE_JNI_OBJECT_METHODS(jshortArray, "()[S")
-DECLARE_JNI_OBJECT_METHODS(jintArray, "()[I")
-DECLARE_JNI_OBJECT_METHODS(jlongArray, "()[J")
-DECLARE_JNI_OBJECT_METHODS(jfloatArray, "()[F")
-DECLARE_JNI_OBJECT_METHODS(jdoubleArray, "()[D")
-DECLARE_JNI_OBJECT_METHODS(jcharArray, "()[C")
-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);
@@ -1344,24 +1103,6 @@ DECLARE_JNI_OBJECT_METHODS(jthrowable, "()Ljava/lang/Throwable;")
using the setter with \a signature.
*/
-template <>
-Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(const char *className,
- const char *fieldName,
- const char *signature,
- jobject value)
-{
- QJniEnvironment env;
- jclass clazz = loadClass(className, env);
-
- if (!clazz)
- return;
-
- jfieldID id = getCachedFieldID(env, clazz, className, fieldName, signature, true);
- if (id) {
- env->SetStaticObjectField(clazz, id, value);
- env.exceptionCheckAndClear();
- }
-}
/*!
\fn template <typename T> void QJniObject::setStaticField(jclass clazz, const char *fieldName, const char *signature, T value);
@@ -1369,22 +1110,9 @@ Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(const char *className,
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 *signature,
- jobject value)
-{
- QJniEnvironment env;
- jfieldID id = getFieldID(env, clazz, fieldName, signature, true);
-
- if (id) {
- env->SetStaticObjectField(clazz, id, value);
- env.exceptionCheckAndClear();
- }
-}
/*!
- \fn T QJniObject::getField(const char *fieldName) const
+ \fn template<typename T> T QJniObject::getField(const char *fieldName) const
Retrieves the value of the field \a fieldName.
@@ -1395,18 +1123,26 @@ template <> Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(jclass clazz,
*/
/*!
- \fn T QJniObject::getStaticField(const char *className, const char *fieldName)
+ \fn template<typename T> T QJniObject::getStaticField(const char *className, const char *fieldName)
Retrieves the value from the static field \a fieldName on the class \a className.
*/
/*!
- \fn T QJniObject::getStaticField(jclass clazz, const char *fieldName)
+ \fn template<typename T> T QJniObject::getStaticField(jclass clazz, const char *fieldName)
Retrieves the value from the static field \a fieldName on \a clazz.
*/
/*!
+ \fn template <typename Klass, typename T> auto QJniObject::getStaticField(const char *fieldName)
+
+ Retrieves the value from the static field \a fieldName for the class \c Klass.
+
+ \c Klass needs to be a C++ type with a registered type mapping to a Java type.
+*/
+
+/*!
\fn template <typename T> void QJniObject::setStaticField(const char *className, const char *fieldName, T value)
Sets the static field \a fieldName of the class \a className to \a value.
@@ -1417,98 +1153,19 @@ template <> Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(jclass clazz,
Sets the static field \a fieldName of the class \a clazz to \a value.
*/
-#define MAKE_JNI_PRIMITIVE_FIELDS(FieldName, Type, Signature) \
-template <> Q_CORE_EXPORT Type QJniObject::getField<Type>(const char *fieldName) const \
-{ \
- QJniEnvironment env; \
- Type res = 0; \
- jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, Signature); \
- if (id) {\
- res = env->Get##FieldName##Field(d->m_jobject, id); \
- if (env.exceptionCheckAndClear()) \
- res = 0; \
- } \
- return res;\
-} \
-template <> \
-Q_CORE_EXPORT Type QJniObject::getStaticField<Type>(const char *className, const char *fieldName) \
-{ \
- QJniEnvironment env; \
- jclass clazz = loadClass(className, env); \
- if (!clazz) \
- return 0; \
- jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, \
- Signature, true); \
- if (!id) \
- return 0; \
- Type res = env->GetStatic##FieldName##Field(clazz, id); \
- if (env.exceptionCheckAndClear()) \
- res = 0; \
- return res;\
-} \
-template <>\
-Q_CORE_EXPORT Type QJniObject::getStaticField<Type>(jclass clazz, const char *fieldName)\
-{\
- QJniEnvironment env;\
- Type res = 0;\
- jfieldID id = getFieldID(env, clazz, fieldName, Signature, true);\
- if (id) {\
- res = env->GetStatic##FieldName##Field(clazz, id);\
- if (env.exceptionCheckAndClear()) \
- res = 0; \
- }\
- return res;\
-}\
-template <> Q_CORE_EXPORT void QJniObject::setStaticField<Type>(const char *className, \
- const char *fieldName, \
- Type value) \
-{ \
- QJniEnvironment env; \
- jclass clazz = loadClass(className, env); \
- if (!clazz) \
- return; \
- jfieldID id = getCachedFieldID(env, clazz, className, fieldName, Signature, true); \
- if (!id) \
- return; \
- env->SetStatic##FieldName##Field(clazz, id, value); \
- env.exceptionCheckAndClear(); \
-}\
-template <> Q_CORE_EXPORT void QJniObject::setStaticField<Type>(jclass clazz,\
- const char *fieldName,\
- Type value)\
-{\
- QJniEnvironment env;\
- jfieldID id = getFieldID(env, clazz, fieldName, Signature, true);\
- if (id) {\
- env->SetStatic##FieldName##Field(clazz, id, value);\
- env.exceptionCheckAndClear();\
- }\
-}\
-template <> Q_CORE_EXPORT void QJniObject::setField<Type>(const char *fieldName, Type value) \
-{ \
- QJniEnvironment env; \
- jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, Signature); \
- if (id) { \
- env->Set##FieldName##Field(d->m_jobject, id, value); \
- env.exceptionCheckAndClear(); \
- } \
-} \
-
-#define DECLARE_JNI_PRIMITIVE_FIELDS(FieldName, Type, Signature) MAKE_JNI_PRIMITIVE_FIELDS(FieldName, Type, \
- Signature)
-DECLARE_JNI_PRIMITIVE_FIELDS(Boolean, jboolean, "Z")
-DECLARE_JNI_PRIMITIVE_FIELDS(Byte, jbyte, "B")
-DECLARE_JNI_PRIMITIVE_FIELDS(Char, jchar, "C")
-DECLARE_JNI_PRIMITIVE_FIELDS(Short, jshort, "S")
-DECLARE_JNI_PRIMITIVE_FIELDS(Int, jint, "I")
-DECLARE_JNI_PRIMITIVE_FIELDS(Long, jlong, "J")
-DECLARE_JNI_PRIMITIVE_FIELDS(Float, jfloat, "F")
-DECLARE_JNI_PRIMITIVE_FIELDS(Double, jdouble, "D")
+
+/*!
+ \fn template <typename Klass, typename T> auto QJniObject::setStaticField(const char *fieldName, T value)
+
+ Sets the static field \a fieldName of the class \c Klass to \a value.
+
+ \c Klass needs to be a C++ type with a registered type mapping to a Java type.
+*/
/*!
\fn QJniObject QJniObject::getStaticObjectField(const char *className, const char *fieldName, const char *signature)
- Retrieves a JNI object from the field \a filedName with \a signature from
+ Retrieves a JNI object from the field \a fieldName with \a signature from
class \a className.
\note This function can be used without a template type.
@@ -1522,16 +1179,18 @@ QJniObject QJniObject::getStaticObjectField(const char *className,
const char *fieldName,
const char *signature)
{
- QJniEnvironment env;
- jclass clazz = loadClass(className, env);
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jclass clazz = QJniObject::loadClass(className, env);
if (!clazz)
return QJniObject();
- jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName,
+ jfieldID id = QJniObject::getCachedFieldID(env, clazz,
+ className,
+ fieldName,
signature, true);
if (!id)
return QJniObject();
- return getCleanJniObject(env->GetStaticObjectField(clazz, id));
+ return getCleanJniObject(env->GetStaticObjectField(clazz, id), env);
}
/*!
@@ -1546,72 +1205,12 @@ QJniObject QJniObject::getStaticObjectField(const char *className,
QJniObject jobj = QJniObject::getStaticObjectField(clazz, "FIELD_NAME", "Ljava/lang/String;");
\endcode
*/
-QJniObject QJniObject::getStaticObjectField(jclass clazz,
- const char *fieldName,
+QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName,
const char *signature)
{
- QJniEnvironment env;
+ JNIEnv *env = QJniEnvironment::getJniEnv();
jfieldID id = getFieldID(env, clazz, fieldName, signature, true);
- if (!id)
- return QJniObject();
-
- return getCleanJniObject(env->GetStaticObjectField(clazz, id));
-}
-
-/*!
- \fn QJniObject QJniObject::getStaticObjectField<jobject>(jclass clazz, const char *fieldName, const char *signature)
-
- 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 *signature)
-{
- return getStaticObjectField(clazz, fieldName, signature);
-}
-
-/*!
- \fn QJniObject QJniObject::getStaticObjectField<jobject>(const char *className, const char *fieldName, const char *signature)
-
- 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 *signature)
-{
- return getStaticObjectField(className, fieldName, signature);
-}
-
-/*!
- \fn QJniObject QJniObject::getStaticObjectField<jobjectArray>(jclass clazz, const char *fieldName, const char *signature)
-
- 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 *signature)
-{
- return getStaticObjectField(clazz, fieldName, signature);
-}
-
-/*!
- \fn QJniObject QJniObject::getStaticObjectField<jobjectArray>(const char *className, const char *fieldName, const char *signature)
-
- 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 *signature)
-{
- return getStaticObjectField(className, fieldName, signature);
+ return getCleanJniObject(env->GetStaticObjectField(clazz, id), env);
}
/*!
@@ -1622,36 +1221,13 @@ Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobjectArray>(const ch
\code
QJniObject stringArray = ...;
QJniObject obj = ...;
- obj.setField<jobjectArray>("KEY_VALUES", "([Ljava/lang/String;)V",
+ obj.setObjectField<jobjectArray>("KEY_VALUES", "([Ljava/lang/String;)V",
stringArray.object<jobjectArray>())
\endcode
*/
-template <> Q_CORE_EXPORT
-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, signature);
- if (id) {
- env->SetObjectField(d->m_jobject, id, value);
- env.exceptionCheckAndClear();
- }
-}
-
-template <> Q_CORE_EXPORT
-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, signature);
- if (id) {
- env->SetObjectField(d->m_jobject, id, value);
- env.exceptionCheckAndClear();
- }
-}
/*!
- \fn QJniObject QJniObject::getObjectField(const char *fieldName) const
+ \fn template<typename T> QJniObject QJniObject::getObjectField(const char *fieldName) const
Retrieves a JNI object from the field \a fieldName.
@@ -1673,12 +1249,11 @@ void QJniObject::setField<jobjectArray>(const char *fieldName,
*/
QJniObject QJniObject::getObjectField(const char *fieldName, const char *signature) const
{
- QJniEnvironment env;
- jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, signature);
+ jfieldID id = getCachedFieldID(jniEnv(), fieldName, signature);
if (!id)
return QJniObject();
- return getCleanJniObject(env->GetObjectField(d->m_jobject, id));
+ return getCleanJniObject(jniEnv()->GetObjectField(d->m_jobject, id), jniEnv());
}
/*!
@@ -1695,7 +1270,7 @@ QJniObject QJniObject::getObjectField(const char *fieldName, const char *signatu
*/
/*!
- \fn QJniObject QJniObject::getStaticObjectField(const char *className, const char *fieldName)
+ \fn template<typename T> QJniObject QJniObject::getStaticObjectField(const char *className, const char *fieldName)
Retrieves the object from the field \a fieldName on the class \a className.
@@ -1705,7 +1280,7 @@ QJniObject QJniObject::getObjectField(const char *fieldName, const char *signatu
*/
/*!
- \fn QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName)
+ \fn template<typename T> QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName)
Retrieves the object from the field \a fieldName on \a clazz.
@@ -1714,52 +1289,6 @@ QJniObject QJniObject::getObjectField(const char *fieldName, const char *signatu
\endcode
*/
-#define MAKE_JNI_OBJECT_FILEDS(Type, Signature) \
-template <> Q_CORE_EXPORT void QJniObject::setField<Type>(const char *fieldName, Type value) \
-{ \
- QJniObject::setField<jobject>(fieldName, Signature, value); \
-} \
-\
-template <> Q_CORE_EXPORT void QJniObject::setStaticField<Type>(const char *className, \
- const char *fieldName, \
- Type value) \
-{ \
- QJniObject::setStaticField<jobject>(className, fieldName, Signature, value); \
-}\
-template <>\
-Q_CORE_EXPORT QJniObject QJniObject::getObjectField<Type>(const char *fieldName) const\
-{\
- return getObjectField(fieldName, Signature);\
-}\
-template <>\
-Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<Type>(jclass clazz,\
- const char *fieldName)\
-{\
- return getStaticObjectField(clazz, fieldName, Signature);\
-}\
-template <>\
-Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<Type>(const char *className,\
- const char *fieldName)\
-{\
- return getStaticObjectField(className, fieldName, Signature);\
-}\
-
-#define DECLARE_JNI_OBJECT_FILEDS(Type, Signature) MAKE_JNI_OBJECT_FILEDS(Type, Signature)
-
-DECLARE_JNI_OBJECT_FILEDS(jobject, "Ljava/lang/Object;")
-DECLARE_JNI_OBJECT_FILEDS(jobjectArray, "[Ljava/lang/Object;")
-DECLARE_JNI_OBJECT_FILEDS(jstring, "Ljava/lang/String;")
-DECLARE_JNI_OBJECT_FILEDS(jclass, "Ljava/lang/Class;")
-DECLARE_JNI_OBJECT_FILEDS(jthrowable, "Ljava/lang/Throwable;")
-DECLARE_JNI_OBJECT_FILEDS(jbooleanArray, "[Z")
-DECLARE_JNI_OBJECT_FILEDS(jbyteArray, "[B")
-DECLARE_JNI_OBJECT_FILEDS(jcharArray, "[C")
-DECLARE_JNI_OBJECT_FILEDS(jshortArray, "[S")
-DECLARE_JNI_OBJECT_FILEDS(jintArray, "[I")
-DECLARE_JNI_OBJECT_FILEDS(jlongArray, "[J")
-DECLARE_JNI_OBJECT_FILEDS(jfloatArray, "[F")
-DECLARE_JNI_OBJECT_FILEDS(jdoubleArray, "[D")
-
/*!
\fn QJniObject QJniObject::fromString(const QString &string)
@@ -1775,8 +1304,11 @@ DECLARE_JNI_OBJECT_FILEDS(jdoubleArray, "[D")
QJniObject QJniObject::fromString(const QString &string)
{
QJniEnvironment env;
- return getCleanJniObject(env->NewString(reinterpret_cast<const jchar*>(string.constData()),
- string.length()));
+ jstring stringRef = env->NewString(reinterpret_cast<const jchar*>(string.constData()),
+ string.length());
+ QJniObject stringObject = getCleanJniObject(stringRef, env.jniEnv());
+ stringObject.d->m_className = "java/lang/String";
+ return stringObject;
}
/*!
@@ -1799,7 +1331,10 @@ QString QJniObject::toString() const
return QString();
QJniObject string = callObjectMethod<jstring>("toString");
- return qt_convertJString(static_cast<jstring>(string.object()));
+ const int strLength = string.jniEnv()->GetStringLength(string.object<jstring>());
+ QString res(strLength, Qt::Uninitialized);
+ string.jniEnv()->GetStringRegion(string.object<jstring>(), 0, strLength, reinterpret_cast<jchar *>(res.data()));
+ return res;
}
/*!
@@ -1817,10 +1352,10 @@ bool QJniObject::isClassAvailable(const char *className)
{
QJniEnvironment env;
- if (!env)
+ if (!env.jniEnv())
return false;
- return loadClass(className, env);;
+ return loadClass(className, env.jniEnv());
}
/*!
@@ -1856,13 +1391,17 @@ bool QJniObject::isValid() const
QJniObject QJniObject::fromLocalRef(jobject lref)
{
QJniObject obj(lref);
- QJniEnvironment()->DeleteLocalRef(lref);
+ obj.jniEnv()->DeleteLocalRef(lref);
return obj;
}
bool QJniObject::isSameObject(jobject obj) const
{
- return QJniEnvironment()->IsSameObject(d->m_jobject, obj);
+ if (d->m_jobject == obj)
+ return true;
+ if (!d->m_jobject || !obj)
+ return false;
+ return jniEnv()->IsSameObject(d->m_jobject, obj);
}
bool QJniObject::isSameObject(const QJniObject &other) const
@@ -1872,15 +1411,14 @@ bool QJniObject::isSameObject(const QJniObject &other) const
void QJniObject::assign(jobject obj)
{
- if (isSameObject(obj))
+ if (d && isSameObject(obj))
return;
- jobject jobj = static_cast<jobject>(obj);
d = QSharedPointer<QJniObjectPrivate>::create();
if (obj) {
- QJniEnvironment env;
- d->m_jobject = env->NewGlobalRef(jobj);
- jclass objectClass = env->GetObjectClass(jobj);
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ d->m_jobject = env->NewGlobalRef(obj);
+ jclass objectClass = env->GetObjectClass(obj);
d->m_jclass = static_cast<jclass>(env->NewGlobalRef(objectClass));
env->DeleteLocalRef(objectClass);
}