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