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
create(const std::string & message)12 jni::local_ref<CodedException> CodedException::create(const std::string &message) {
13 return CodedException::newInstance(jni::make_jstring(message));
14 }
15
getCode()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
getLocalizedMessage()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
create(const std::string & message,const std::string & jsStack)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
create(const std::string & message)43 jni::local_ref<UnexpectedException> UnexpectedException::create(const std::string &message) {
44 return UnexpectedException::newInstance(
45 jni::make_jstring(message)
46 );
47 }
48
create(int received,int expected)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
makeCodedError(jsi::Runtime & rt,jsi::String code,jsi::String message)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
rethrowAsCodedError(jsi::Runtime & rt,jni::JniException & jniException)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
throwPendingJniExceptionAsCppException()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
throwNewJavaException(jthrowable throwable)118 void throwNewJavaException(jthrowable throwable) {
119 throw jni::JniException(jni::wrap_alias(throwable));
120 }
121
122 } // namespace expo
123