Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qjniobject.h
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QJNIOBJECT_H
5#define QJNIOBJECT_H
6
7#include <QtCore/qsharedpointer.h>
8
9#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
10#include <jni.h>
11#include <QtCore/qjnienvironment.h>
12#include <QtCore/qxptype_traits.h>
13
14QT_BEGIN_NAMESPACE
15
16class QJniObjectPrivate;
17class QJniObject;
18
19namespace QtJniTypes
20{
21namespace Detail
22{
23// any type with an "jobject object()" member function stores a global reference
24template <typename T, typename = void> struct StoresGlobalRefTest : std::false_type {};
25template <typename T>
26struct StoresGlobalRefTest<T, std::void_t<decltype(std::declval<T>().object())>>
27 : std::is_same<decltype(std::declval<T>().object()), jobject>
28{};
29
30// detect if a type is std::expected-like
31template <typename R, typename = void>
32struct CallerHandlesException : std::false_type {
33 using value_type = R;
34};
35template <typename R>
36struct CallerHandlesException<R, std::void_t<typename R::unexpected_type,
37 typename R::value_type,
38 typename R::error_type>> : std::true_type
39{
40 using value_type = typename R::value_type;
41};
42
43template <typename ReturnType>
44static constexpr bool callerHandlesException = CallerHandlesException<ReturnType>::value;
45
46template <typename ...Args>
47struct LocalFrame
48{
49 mutable JNIEnv *env;
50 bool hasFrame = false;
51
52 explicit LocalFrame(JNIEnv *env = nullptr) noexcept
53 : env(env)
54 {
55 }
56 ~LocalFrame()
57 {
58 if (hasFrame)
59 env->PopLocalFrame(nullptr);
60 }
61 bool ensureFrame()
62 {
63 if (!hasFrame)
64 hasFrame = jniEnv()->PushLocalFrame(sizeof...(Args)) == 0;
65 return hasFrame;
66 }
67 JNIEnv *jniEnv() const
68 {
69 if (!env)
70 env = QJniEnvironment::getJniEnv();
71 return env;
72 }
73
74 template <typename T>
75 auto convertToJni(T &&value)
76 {
77 using Type = q20::remove_cvref_t<T>;
78 using ResultType = decltype(QtJniTypes::Traits<Type>::convertToJni(jniEnv(),
79 std::declval<T&&>()));
80 if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>,
81 std::remove_pointer_t<ResultType>>) {
82 // Make sure the local frame is engaged if we create a jobject, unless
83 // we know that the value stores a global reference that it returns.
84 if constexpr (!qxp::is_detected_v<StoresGlobalRefTest, Type>) {
85 if (!ensureFrame())
86 return ResultType{};
87 }
88 }
89 return QtJniTypes::Traits<Type>::convertToJni(jniEnv(), std::forward<T>(value));
90 }
91 template <typename T>
92 auto convertFromJni(QJniObject &&object)
93 {
94 using Type = q20::remove_cvref_t<T>;
95 return QtJniTypes::Traits<Type>::convertFromJni(std::move(object));
96 }
97};
98
99template <typename Ret, typename ...Args>
100struct LocalFrameWithReturn : LocalFrame<Args...>
101{
102 using ReturnType = Ret;
103
104 using LocalFrame<Args...>::LocalFrame;
105
106 template <typename T>
107 auto convertFromJni(QJniObject &&object)
108 {
109 return LocalFrame<Args...>::template convertFromJni<T>(std::move(object));
110 }
111
112 template <typename T>
113 auto convertFromJni(jobject object);
114
115 bool checkAndClearExceptions() const
116 {
117 if constexpr (callerHandlesException<ReturnType>)
118 return false;
119 else
120 return QJniEnvironment::checkAndClearExceptions(this->jniEnv());
121 }
122
123 auto makeResult()
124 {
125 if constexpr (callerHandlesException<ReturnType>) {
126 JNIEnv *env = this->jniEnv();
127 if (env->ExceptionCheck()) {
128 jthrowable exception = env->ExceptionOccurred();
129 env->ExceptionClear();
130 return ReturnType(typename ReturnType::unexpected_type(exception));
131 }
132 return ReturnType();
133 } else {
134 checkAndClearExceptions();
135 }
136 }
137
138 template <typename Value>
139 auto makeResult(Value &&value)
140 {
141 if constexpr (callerHandlesException<ReturnType>) {
142 auto maybeValue = makeResult();
143 if (maybeValue)
144 return ReturnType(std::forward<Value>(value));
145 return std::move(maybeValue);
146 } else {
147 checkAndClearExceptions();
148 return std::forward<Value>(value);
149 }
150 }
151};
152}
153}
154
155class Q_CORE_EXPORT QJniObject
156{
157 template <typename Ret, typename ...Args> using LocalFrame
158 = QtJniTypes::Detail::LocalFrameWithReturn<Ret, Args...>;
159
160public:
161 QJniObject();
162 explicit QJniObject(const char *className);
163 explicit QJniObject(const char *className, const char *signature, ...);
164 template<typename ...Args
165#ifndef Q_QDOC
166 , std::enable_if_t<!std::disjunction_v<QtJniTypes::IsStringType<std::decay_t<Args>>...>>* = nullptr
167#endif
168 >
169 explicit QJniObject(const char *className, Args &&...args)
170 : QJniObject(QtJniTypes::Detail::LocalFrame<Args...>{}, className, std::forward<Args>(args)...)
171 {
172 }
173private:
174 template<typename ...Args>
175 explicit QJniObject(QtJniTypes::Detail::LocalFrame<Args...> localFrame, const char *className, Args &&...args)
176 : QJniObject(className, QtJniTypes::constructorSignature<Args...>().data(),
177 localFrame.convertToJni(std::forward<Args>(args))...)
178 {
179 }
180public:
181 explicit QJniObject(jclass clazz);
182 explicit QJniObject(jclass clazz, const char *signature, ...);
183 template<typename ...Args
184#ifndef Q_QDOC
185 , std::enable_if_t<!std::disjunction_v<QtJniTypes::IsStringType<std::decay_t<Args>>...>>* = nullptr
186#endif
187 >
188 explicit QJniObject(jclass clazz, Args &&...args)
189 : QJniObject(clazz, QtJniTypes::constructorSignature<Args...>().data(),
190 std::forward<Args>(args)...)
191 {}
192 QJniObject(jobject globalRef);
193
194 QJniObject(const QJniObject &other) noexcept = default;
195 QJniObject(QJniObject &&other) noexcept = default;
196 QJniObject &operator=(const QJniObject &other) noexcept = default;
197 QJniObject &operator=(QJniObject &&other) noexcept = default;
198
199 ~QJniObject();
200
201 void swap(QJniObject &other) noexcept { d.swap(other.d); }
202
203 template<typename Class, typename ...Args
204#ifndef Q_QDOC
205 , QtJniTypes::IfValidSignatureTypes<Class, Args...> = true
206#endif
207 >
208 static inline auto construct(Args &&...args)
209 {
210 LocalFrame<Class, Args...> frame;
211 jclass clazz = QJniObject::loadClassKeepExceptions(QtJniTypes::Traits<Class>::className().data(),
212 frame.jniEnv());
213 auto res = clazz
214 ? QJniObject(clazz, QtJniTypes::constructorSignature<Args...>().data(),
215 frame.convertToJni(std::forward<Args>(args))...)
216 : QtJniTypes::Detail::callerHandlesException<Class>
217 ? QJniObject(Qt::Initialization::Uninitialized)
218 : QJniObject();
219 return frame.makeResult(std::move(res));
220 }
221
222 jobject object() const;
223 template <typename T> T object() const
224 {
225 QtJniTypes::assertObjectType<T>();
226 return static_cast<T>(javaObject());
227 }
228
229 jclass objectClass() const;
230 QByteArray className() const;
231
232 template <typename ReturnType = void, typename ...Args
233#ifndef Q_QDOC
234 , QtJniTypes::IfValidFieldType<ReturnType> = true
235#endif
236 >
237 auto callMethod(const char *methodName, const char *signature, Args &&...args) const
238 {
239 using Ret = typename QtJniTypes::Detail::CallerHandlesException<ReturnType>::value_type;
240 LocalFrame<ReturnType, Args...> frame(jniEnv());
241 jmethodID id = getCachedMethodID(frame.jniEnv(), methodName, signature);
242
243 if constexpr (QtJniTypes::isObjectType<Ret>()) {
244 return frame.makeResult(frame.template convertFromJni<Ret>(callObjectMethodImpl(
245 id, frame.convertToJni(std::forward<Args>(args))...))
246 );
247 } else {
248 if (id) {
249 if constexpr (std::is_same_v<Ret, void>) {
250 callVoidMethodV(frame.jniEnv(), id,
251 frame.convertToJni(std::forward<Args>(args))...);
252 } else {
253 Ret res{};
254 callMethodForType<Ret>(frame.jniEnv(), res, object(), id,
255 frame.convertToJni(std::forward<Args>(args))...);
256 return frame.makeResult(res);
257 }
258 }
259 if constexpr (!std::is_same_v<Ret, void>)
260 return frame.makeResult(Ret{});
261 else
262 return frame.makeResult();
263 }
264 }
265
266 template <typename ReturnType = void, typename ...Args
267#ifndef Q_QDOC
268 , QtJniTypes::IfValidSignatureTypes<ReturnType, Args...> = true
269#endif
270 >
271 auto callMethod(const char *methodName, Args &&...args) const
272 {
273 constexpr auto signature = QtJniTypes::methodSignature<ReturnType, Args...>();
274 return callMethod<ReturnType>(methodName, signature.data(), std::forward<Args>(args)...);
275 }
276
277 template <typename Ret, typename ...Args
278#ifndef Q_QDOC
279 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
280#endif
281 >
282 QJniObject callObjectMethod(const char *methodName, Args &&...args) const
283 {
284 QtJniTypes::assertObjectType<Ret>();
285 constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
286 LocalFrame<Ret, Args...> frame(jniEnv());
287 auto object = frame.template convertFromJni<Ret>(callObjectMethod(methodName, signature,
288 frame.convertToJni(std::forward<Args>(args))...));
289 frame.checkAndClearExceptions();
290 return object;
291 }
292
293 QJniObject callObjectMethod(const char *methodName, const char *signature, ...) const;
294
295 template <typename Ret = void, typename ...Args>
296 static auto callStaticMethod(const char *className, const char *methodName, const char *signature, Args &&...args)
297 {
298 LocalFrame<Ret, Args...> frame;
299 jclass clazz = QJniObject::loadClass(className, frame.jniEnv());
300 return callStaticMethod<Ret>(clazz, methodName, signature, std::forward<Args>(args)...);
301 }
302
303 template <typename Ret = void, typename ...Args>
304 static auto callStaticMethod(jclass clazz, const char *methodName, const char *signature, Args &&...args)
305 {
306 LocalFrame<Ret, Args...> frame;
307 jmethodID id = clazz ? getMethodID(frame.jniEnv(), clazz, methodName, signature, true)
308 : 0;
309 return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...);
310 }
311
312 template <typename ReturnType = void, typename ...Args
313#ifndef Q_QDOC
314 , QtJniTypes::IfValidFieldType<ReturnType> = true
315#endif
316 >
317 static auto callStaticMethod(jclass clazz, jmethodID methodId, Args &&...args)
318 {
319 using Ret = typename QtJniTypes::Detail::CallerHandlesException<ReturnType>::value_type;
320 LocalFrame<ReturnType, Args...> frame;
321 if constexpr (QtJniTypes::isObjectType<Ret>()) {
322 return frame.makeResult(frame.template convertFromJni<Ret>(callStaticObjectMethod(
323 clazz, methodId,
324 frame.convertToJni(std::forward<Args>(args))...))
325 );
326 } else {
327 if (clazz && methodId) {
328 if constexpr (std::is_same_v<Ret, void>) {
329 callStaticMethodForVoid(frame.jniEnv(), clazz, methodId,
330 frame.convertToJni(std::forward<Args>(args))...);
331 } else {
332 Ret res{};
333 callStaticMethodForType<Ret>(frame.jniEnv(), res, clazz, methodId,
334 frame.convertToJni(std::forward<Args>(args))...);
335 return frame.makeResult(res);
336 }
337 }
338 if constexpr (!std::is_same_v<Ret, void>)
339 return frame.makeResult(Ret{});
340 else
341 return frame.makeResult();
342 }
343 }
344
345 template <typename ReturnType = void, typename ...Args
346#ifndef Q_QDOC
347 , QtJniTypes::IfValidSignatureTypes<ReturnType, Args...> = true
348#endif
349 >
350 static auto callStaticMethod(const char *className, const char *methodName, Args &&...args)
351 {
352 using Ret = typename QtJniTypes::Detail::CallerHandlesException<ReturnType>::value_type;
353 LocalFrame<Ret, Args...> frame;
354 jclass clazz = QJniObject::loadClass(className, frame.jniEnv());
355 const jmethodID id = clazz ? getMethodID(frame.jniEnv(), clazz, methodName,
356 QtJniTypes::methodSignature<Ret, Args...>().data(), true)
357 : 0;
358 return callStaticMethod<ReturnType>(clazz, id, std::forward<Args>(args)...);
359 }
360
361 template <typename ReturnType = void, typename ...Args
362#ifndef Q_QDOC
363 , QtJniTypes::IfValidSignatureTypes<ReturnType, Args...> = true
364#endif
365 >
366 static auto callStaticMethod(jclass clazz, const char *methodName, Args &&...args)
367 {
368 constexpr auto signature = QtJniTypes::methodSignature<ReturnType, Args...>();
369 return callStaticMethod<ReturnType>(clazz, methodName, signature.data(), std::forward<Args>(args)...);
370 }
371 template <typename Klass, typename ReturnType = void, typename ...Args
372#ifndef Q_QDOC
373 , QtJniTypes::IfValidSignatureTypes<ReturnType, Args...> = true
374#endif
375 >
376 static auto callStaticMethod(const char *methodName, Args &&...args)
377 {
378 LocalFrame<ReturnType, Args...> frame;
379 const jclass clazz = QJniObject::loadClass(QtJniTypes::Traits<Klass>::className().data(),
380 frame.jniEnv());
381 const jmethodID id = clazz ? getMethodID(frame.jniEnv(), clazz, methodName,
382 QtJniTypes::methodSignature<ReturnType, Args...>().data(), true)
383 : 0;
384 return callStaticMethod<ReturnType>(clazz, id, std::forward<Args>(args)...);
385 }
386
387 static QJniObject callStaticObjectMethod(const char *className, const char *methodName,
388 const char *signature, ...);
389
390 static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName,
391 const char *signature, ...);
392
393 static QJniObject callStaticObjectMethod(jclass clazz, jmethodID methodId, ...);
394
395
396 template <typename Ret, typename ...Args
397#ifndef Q_QDOC
398 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
399#endif
400 >
401 static QJniObject callStaticObjectMethod(const char *className, const char *methodName, Args &&...args)
402 {
403 QtJniTypes::assertObjectType<Ret>();
404 constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
405 LocalFrame<QJniObject, Args...> frame;
406 return frame.template convertFromJni<Ret>(callStaticObjectMethod(className, methodName, signature.data(),
407 frame.convertToJni(std::forward<Args>(args))...));
408 }
409
410 template <typename Ret, typename ...Args
411#ifndef Q_QDOC
412 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
413#endif
414 >
415 static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName, Args &&...args)
416 {
417 QtJniTypes::assertObjectType<Ret>();
418 constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
419 LocalFrame<QJniObject, Args...> frame;
420 return frame.template convertFromJni<Ret>(callStaticObjectMethod(clazz, methodName, signature.data(),
421 frame.convertToJni(std::forward<Args>(args))...));
422 }
423
424 template <typename Type
425#ifndef Q_QDOC
426 , QtJniTypes::IfValidFieldType<Type> = true
427#endif
428 >
429 auto getField(const char *fieldName) const
430 {
431 using T = typename QtJniTypes::Detail::CallerHandlesException<Type>::value_type;
432 LocalFrame<Type, T> frame(jniEnv());
433 constexpr auto signature = QtJniTypes::fieldSignature<T>();
434 jfieldID id = getCachedFieldID(frame.jniEnv(), fieldName, signature);
435
436 if constexpr (QtJniTypes::isObjectType<T>()) {
437 return frame.makeResult(frame.template convertFromJni<T>(getObjectFieldImpl(
438 frame.jniEnv(), id))
439 );
440 } else {
441 T res{};
442 if (id)
443 getFieldForType<T>(frame.jniEnv(), res, object(), id);
444 return frame.makeResult(res);
445 }
446 }
447
448 template <typename Klass, typename T
449#ifndef Q_QDOC
450 , QtJniTypes::IfValidFieldType<T> = true
451#endif
452 >
453 static auto getStaticField(const char *fieldName)
454 {
455 return getStaticField<T>(QtJniTypes::Traits<Klass>::className(), fieldName);
456 }
457
458 template <typename T
459#ifndef Q_QDOC
460 , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true
461#endif
462 >
463 QJniObject getObjectField(const char *fieldName) const
464 {
465 constexpr auto signature = QtJniTypes::fieldSignature<T>();
466 return getObjectField(fieldName, signature);
467 }
468
469 QJniObject getObjectField(const char *fieldName, const char *signature) const;
470
471 template <typename Type
472#ifndef Q_QDOC
473 , QtJniTypes::IfValidFieldType<Type> = true
474#endif
475 >
476 static auto getStaticField(const char *className, const char *fieldName)
477 {
478 using T = typename QtJniTypes::Detail::CallerHandlesException<Type>::value_type;
479 LocalFrame<Type, T> frame;
480 jclass clazz = QJniObject::loadClass(className, frame.jniEnv());
481 return getStaticField<Type>(clazz, fieldName);
482 }
483
484 template <typename Type
485#ifndef Q_QDOC
486 , QtJniTypes::IfValidFieldType<Type> = true
487#endif
488 >
489 static auto getStaticField(jclass clazz, const char *fieldName)
490 {
491 using T = typename QtJniTypes::Detail::CallerHandlesException<Type>::value_type;
492 LocalFrame<Type, T> frame;
493 constexpr auto signature = QtJniTypes::fieldSignature<T>();
494 jfieldID id = clazz ? getFieldID(frame.jniEnv(), clazz, fieldName, signature, true)
495 : nullptr;
496 if constexpr (QtJniTypes::isObjectType<T>()) {
497 return frame.makeResult(frame.template convertFromJni<T>(getStaticObjectFieldImpl(
498 frame.jniEnv(), clazz, id))
499 );
500 } else {
501 T res{};
502 if (id)
503 getStaticFieldForType<T>(frame.jniEnv(), res, clazz, id);
504 return frame.makeResult(res);
505 }
506 }
507
508 template <typename T
509#ifndef Q_QDOC
510 , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true
511#endif
512 >
513 static QJniObject getStaticObjectField(const char *className, const char *fieldName)
514 {
515 constexpr auto signature = QtJniTypes::fieldSignature<T>();
516 return getStaticObjectField(className, fieldName, signature);
517 }
518
519 static QJniObject getStaticObjectField(const char *className,
520 const char *fieldName,
521 const char *signature);
522
523 template <typename T
524#ifndef Q_QDOC
525 , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true
526#endif
527 >
528 static QJniObject getStaticObjectField(jclass clazz, const char *fieldName)
529 {
530 constexpr auto signature = QtJniTypes::fieldSignature<T>();
531 return getStaticObjectField(clazz, fieldName, signature);
532 }
533
534 static QJniObject getStaticObjectField(jclass clazz, const char *fieldName,
535 const char *signature);
536
537 template <typename Ret = void, typename Type
538#ifndef Q_QDOC
539 , QtJniTypes::IfValidFieldType<Type> = true
540#endif
541 >
542 auto setField(const char *fieldName, Type value)
543 {
544 // handle old code that explicitly specifies the field type (i.e. Ret != void)
545 using T = std::conditional_t<std::is_void_v<Ret> || QtJniTypes::Detail::callerHandlesException<Ret>,
546 Type, Ret>;
547 LocalFrame<Ret, T> frame(jniEnv());
548 constexpr auto signature = QtJniTypes::fieldSignature<T>();
549 jfieldID id = getCachedFieldID(jniEnv(), fieldName, signature);
550 if (id)
551 setFieldForType<T>(jniEnv(), object(), id, value);
552 return frame.makeResult();
553 }
554
555 template <typename Ret = void, typename Type
556#ifndef Q_QDOC
557 , QtJniTypes::IfValidFieldType<Type> = true
558#endif
559 >
560 auto setField(const char *fieldName, const char *signature, Type value)
561 {
562 // handle old code that explicitly specifies the field type (i.e. Ret != void)
563 using T = std::conditional_t<std::is_void_v<Ret> || QtJniTypes::Detail::callerHandlesException<Ret>,
564 Type, Ret>;
565 LocalFrame<Ret, T> frame(jniEnv());
566 jfieldID id = getCachedFieldID(frame.jniEnv(), fieldName, signature);
567 if (id)
568 setFieldForType<T>(jniEnv(), object(), id, value);
569 return frame.makeResult();
570 }
571
572 template <typename Ret = void, typename Type
573#ifndef Q_QDOC
574 , QtJniTypes::IfValidFieldType<Type> = true
575#endif
576 >
577 static auto setStaticField(const char *className, const char *fieldName, Type value)
578 {
579 // handle old code that explicitly specifies the field type (i.e. Ret != void)
580 using T = std::conditional_t<std::is_void_v<Ret> || QtJniTypes::Detail::callerHandlesException<Ret>,
581 Type, Ret>;
582 LocalFrame<Ret, T> frame;
583 if (jclass clazz = QJniObject::loadClass(className, frame.jniEnv())) {
584 constexpr auto signature = QtJniTypes::fieldSignature<q20::remove_cvref_t<T>>();
585 jfieldID id = getCachedFieldID(frame.jniEnv(), clazz, className, fieldName,
586 signature, true);
587 if (id)
588 setStaticFieldForType<T>(frame.jniEnv(), clazz, id, value);
589 }
590 return frame.makeResult();
591 }
592
593 template <typename Ret = void, typename Type
594#ifndef Q_QDOC
595 , QtJniTypes::IfValidFieldType<Type> = true
596#endif
597 >
598 static auto setStaticField(const char *className, const char *fieldName,
599 const char *signature, Type value)
600 {
601 // handle old code that explicitly specifies the field type (i.e. Ret != void)
602 using T = std::conditional_t<std::is_void_v<Ret> || QtJniTypes::Detail::callerHandlesException<Ret>,
603 Type, Ret>;
604 LocalFrame<Ret, T> frame;
605 if (jclass clazz = QJniObject::loadClass(className, frame.jniEnv())) {
606 jfieldID id = getCachedFieldID(frame.jniEnv(), clazz, className, fieldName,
607 signature, true);
608 if (id)
609 setStaticFieldForType<T>(frame.jniEnv(), clazz, id, value);
610 }
611 return frame.makeResult();
612 }
613
614 template <typename Ret = void, typename Type
615#ifndef Q_QDOC
616 , QtJniTypes::IfValidFieldType<Type> = true
617#endif
618 >
619 static auto setStaticField(jclass clazz, const char *fieldName,
620 const char *signature, Type value)
621 {
622 // handle old code that explicitly specifies the field type (i.e. Ret != void)
623 using T = std::conditional_t<std::is_void_v<Ret> || QtJniTypes::Detail::callerHandlesException<Ret>,
624 Type, Ret>;
625 LocalFrame<Ret, T> frame;
626 jfieldID id = getFieldID(frame.jniEnv(), clazz, fieldName, signature, true);
627
628 if (id)
629 setStaticFieldForType<T>(frame.jniEnv(), clazz, id, value);
630 return frame.makeResult();
631 }
632
633 template <typename Ret = void, typename Type
634#ifndef Q_QDOC
635 , QtJniTypes::IfValidFieldType<Type> = true
636#endif
637 >
638 static auto setStaticField(jclass clazz, const char *fieldName, Type value)
639 {
640 return setStaticField<Ret, Type>(clazz, fieldName,
641 QtJniTypes::fieldSignature<q20::remove_cvref_t<Type>>(),
642 value);
643 }
644
645 template <typename Klass, typename Ret = void, typename Type
646#ifndef Q_QDOC
647 , QtJniTypes::IfValidFieldType<Type> = true
648#endif
649 >
650 static auto setStaticField(const char *fieldName, Type value)
651 {
652 return setStaticField<Ret, Type>(QtJniTypes::Traits<Klass>::className(), fieldName, value);
653 }
654
655 static QJniObject fromString(const QString &string);
656 QString toString() const;
657
658 static bool isClassAvailable(const char *className);
659 bool isValid() const;
660
661 // This function takes ownership of the jobject and releases the local ref. before returning.
662 static QJniObject fromLocalRef(jobject lref);
663
664 template <typename T,
665 std::enable_if_t<std::is_convertible_v<T, jobject>, bool> = true>
666 QJniObject &operator=(T obj)
667 {
668 assign(static_cast<T>(obj));
669 return *this;
670 }
671
672protected:
673 QJniObject(Qt::Initialization) {}
674 JNIEnv *jniEnv() const noexcept;
675
676private:
677 static jclass loadClass(const QByteArray &className, JNIEnv *env);
678 static jclass loadClassKeepExceptions(const QByteArray &className, JNIEnv *env);
679
680#if QT_CORE_REMOVED_SINCE(6, 7)
681 // these need to stay in the ABI as they were used in inline methods before 6.7
682 static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded);
683 static QByteArray toBinaryEncClassName(const QByteArray &className);
684 void callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const;
685#endif
686
687 static jfieldID getCachedFieldID(JNIEnv *env, jclass clazz, const QByteArray &className,
688 const char *name, const char *signature,
689 bool isStatic = false);
690 jfieldID getCachedFieldID(JNIEnv *env, const char *name, const char *signature,
691 bool isStatic = false) const;
692 static jmethodID getCachedMethodID(JNIEnv *env, jclass clazz, const QByteArray &className,
693 const char *name, const char *signature,
694 bool isStatic = false);
695 jmethodID getCachedMethodID(JNIEnv *env, const char *name, const char *signature,
696 bool isStatic = false) const;
697
698 static jfieldID getFieldID(JNIEnv *env, jclass clazz, const char *name,
699 const char *signature, bool isStatic = false);
700 static jmethodID getMethodID(JNIEnv *env, jclass clazz, const char *name,
701 const char *signature, bool isStatic = false);
702
703 void callVoidMethodV(JNIEnv *env, jmethodID id, ...) const;
704
705 bool isSameObject(jobject obj) const;
706 bool isSameObject(const QJniObject &other) const;
707 void assign(jobject obj);
708 jobject javaObject() const;
709
710 friend bool operator==(const QJniObject &, const QJniObject &);
711 friend bool operator!=(const QJniObject&, const QJniObject&);
712
713 template<typename T>
714 static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, jmethodID id, ...)
715 {
716 if (!id)
717 return;
718
719 va_list args = {};
720 va_start(args, id);
721 QtJniTypes::Caller<T>::callMethodForType(env, res, obj, id, args);
722 va_end(args);
723 }
724
725 jobject callObjectMethodImpl(jmethodID method, ...) const
726 {
727 va_list args;
728 va_start(args, method);
729 jobject res = method ? jniEnv()->CallObjectMethodV(javaObject(), method, args)
730 : nullptr;
731 va_end(args);
732 return res;
733 }
734
735 template<typename T>
736 static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz,
737 jmethodID id, ...)
738 {
739 if (!clazz || !id)
740 return;
741 va_list args = {};
742 va_start(args, id);
743 QtJniTypes::Caller<T>::callStaticMethodForType(env, res, clazz, id, args);
744 va_end(args);
745 }
746
747 static void callStaticMethodForVoid(JNIEnv *env, jclass clazz, jmethodID id, ...)
748 {
749 if (!clazz || !id)
750 return;
751 va_list args;
752 va_start(args, id);
753 env->CallStaticVoidMethodV(clazz, id, args);
754 va_end(args);
755 }
756
757
758 template<typename T>
759 static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id)
760 {
761 if (!id)
762 return;
763
764 QtJniTypes::Caller<T>::getFieldForType(env, res, obj, id);
765 }
766
767 template<typename T>
768 static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, jfieldID id)
769 {
770 QtJniTypes::Caller<T>::getStaticFieldForType(env, res, clazz, id);
771 }
772
773 template<typename Type>
774 static constexpr void setFieldForType(JNIEnv *env, jobject obj, jfieldID id, Type value)
775 {
776 if (!id)
777 return;
778
779 using T = q20::remove_cvref_t<Type>;
780 if constexpr (QtJniTypes::isObjectType<T>()) {
781 LocalFrame<T, T> frame(env);
782 env->SetObjectField(obj, id, static_cast<jobject>(frame.convertToJni(value)));
783 } else {
784 using ValueType = typename QtJniTypes::Detail::CallerHandlesException<T>::value_type;
785 QtJniTypes::Caller<ValueType>::setFieldForType(env, obj, id, value);
786 }
787 }
788
789 jobject getObjectFieldImpl(JNIEnv *env, jfieldID field) const
790 {
791 return field ? env->GetObjectField(javaObject(), field) : nullptr;
792 }
793
794 static jobject getStaticObjectFieldImpl(JNIEnv *env, jclass clazz, jfieldID field)
795 {
796 return clazz && field ? env->GetStaticObjectField(clazz, field)
797 : nullptr;
798 }
799
800 template<typename Type>
801 static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz, jfieldID id, Type value)
802 {
803 if (!clazz || !id)
804 return;
805
806 using T = q20::remove_cvref_t<Type>;
807 if constexpr (QtJniTypes::isObjectType<T>()) {
808 LocalFrame<T, T> frame(env);
809 env->SetStaticObjectField(clazz, id, static_cast<jobject>(frame.convertToJni(value)));
810 } else {
811 QtJniTypes::Caller<T>::setStaticFieldForType(env, clazz, id, value);
812 }
813 }
814
815 friend QJniObjectPrivate;
816 QSharedPointer<QJniObjectPrivate> d;
817};
818
819inline bool operator==(const QJniObject &obj1, const QJniObject &obj2)
820{
821 return obj1.isSameObject(obj2);
822}
823
824inline bool operator!=(const QJniObject &obj1, const QJniObject &obj2)
825{
826 return !obj1.isSameObject(obj2);
827}
828
829namespace QtJniTypes {
830struct JObjectBase
831{
832 operator QJniObject() const { return m_object; }
833
834 bool isValid() const { return m_object.isValid(); }
835 jclass objectClass() const { return m_object.objectClass(); }
836 QString toString() const { return m_object.toString(); }
837
838 template <typename T = jobject>
839 T object() const {
840 return m_object.object<T>();
841 }
842
843protected:
844 JObjectBase() = default;
845 JObjectBase(const JObjectBase &) = default;
846 JObjectBase(JObjectBase &&) = default;
847 JObjectBase &operator=(const JObjectBase &) = default;
848 JObjectBase &operator=(JObjectBase &&) = default;
849 ~JObjectBase() = default;
850
851 Q_IMPLICIT JObjectBase(jobject object) : m_object(object) {}
852 Q_IMPLICIT JObjectBase(const QJniObject &object) : m_object(object) {}
853 Q_IMPLICIT JObjectBase(QJniObject &&object) noexcept : m_object(std::move(object)) {}
854
855 QJniObject m_object;
856};
857
858template<typename Type>
859class JObject : public JObjectBase
860{
861public:
862 using Class = Type;
863
864 JObject()
865 : JObjectBase{QJniObject(QtJniTypes::Traits<Class>::className())}
866 {}
867 Q_IMPLICIT JObject(jobject object) : JObjectBase(object) {}
868 Q_IMPLICIT JObject(const QJniObject &object) : JObjectBase(object) {}
869 Q_IMPLICIT JObject(QJniObject &&object) noexcept : JObjectBase(std::move(object)) {}
870
871 // base class SMFs are protected, make them public:
872 JObject(const JObject &other) = default;
873 JObject(JObject &&other) noexcept = default;
874 JObject &operator=(const JObject &other) = default;
875 JObject &operator=(JObject &&other) noexcept = default;
876
877 ~JObject() = default;
878
879 template<typename Arg, typename ...Args
880 , std::enable_if_t<!std::is_same_v<q20::remove_cvref_t<Arg>, JObject>, bool> = true
881 , IfValidSignatureTypes<Arg, Args...> = true
882 >
883 explicit JObject(Arg && arg, Args &&...args)
884 : JObjectBase{QJniObject(QtJniTypes::Traits<Class>::className(),
885 std::forward<Arg>(arg), std::forward<Args>(args)...)}
886 {}
887
888 // named constructors avoid ambiguities
889 static JObject fromJObject(jobject object)
890 {
891 return JObject(object);
892 }
893 template <typename ...Args>
894 static JObject construct(Args &&...args)
895 {
896 return JObject(std::forward<Args>(args)...);
897 }
898 static JObject fromLocalRef(jobject lref)
899 {
900 return JObject(QJniObject::fromLocalRef(lref));
901 }
902
903#ifdef Q_QDOC // from JObjectBase, which we don't document
904 bool isValid() const;
905 jclass objectClass() const;
906 QString toString() const;
907 template <typename T = jobject> object() const;
908#endif
909
910 static bool registerNativeMethods(std::initializer_list<JNINativeMethod> methods)
911 {
912 QJniEnvironment env;
913 return env.registerNativeMethods<Class>(methods);
914 }
915
916 // public API forwarding to QJniObject, with the implicit Class template parameter
917 template <typename Ret = void, typename ...Args
918#ifndef Q_QDOC
919 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
920#endif
921 >
922 static auto callStaticMethod(const char *name, Args &&...args)
923 {
924 return QJniObject::callStaticMethod<Class, Ret, Args...>(name,
925 std::forward<Args>(args)...);
926 }
927 template <typename T
928#ifndef Q_QDOC
929 , QtJniTypes::IfValidFieldType<T> = true
930#endif
931 >
932 static auto getStaticField(const char *field)
933 {
934 return QJniObject::getStaticField<Class, T>(field);
935 }
936 template <typename Ret = void, typename T
937#ifndef Q_QDOC
938 , QtJniTypes::IfValidFieldType<T> = true
939#endif
940 >
941 static auto setStaticField(const char *field, T &&value)
942 {
943 return QJniObject::setStaticField<Class, Ret, T>(field, std::forward<T>(value));
944 }
945
946 // keep only these overloads, the rest is made private
947 template <typename Ret = void, typename ...Args
948#ifndef Q_QDOC
949 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
950#endif
951 >
952 auto callMethod(const char *method, Args &&...args) const
953 {
954 return m_object.callMethod<Ret>(method, std::forward<Args>(args)...);
955 }
956 template <typename T
957#ifndef Q_QDOC
958 , QtJniTypes::IfValidFieldType<T> = true
959#endif
960 >
961 auto getField(const char *fieldName) const
962 {
963 return m_object.getField<T>(fieldName);
964 }
965
966 template <typename Ret = void, typename T
967#ifndef Q_QDOC
968 , QtJniTypes::IfValidFieldType<T> = true
969#endif
970 >
971 auto setField(const char *fieldName, T &&value)
972 {
973 return m_object.setField<Ret>(fieldName, std::forward<T>(value));
974 }
975
976 QByteArray className() const {
977 return QtJniTypes::Traits<Class>::className().data();
978 }
979
980 static bool isClassAvailable()
981 {
982 return QJniObject::isClassAvailable(QtJniTypes::Traits<Class>::className().data());
983 }
984
985private:
986 friend bool comparesEqual(const JObject &lhs, const JObject &rhs)
987 { return lhs.m_object == rhs.m_object; }
988 Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(JObject);
989};
990
991template <typename T> struct Traits<JObject<T>> {
992 static constexpr auto signature() { return Traits<T>::signature(); }
993 static constexpr auto className() { return Traits<T>::className(); }
994 static auto convertToJni(JNIEnv *, const JObject<T> &value)
995 {
996 return value.object();
997 }
998 static auto convertFromJni(QJniObject &&object)
999 {
1000 return JObject<T>(std::move(object));
1001 }
1002};
1003
1004template<>
1005struct Traits<QJniObject>
1006{
1007 static constexpr auto className()
1008 {
1009 return CTString("java/lang/Object");
1010 }
1011
1012 static constexpr auto signature()
1013 {
1014 return CTString("Ljava/lang/Object;");
1015 }
1016
1017 static auto convertToJni(JNIEnv *, const QJniObject &value)
1018 {
1019 return value.object();
1020 }
1021 static auto convertFromJni(QJniObject &&object)
1022 {
1023 return std::move(object);
1024 }
1025};
1026
1027template<>
1028struct Traits<QString>
1029{
1030 static constexpr auto className()
1031 {
1032 return CTString("java/lang/String");
1033 }
1034 static constexpr auto signature()
1035 {
1036 return CTString("Ljava/lang/String;");
1037 }
1038
1039 static auto convertToJni(JNIEnv *env, const QString &value)
1040 {
1041 return QtJniTypes::Detail::fromQString(value, env);
1042 }
1043
1044 static auto convertFromJni(QJniObject &&object)
1045 {
1046 return object.toString();
1047 }
1048};
1049
1050template <typename T>
1051struct Traits<T, std::enable_if_t<QtJniTypes::Detail::callerHandlesException<T>>>
1052{
1053 static constexpr auto className()
1054 {
1055 return Traits<typename T::value_type>::className();
1056 }
1057
1058 static constexpr auto signature()
1059 {
1060 return Traits<typename T::value_type>::signature();
1061 }
1062};
1063
1064}
1065
1066template <typename ReturnType, typename ...Args>
1067template <typename T>
1068auto QtJniTypes::Detail::LocalFrameWithReturn<ReturnType, Args...>::convertFromJni(jobject object)
1069{
1070 // If the caller wants to handle exceptions through a std::expected-like
1071 // type, then we cannot turn the jobject into a QJniObject, as a
1072 // std::expected<jobject, jthrowable> cannot be constructed from a QJniObject.
1073 // The caller will have to take care of this themselves, by asking for a
1074 // std::expected<QJniObject, ...>, or (typically) using a declared JNI class
1075 // or implicitly supported Qt type (QString or array type).
1076 if constexpr (callerHandlesException<ReturnType> &&
1077 std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>)
1078 return static_cast<T>(object);
1079 else
1080 return convertFromJni<T>(object ? QJniObject::fromLocalRef(object) : QJniObject());
1081}
1082
1083QT_END_NAMESPACE
1084
1085#endif
1086
1087#endif // QJNIOBJECT_H
\inmodule QtCore
Definition qmutex.h:346
\preliminary \inmodule QtCorePrivate
Q_CORE_EXPORT void unregisterNewIntentListener(NewIntentListener *listener)
Q_CORE_EXPORT int acuqireServiceSetup(int flags)
Q_CORE_EXPORT void registerNewIntentListener(NewIntentListener *listener)
Q_CORE_EXPORT void unregisterResumePauseListener(ResumePauseListener *listener)
Q_CORE_EXPORT void unregisterGenericMotionEventListener(GenericMotionEventListener *listener)
Q_CORE_EXPORT bool acquireAndroidDeadlockProtector()
Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener)
Q_CORE_EXPORT void handleResume()
Q_CORE_EXPORT void registerResumePauseListener(ResumePauseListener *listener)
Q_CORE_EXPORT void releaseAndroidDeadlockProtector()
Q_CORE_EXPORT void handleNewIntent(JNIEnv *env, jobject intent)
Q_CORE_EXPORT void setOnBindListener(OnBindListener *listener)
Q_CORE_EXPORT void registerKeyEventListener(KeyEventListener *listener)
Q_CORE_EXPORT void handlePause()
Q_CORE_EXPORT bool isUncompressedNativeLibs()
Q_CORE_EXPORT void unregisterActivityResultListener(ActivityResultListener *listener)
Q_CORE_EXPORT void registerGenericMotionEventListener(GenericMotionEventListener *listener)
Q_CORE_EXPORT void handleActivityResult(jint requestCode, jint resultCode, jobject data)
Q_CORE_EXPORT void waitForServiceSetup()
jobject classLoader()
Q_CORE_EXPORT void registerActivityResultListener(ActivityResultListener *listener)
Q_GLOBAL_STATIC(DefaultRoleNames, qDefaultRoleNames, { { Qt::DisplayRole, "display" }, { Qt::DecorationRole, "decoration" }, { Qt::EditRole, "edit" }, { Qt::ToolTipRole, "toolTip" }, { Qt::StatusTipRole, "statusTip" }, { Qt::WhatsThisRole, "whatsThis" }, }) const QHash< int
Q_DECLARE_JNI_NATIVE_METHOD(dispatchKeyEvent)
Q_DECLARE_JNI_NATIVE_METHOD(dispatchGenericMotionEvent)
static jobject g_jClassLoader
static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, QtJniTypes::MotionEvent event)
static JavaVM * g_javaVM
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
static jobject g_jActivity
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")
static jboolean updateNativeActivity(JNIEnv *env, jclass=nullptr)
static jboolean dispatchKeyEvent(JNIEnv *, jclass, QtJniTypes::KeyEvent event)
static jobject g_jService