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 void rethrowAsCodedError(
50   jsi::Runtime &rt,
51   JSIInteropModuleRegistry *registry,
52   jni::JniException &jniException
53 ) {
54   jni::local_ref<jni::JThrowable> unboxedThrowable = jniException.getThrowable();
55   if (unboxedThrowable->isInstanceOf(CodedException::javaClassLocal())) {
56     auto codedException = jni::static_ref_cast<CodedException>(unboxedThrowable);
57     auto code = codedException->getCode();
58     auto message = codedException->getLocalizedMessage();
59 
60     auto *codedErrorPointer = registry->jsRegistry->getOptionalObject<jsi::Function>(
61       JSReferencesCache::JSKeys::CODED_ERROR
62     );
63     if (codedErrorPointer != nullptr) {
64       auto &jsCodedError = *codedErrorPointer;
65 
66       throw jsi::JSError(
67         message.value_or(""),
68         rt,
69         jsCodedError.callAsConstructor(
70           rt,
71           jsi::String::createFromUtf8(rt, code),
72           jsi::String::createFromUtf8(rt, message.value_or(""))
73         )
74       );
75     }
76   }
77 
78   // Rethrow error if we can't wrap it.
79   throw;
80 }
81 } // namespace expo
82