55
66#include < string>
77
8+ #include " app/meta/move.h"
9+ #include " firestore/src/jni/call_traits.h"
10+ #include " firestore/src/jni/class.h"
811#include " firestore/src/jni/object.h"
912#include " firestore/src/jni/ownership.h"
1013#include " firestore/src/jni/string.h"
@@ -14,6 +17,9 @@ namespace firebase {
1417namespace firestore {
1518namespace jni {
1619
20+ // Since we're targeting STLPort, `std::invoke` is not available.
21+ #define INVOKE (env, method, ...) ((env)->*(method))(__VA_ARGS__);
22+
1723/* *
1824 * A wrapper around a JNIEnv pointer that makes dealing with JNI simpler in C++,
1925 * by:
@@ -42,6 +48,119 @@ class Env {
4248 /* * Returns the underlying JNIEnv pointer. */
4349 JNIEnv* get () const { return env_; }
4450
51+ // MARK: Class Operations
52+
53+ /* *
54+ * Finds the java class associated with the given name which should be
55+ * formatted like "java/lang/Object".
56+ */
57+ Local<Class> FindClass (const char * name);
58+
59+ // MARK: Object Operations
60+
61+ /* *
62+ * Creates a new Java object of the given class, returning the result in a
63+ * reference wrapper of type T.
64+ *
65+ * @tparam T The C++ type to which the method should be coerced.
66+ * @tparam Args The C++ types of the arguments to the method.
67+ * @param clazz The Java class of the resulting object.
68+ * @param method The constructor method to invoke.
69+ * @param args The C++ arguments of the constructor. These will be converted
70+ * to their JNI equivalent value with a call to ToJni before invocation.
71+ * @return a local reference to the newly-created object.
72+ */
73+ template <typename T = Object, typename ... Args>
74+ Local<T> New (const Class& clazz, jmethodID method, Args&&... args) {
75+ if (!ok ()) return {};
76+
77+ jobject result =
78+ env_->NewObject (clazz.get (), method, ToJni (Forward<Args>(args))...);
79+ RecordException ();
80+ return MakeResult<T>(result);
81+ }
82+
83+ // MARK: Calling Instance Methods
84+
85+ /* *
86+ * Finds the method on the given class that's associated with the method name
87+ * and signature.
88+ */
89+ jmethodID GetMethodId (const Class& clazz, const char * name, const char * sig);
90+
91+ /* *
92+ * Invokes the JNI instance method using the `Call*Method` appropriate to the
93+ * return type T.
94+ *
95+ * @tparam T The C++ return type to which the method should be coerced.
96+ * @param object The object to use as `this` for the invocation.
97+ * @param method The method to invoke.
98+ * @param args The C++ arguments of the method. These will be converted to
99+ * their JNI equivalent value with a call to ToJni before invocation.
100+ * @return The primitive result if T is a primitive, nothing if T is `void`,
101+ * or a local reference to the returned object.
102+ */
103+ template <typename T, typename ... Args>
104+ ResultType<T> Call (const Object& object, jmethodID method, Args&&... args) {
105+ auto env_method = CallTraits<JniType<T>>::kCall ;
106+ return CallHelper<T>(env_method, object.get (), method,
107+ ToJni (Forward<Args>(args))...);
108+ }
109+
110+ // MARK: Accessing Static Fields
111+
112+ jfieldID GetStaticFieldId (const Class& clazz, const char * name,
113+ const char * sig);
114+
115+ /* *
116+ * Returns the value of the given field using the GetStatic*Field method
117+ * appropriate to the field type T.
118+ *
119+ * @tparam T The C++ type to which the field value should be coerced.
120+ * @param clazz The class to use as the container for the field.
121+ * @param field The field to get.
122+ * @return a local reference to the field value.
123+ */
124+ template <typename T = Object>
125+ ResultType<T> GetStaticField (const Class& clazz, jfieldID field) {
126+ if (!ok ()) return {};
127+
128+ auto env_method = CallTraits<JniType<T>>::kGetStaticField ;
129+ auto result = INVOKE (env_, env_method, clazz.get (), field);
130+ RecordException ();
131+ return MakeResult<T>(result);
132+ }
133+
134+ // MARK: Calling Static Methods
135+
136+ /* *
137+ * Finds the method on the given class that's associated with the method name
138+ * and signature.
139+ */
140+ jmethodID GetStaticMethodId (const Class& clazz, const char * name,
141+ const char * sig);
142+
143+ /* *
144+ * Invokes the JNI static method using the CallStatic*Method appropriate to
145+ * the return type T.
146+ *
147+ * @tparam T The C++ return type to which the method should be coerced.
148+ * @tparam Args The C++ types of the arguments to the method.
149+ * @param clazz The class against which to invoke the static method.
150+ * @param method The method to invoke.
151+ * @param args The C++ arguments of the method. These will be converted to
152+ * their JNI equivalent value with a call to ToJni before invocation.
153+ * @return The primitive result if T is a primitive, nothing if T is `void`,
154+ * or a local reference to the returned object.
155+ */
156+ template <typename T, typename ... Args>
157+ ResultType<T> CallStatic (const Class& clazz, jmethodID method,
158+ Args&&... args) {
159+ auto env_method = CallTraits<JniType<T>>::kCallStatic ;
160+ return CallHelper<T>(env_method, clazz.get (), method,
161+ ToJni (Forward<Args>(args))...);
162+ }
163+
45164 // MARK: String Operations
46165
47166 /* *
@@ -74,12 +193,66 @@ class Env {
74193 }
75194
76195 private:
196+ /* *
197+ * Invokes the JNI instance method using the given method reference on JNIEnv.
198+ *
199+ * @tparam T The non-void C++ return type to which the method's result should
200+ * be coerced.
201+ * @param env_method A method reference from JNIEnv, appropriate for the
202+ * return type T, and the kind of method being invoked (instance or
203+ * static). Use `CallTraits<JniType<T>>::kCall` or `kCallStatic` to find
204+ * the right method.
205+ * @param args The method and JNI arguments of the JNI method, including the
206+ * class or object, jmethodID, and any arguments to pass.
207+ * @return The primitive result if T is a primitive or a local reference to
208+ * the returned object.
209+ */
210+ template <typename T, typename M, typename ... Args>
211+ typename enable_if<!is_same<T, void >::value, ResultType<T>>::type CallHelper (
212+ M&& env_method, Args&&... args) {
213+ if (!ok ()) return {};
214+
215+ auto result = INVOKE (env_, env_method, Forward<Args>(args)...);
216+ RecordException ();
217+ return MakeResult<T>(result);
218+ }
219+
220+ /* *
221+ * Invokes a JNI call method if the return type is `void`.
222+ *
223+ * If `T` is anything but `void`, the overload is disabled.
224+ */
225+ template <typename T, typename M, typename ... Args>
226+ typename enable_if<is_same<T, void >::value, void >::type CallHelper (
227+ M&& env_method, Args&&... args) {
228+ if (!ok ()) return ;
229+
230+ INVOKE (env_, env_method, Forward<Args>(args)...);
231+ RecordException ();
232+ }
233+
77234 void RecordException ();
78235
236+ template <typename T>
237+ EnableForPrimitive<T, T> MakeResult (JniType<T> value) {
238+ return static_cast <T>(value);
239+ }
240+
241+ template <typename T>
242+ EnableForReference<T, Local<T>> MakeResult (jobject object) {
243+ // JNI object method results are always jobject, even when the actual type
244+ // is jstring or jclass. Cast to the correct type here so that Local<T>
245+ // doesn't have to account for this.
246+ auto typed_object = static_cast <JniType<T>>(object);
247+ return Local<T>(env_, typed_object);
248+ }
249+
79250 JNIEnv* env_ = nullptr ;
80251 jthrowable last_exception_ = nullptr ;
81252};
82253
254+ #undef INVOKE
255+
83256} // namespace jni
84257} // namespace firestore
85258} // namespace firebase
0 commit comments