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.cpp1486
1 files changed, 513 insertions, 973 deletions
diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp
index 418a404bb4..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
@@ -286,82 +278,162 @@ 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::checkAndClearExceptions(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);
@@ -372,20 +444,26 @@ static inline jmethodID getMethodID(JNIEnv *env,
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,15 +485,21 @@ 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);
@@ -426,20 +510,18 @@ static inline jfieldID getFieldID(JNIEnv *env,
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,57 +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);
-
- if (clazz || isCached)
- 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::checkAndClearExceptions(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().jniEnv(), 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()
@@ -536,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.jniEnv(), 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.jniEnv(), 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();
}
/*!
@@ -569,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.jniEnv(), 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.jniEnv(), 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.jniEnv(), true);
- d->m_own_jclass = false;
- if (d->m_jclass) {
- jmethodID constructorId = getCachedMethodID(env.jniEnv(), 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.
@@ -622,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.jniEnv(), 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
@@ -652,45 +670,11 @@ QJniObject::QJniObject(jclass clazz, const char *signature, ...)
*/
QJniObject::QJniObject(jclass clazz)
- : d(new QJniObjectPrivate())
-{
- QJniEnvironment env;
- d->m_jclass = static_cast<jclass>(env->NewGlobalRef(clazz));
- if (d->m_jclass) {
- // get default constructor
- jmethodID constructorId = getMethodID(env.jniEnv(), 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())
+ : QJniObject(clazz, "()V")
{
- QJniEnvironment env;
- if (clazz) {
- d->m_jclass = static_cast<jclass>(env->NewGlobalRef(clazz));
- if (d->m_jclass) {
- jmethodID constructorId = getMethodID(env.jniEnv(), 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
@@ -702,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.checkAndClearExceptions()) {
- 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()
@@ -744,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
@@ -766,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.jniEnv(), d->m_jclass, d->m_className, methodName, signature);
- if (id) {
- res = env->CallObjectMethodV(d->m_jobject, id, args);
- if (env.checkAndClearExceptions()) {
- 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.jniEnv());
- if (clazz) {
- jmethodID id = getCachedMethodID(env.jniEnv(), clazz, toBinaryEncClassName(className),
- methodName, signature, true);
- if (id) {
- res = env->CallStaticObjectMethodV(clazz, id, args);
- if (env.checkAndClearExceptions()) {
- 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.jniEnv(), 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.jniEnv(), 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.checkAndClearExceptions();
- }
-}
/*!
- \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;
@@ -878,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.jniEnv());
- if (clazz) {
- jmethodID id = getCachedMethodID(env.jniEnv(), clazz, toBinaryEncClassName(className),
- methodName, signature, true);
- if (id) {
- va_list args;
- va_start(args, signature);
- env->CallStaticVoidMethodV(clazz, id, args);
- va_end(args);
- env.checkAndClearExceptions();
- }
- }
-}
/*!
- \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;
@@ -928,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.jniEnv(), clazz, methodName, signature, true);
- if (id) {
- va_list args;
- va_start(args, signature);
- env->CallStaticVoidMethodV(clazz, id, args);
- va_end(args);
- env.checkAndClearExceptions();
- }
- }
-}
-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.jniEnv());
- if (clazz) {
- jmethodID id = getCachedMethodID(env.jniEnv(), clazz,
- toBinaryEncClassName(className), methodName,
- signature, true);
- if (id) {
- env->CallStaticVoidMethodV(clazz, id, args);
- env.checkAndClearExceptions();
- }
- }
-}
+/*!
+ \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.jniEnv(), clazz, methodName, signature, true);
- if (id) {
- env->CallStaticVoidMethodV(clazz, id, args);
- env.checkAndClearExceptions();
+ 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.jniEnv(), d->m_jclass, d->m_className, methodName, signature);
- if (id) {
- env->CallVoidMethodV(d->m_jobject, id, args);
- env.checkAndClearExceptions();
- }
-}
+/*!
+ \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.jniEnv(), 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.checkAndClearExceptions()) \
- 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.jniEnv()); \
- if (clazz) { \
- jmethodID id = getCachedMethodID(env.jniEnv(), 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.checkAndClearExceptions()) \
- 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.jniEnv(), 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.checkAndClearExceptions()) \
- 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.jniEnv(), d->m_jclass, d->m_className, methodName, signature);\
- if (id) {\
- res = env->Call##MethodName##MethodV(d->m_jobject, id, args);\
- if (env.checkAndClearExceptions()) \
- 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.jniEnv());\
- if (clazz) {\
- jmethodID id = getCachedMethodID(env.jniEnv(), clazz, toBinaryEncClassName(className), methodName,\
- signature, true);\
- if (id) {\
- res = env->CallStatic##MethodName##MethodV(clazz, id, args);\
- if (env.checkAndClearExceptions()) \
- 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.jniEnv(), clazz, methodName, signature, true);\
- if (id) {\
- res = env->CallStatic##MethodName##MethodV(clazz, id, args);\
- if (env.checkAndClearExceptions()) \
- 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
@@ -1161,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.jniEnv(), 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;
}
@@ -1187,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());
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jclass clazz = QJniObject::loadClass(className, env);
if (clazz) {
- jmethodID id = getCachedMethodID(env.jniEnv(), 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;
}
@@ -1215,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) {
+ 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;
}
@@ -1236,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);
@@ -1342,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.jniEnv());
-
- if (!clazz)
- return;
-
- jfieldID id = getCachedFieldID(env.jniEnv(), clazz, className, fieldName, signature, true);
- if (id) {
- env->SetStaticObjectField(clazz, id, value);
- env.checkAndClearExceptions();
- }
-}
/*!
\fn template <typename T> void QJniObject::setStaticField(jclass clazz, const char *fieldName, const char *signature, T value);
@@ -1367,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.jniEnv(), clazz, fieldName, signature, true);
-
- if (id) {
- env->SetStaticObjectField(clazz, id, value);
- env.checkAndClearExceptions();
- }
-}
/*!
- \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.
@@ -1393,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.
@@ -1415,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.jniEnv(), d->m_jclass, d->m_className, fieldName, Signature); \
- if (id) {\
- res = env->Get##FieldName##Field(d->m_jobject, id); \
- if (env.checkAndClearExceptions()) \
- 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.jniEnv()); \
- if (!clazz) \
- return 0; \
- jfieldID id = getCachedFieldID(env.jniEnv(), clazz, toBinaryEncClassName(className), fieldName, \
- Signature, true); \
- if (!id) \
- return 0; \
- Type res = env->GetStatic##FieldName##Field(clazz, id); \
- if (env.checkAndClearExceptions()) \
- 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.jniEnv(), clazz, fieldName, Signature, true);\
- if (id) {\
- res = env->GetStatic##FieldName##Field(clazz, id);\
- if (env.checkAndClearExceptions()) \
- 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.jniEnv()); \
- if (!clazz) \
- return; \
- jfieldID id = getCachedFieldID(env.jniEnv(), clazz, className, fieldName, Signature, true); \
- if (!id) \
- return; \
- env->SetStatic##FieldName##Field(clazz, id, value); \
- env.checkAndClearExceptions(); \
-}\
-template <> Q_CORE_EXPORT void QJniObject::setStaticField<Type>(jclass clazz,\
- const char *fieldName,\
- Type value)\
-{\
- QJniEnvironment env;\
- jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, Signature, true);\
- if (id) {\
- env->SetStatic##FieldName##Field(clazz, id, value);\
- env.checkAndClearExceptions();\
- }\
-}\
-template <> Q_CORE_EXPORT void QJniObject::setField<Type>(const char *fieldName, Type value) \
-{ \
- QJniEnvironment env; \
- jfieldID id = getCachedFieldID(env.jniEnv(), d->m_jclass, d->m_className, fieldName, Signature); \
- if (id) { \
- env->Set##FieldName##Field(d->m_jobject, id, value); \
- env.checkAndClearExceptions(); \
- } \
-} \
-
-#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.
@@ -1520,16 +1179,18 @@ QJniObject QJniObject::getStaticObjectField(const char *className,
const char *fieldName,
const char *signature)
{
- QJniEnvironment env;
- jclass clazz = loadClass(className, env.jniEnv());
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jclass clazz = QJniObject::loadClass(className, env);
if (!clazz)
return QJniObject();
- jfieldID id = getCachedFieldID(env.jniEnv(), 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);
}
/*!
@@ -1544,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;
- jfieldID id = getFieldID(env.jniEnv(), 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);
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jfieldID id = getFieldID(env, clazz, fieldName, signature, true);
+ return getCleanJniObject(env->GetStaticObjectField(clazz, id), env);
}
/*!
@@ -1620,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.jniEnv(), d->m_jclass, d->m_className, fieldName, signature);
- if (id) {
- env->SetObjectField(d->m_jobject, id, value);
- env.checkAndClearExceptions();
- }
-}
-
-template <> Q_CORE_EXPORT
-void QJniObject::setField<jobjectArray>(const char *fieldName,
- const char *signature,
- jobjectArray value)
-{
- QJniEnvironment env;
- jfieldID id = getCachedFieldID(env.jniEnv(), d->m_jclass, d->m_className, fieldName, signature);
- if (id) {
- env->SetObjectField(d->m_jobject, id, value);
- env.checkAndClearExceptions();
- }
-}
/*!
- \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.
@@ -1671,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.jniEnv(), 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());
}
/*!
@@ -1693,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.
@@ -1703,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.
@@ -1712,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)
@@ -1773,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;
}
/*!
@@ -1797,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;
}
/*!
@@ -1818,7 +1355,7 @@ bool QJniObject::isClassAvailable(const char *className)
if (!env.jniEnv())
return false;
- return loadClass(className, env.jniEnv());;
+ return loadClass(className, env.jniEnv());
}
/*!
@@ -1854,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
@@ -1870,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);
}