1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #include "JavaReferencesCache.h"
4 
5 namespace expo {
6 std::shared_ptr<JavaReferencesCache> JavaReferencesCache::instance() {
7   static std::shared_ptr<JavaReferencesCache> singleton{new JavaReferencesCache};
8   return singleton;
9 }
10 
11 void JavaReferencesCache::loadJClasses(JNIEnv *env) {
12   loadJClass(env, "java/lang/Double", {
13     {"<init>", "(D)V"}
14   });
15 
16   loadJClass(env, "java/lang/Boolean", {
17     {"<init>", "(Z)V"}
18   });
19 
20   loadJClass(env, "com/facebook/react/bridge/PromiseImpl", {
21     {"<init>", "(Lcom/facebook/react/bridge/Callback;Lcom/facebook/react/bridge/Callback;)V"}
22   });
23 
24   loadJClass(env, "java/lang/Object", {});
25 }
26 
27 void JavaReferencesCache::loadJClass(
28   JNIEnv *env,
29   const std::string &name,
30   const std::vector<std::pair<std::string, std::string>> &methodsNames
31 ) {
32   // Note this clazz variable points to a leaked global reference.
33   // This is appropriate for classes that are never unloaded which is any class in an Android app.
34   auto clazz = (jclass) env->NewGlobalRef(env->FindClass(name.c_str()));
35 
36   MethodHashMap methods;
37   methods.reserve(methodsNames.size());
38 
39   for (auto &method: methodsNames) {
40     methods.insert(
41       {method, env->GetMethodID(clazz, method.first.c_str(), method.second.c_str())}
42     );
43   }
44 
45   jClassRegistry.insert(
46     {name, CachedJClass(clazz, std::move(methods))}
47   );
48 }
49 
50 JavaReferencesCache::CachedJClass &JavaReferencesCache::getJClass(
51   const std::string &className
52 ) {
53   return jClassRegistry.at(className);
54 }
55 
56 jmethodID JavaReferencesCache::CachedJClass::getMethod(
57   const std::string &name,
58   const std::string &signature
59 ) {
60   return methods.at({name, signature});
61 }
62 
63 JavaReferencesCache::CachedJClass::CachedJClass(
64   jclass clazz,
65   MethodHashMap methods
66 ) : clazz(clazz), methods(std::move(methods)) {}
67 } // namespace expo
68