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