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 jsi::Value makeCodedError( 50 jsi::Runtime &rt, 51 jsi::String code, 52 jsi::String message 53 ) { 54 auto codedErrorConstructor = rt 55 .global() 56 .getProperty(rt, "ExpoModulesCore_CodedError") 57 .asObject(rt) 58 .asFunction(rt); 59 60 return codedErrorConstructor.callAsConstructor( 61 rt, { 62 jsi::Value(rt, code), 63 jsi::Value(rt, message) 64 } 65 ); 66 } 67 68 void rethrowAsCodedError( 69 jsi::Runtime &rt, 70 jni::JniException &jniException 71 ) { 72 jni::local_ref<jni::JThrowable> unboxedThrowable = jniException.getThrowable(); 73 if (unboxedThrowable->isInstanceOf(CodedException::javaClassLocal())) { 74 auto codedException = jni::static_ref_cast<CodedException>(unboxedThrowable); 75 auto code = codedException->getCode(); 76 auto message = codedException->getLocalizedMessage(); 77 78 auto codedError = makeCodedError( 79 rt, 80 jsi::String::createFromUtf8(rt, code), 81 jsi::String::createFromUtf8(rt, message.value_or("")) 82 ); 83 84 throw jsi::JSError( 85 message.value_or(""), 86 rt, 87 std::move(codedError) 88 ); 89 } 90 91 // Rethrow error if we can't wrap it. 92 throw; 93 } 94 95 void throwPendingJniExceptionAsCppException() { 96 JNIEnv* env = jni::Environment::current(); 97 if (env->ExceptionCheck() == JNI_FALSE) { 98 return; 99 } 100 101 auto throwable = env->ExceptionOccurred(); 102 if (!throwable) { 103 throw std::runtime_error("Unable to get pending JNI exception."); 104 } 105 env->ExceptionClear(); 106 107 throw jni::JniException(jni::adopt_local(throwable)); 108 } 109 110 void throwNewJavaException(jthrowable throwable) { 111 throw jni::JniException(jni::wrap_alias(throwable)); 112 } 113 114 } // namespace expo 115