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