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 /**
64  * Tries to rethrow an jni::JniException as a js version of the CodedException
65  */
66 [[noreturn]] void rethrowAsCodedError(
67   jsi::Runtime &rt,
68   jni::JniException &jniException
69 );
70 
71 jsi::Value makeCodedError(
72   jsi::Runtime &runtime,
73   jsi::String code,
74   jsi::String message
75 );
76 
77 /**
78  * [email protected] is built by ndk r21, its exceptions are not catchable by expo-modules-core built by ndk r23+.
79  * To catch these excetptions, we copy the `facebook::jni::throwPendingJniExceptionAsCppException` here and throw exceptions on our own.
80  */
81 void throwPendingJniExceptionAsCppException();
82 
83 /**
84  * Same as `facebook::jni::throwNewJavaException` but throwing exceptions on our own.
85  */
86 [[noreturn]] void throwNewJavaException(jthrowable throwable);
87 } // namespace expo
88