1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo) 2 3 #include "Exceptions.h" 4 5 #include "JSIInteropModuleRegistry.h" 6 #include "JSReferencesCache.h" 7 8 namespace jni = facebook::jni; 9 10 namespace expo { 11 12 jni::local_ref<CodedException> CodedException::create(const std::string &message) { 13 return CodedException::newInstance(jni::make_jstring(message)); 14 } 15 16 std::string CodedException::getCode() { 17 const auto getCode = this->getClass()->getMethod<jni::JString()>("getCode"); 18 const auto code = getCode(this->self()); 19 return code->toStdString(); 20 } 21 22 std::optional<std::string> CodedException::getLocalizedMessage() { 23 const auto getLocalizedMessage = this->getClass() 24 ->getMethod<jni::JString()>("getLocalizedMessage"); 25 const auto message = getLocalizedMessage(this->self()); 26 if (message != nullptr) { 27 return message->toStdString(); 28 } 29 30 return std::nullopt; 31 } 32 33 jni::local_ref<JavaScriptEvaluateException> JavaScriptEvaluateException::create( 34 const std::string &message, 35 const std::string &jsStack 36 ) { 37 return JavaScriptEvaluateException::newInstance( 38 jni::make_jstring(message), 39 jni::make_jstring(jsStack) 40 ); 41 } 42 43 jni::local_ref<UnexpectedException> UnexpectedException::create(const std::string &message) { 44 return UnexpectedException::newInstance( 45 jni::make_jstring(message) 46 ); 47 } 48 49 jni::local_ref<InvalidArgsNumberException> InvalidArgsNumberException::create(int received, int expected) { 50 return InvalidArgsNumberException::newInstance( 51 received, 52 expected, 53 expected // number of required arguments 54 ); 55 } 56 57 jsi::Value makeCodedError( 58 jsi::Runtime &rt, 59 jsi::String code, 60 jsi::String message 61 ) { 62 auto codedErrorConstructor = rt 63 .global() 64 .getProperty(rt, "ExpoModulesCore_CodedError") 65 .asObject(rt) 66 .asFunction(rt); 67 68 return codedErrorConstructor.callAsConstructor( 69 rt, { 70 jsi::Value(rt, code), 71 jsi::Value(rt, message) 72 } 73 ); 74 } 75 76 void rethrowAsCodedError( 77 jsi::Runtime &rt, 78 jni::JniException &jniException 79 ) { 80 jni::local_ref<jni::JThrowable> unboxedThrowable = jniException.getThrowable(); 81 if (unboxedThrowable->isInstanceOf(CodedException::javaClassLocal())) { 82 auto codedException = jni::static_ref_cast<CodedException>(unboxedThrowable); 83 auto code = codedException->getCode(); 84 auto message = codedException->getLocalizedMessage(); 85 86 auto codedError = makeCodedError( 87 rt, 88 jsi::String::createFromUtf8(rt, code), 89 jsi::String::createFromUtf8(rt, message.value_or("")) 90 ); 91 92 throw jsi::JSError( 93 message.value_or(""), 94 rt, 95 std::move(codedError) 96 ); 97 } 98 99 // Rethrow error if we can't wrap it. 100 throw; 101 } 102 103 void throwPendingJniExceptionAsCppException() { 104 JNIEnv* env = jni::Environment::current(); 105 if (env->ExceptionCheck() == JNI_FALSE) { 106 return; 107 } 108 109 auto throwable = env->ExceptionOccurred(); 110 if (!throwable) { 111 throw std::runtime_error("Unable to get pending JNI exception."); 112 } 113 env->ExceptionClear(); 114 115 throw jni::JniException(jni::adopt_local(throwable)); 116 } 117 118 void throwNewJavaException(jthrowable throwable) { 119 throw jni::JniException(jni::wrap_alias(throwable)); 120 } 121 122 } // namespace expo 123