1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #pragma once
4 
5 #include <fbjni/fbjni.h>
6 #include <jsi/jsi.h>
7 
8 #include <optional>
9 
10 namespace jni = facebook::jni;
11 namespace jsi = facebook::jsi;
12 
13 namespace expo {
14 
15 class JSIInteropModuleRegistry;
16 
17 /**
18  * A convenient wrapper for the Kotlin CodedException.
19  * It can be used with the `jni::throwNewJavaException` function to throw a cpp exception that
20  * will be automatically changed to the corresponding Java/Kotlin exception.
21  * `jni::throwNewJavaException` creates and throws a C++ exception which wraps a Java exception,
22  * so the C++ flow is interrupted. Then, when translatePendingCppExceptionToJavaException
23  * is called at the topmost level of the native stack, the wrapped Java exception is thrown to the java caller.
24  */
25 class CodedException : public jni::JavaClass<CodedException, jni::JThrowable> {
26 public:
27   static auto constexpr kJavaDescriptor = "Lexpo/modules/kotlin/exception/CodedException;";
28 
29   static jni::local_ref<CodedException> create(const std::string &message);
30 
31   std::string getCode();
32 
33   std::optional<std::string> getLocalizedMessage();
34 };
35 
36 /**
37  * A convenient wrapper for the Kotlin JavaScriptEvaluateException.
38  */
39 class JavaScriptEvaluateException
40   : public jni::JavaClass<JavaScriptEvaluateException, CodedException> {
41 public:
42   static auto constexpr kJavaDescriptor = "Lexpo/modules/kotlin/exception/JavaScriptEvaluateException;";
43 
44   static jni::local_ref<JavaScriptEvaluateException> create(
45     const std::string &message,
46     const std::string &jsStack
47   );
48 };
49 
50 /**
51  * A convenient wrapper for the Kotlin UnexpectedException.
52  */
53 class UnexpectedException
54   : public jni::JavaClass<UnexpectedException, CodedException> {
55 public:
56   static auto constexpr kJavaDescriptor = "Lexpo/modules/kotlin/exception/UnexpectedException;";
57 
58   static jni::local_ref<UnexpectedException> create(
59     const std::string &message
60   );
61 };
62 
63 class InvalidArgsNumberException
64 : public jni::JavaClass<InvalidArgsNumberException, CodedException> {
65 public:
66   static auto constexpr kJavaDescriptor = "Lexpo/modules/kotlin/exception/InvalidArgsNumberException;";
67 
68   static jni::local_ref<InvalidArgsNumberException> create(
69     int received,
70     int expected
71   );
72 };
73 
74 /**
75  * Tries to rethrow an jni::JniException as a js version of the CodedException
76  */
77 [[noreturn]] void rethrowAsCodedError(
78   jsi::Runtime &rt,
79   jni::JniException &jniException
80 );
81 
82 jsi::Value makeCodedError(
83   jsi::Runtime &runtime,
84   jsi::String code,
85   jsi::String message
86 );
87 
88 /**
89  * [email protected] is built by ndk r21, its exceptions are not catchable by expo-modules-core built by ndk r23+.
90  * To catch these excetptions, we copy the `facebook::jni::throwPendingJniExceptionAsCppException` here and throw exceptions on our own.
91  */
92 void throwPendingJniExceptionAsCppException();
93 
94 /**
95  * Same as `facebook::jni::throwNewJavaException` but throwing exceptions on our own.
96  */
97 [[noreturn]] void throwNewJavaException(jthrowable throwable);
98 } // namespace expo
99