• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Utility class that provides similar calls like JNIEnv, but performs
16 // additional checks on them, so that it's harder to use them incorrectly.
17 
18 #ifndef ICING_TEXT_CLASSIFIER_LIB3_UTILS_JAVA_JNI_HELPER_H_
19 #define ICING_TEXT_CLASSIFIER_LIB3_UTILS_JAVA_JNI_HELPER_H_
20 
21 #include <jni.h>
22 
23 #include <cstdint>
24 #include <string>
25 
26 #include "icing/text_classifier/lib3/utils/base/status.h"
27 #include "icing/text_classifier/lib3/utils/base/statusor.h"
28 #include "icing/text_classifier/lib3/utils/java/jni-base.h"
29 
30 #define TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN             \
31   if (!EnsureLocalCapacity(env, 1)) {                   \
32     TC3_LOG(ERROR) << "EnsureLocalCapacity(1) failed."; \
33     return {Status::UNKNOWN};                           \
34   }
35 
36 #define TC3_NO_EXCEPTION_OR_RETURN      \
37   if (JniExceptionCheckAndClear(env)) { \
38     return {Status::UNKNOWN};           \
39   }
40 
41 #define TC3_NOT_NULL_OR_RETURN \
42   if (result == nullptr) {     \
43     return {Status::UNKNOWN};  \
44   }
45 
46 #define TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(                   \
47     METHOD_NAME, RETURN_TYPE, INPUT_TYPE, POST_CHECK)                      \
48   template <typename T = RETURN_TYPE>                                      \
49   static StatusOr<ScopedLocalRef<T>> METHOD_NAME(                          \
50       JNIEnv* env, INPUT_TYPE object, jmethodID method_id, ...) {          \
51     TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN;                                   \
52                                                                            \
53     va_list args;                                                          \
54     va_start(args, method_id);                                             \
55     ScopedLocalRef<T> result(                                              \
56         reinterpret_cast<T>(env->METHOD_NAME##V(object, method_id, args)), \
57         env);                                                              \
58     POST_CHECK                                                             \
59     va_end(args);                                                          \
60                                                                            \
61     TC3_NO_EXCEPTION_OR_RETURN;                                            \
62     return result;                                                         \
63   }
64 
65 #define TC3_JNI_NO_CHECK \
66   {}
67 
68 namespace libtextclassifier3 {
69 
70 class JniHelper {
71  public:
72   // Misc methods.
73   static StatusOr<ScopedLocalRef<jclass>> FindClass(JNIEnv* env,
74                                                     const char* class_name);
75 
76   static StatusOr<ScopedLocalRef<jclass>> GetObjectClass(JNIEnv* env,
77                                                          jobject object);
78 
79   template <typename T = jobject>
80   static StatusOr<ScopedLocalRef<T>> GetObjectArrayElement(JNIEnv* env,
81                                                            jobjectArray array,
82                                                            jsize index);
83   static StatusOr<jmethodID> GetMethodID(JNIEnv* env, jclass clazz,
84                                          const char* method_name,
85                                          const char* signature);
86   static StatusOr<jmethodID> GetStaticMethodID(JNIEnv* env, jclass clazz,
87                                                const char* method_name,
88                                                const char* signature);
89 
90   static StatusOr<jfieldID> GetFieldID(JNIEnv* env, jclass clazz,
91                                        const char* field_name,
92                                        const char* signature);
93   static StatusOr<jfieldID> GetStaticFieldID(JNIEnv* env, jclass clazz,
94                                              const char* field_name,
95                                              const char* signature);
96 
97   static StatusOr<ScopedLocalRef<jobject>> GetStaticObjectField(
98       JNIEnv* env, jclass class_name, jfieldID field_id);
99   static StatusOr<jint> GetStaticIntField(JNIEnv* env, jclass class_name,
100                                           jfieldID field_id);
101 
102   // New* methods.
103   TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(NewObject, jobject, jclass,
104                                                   TC3_NOT_NULL_OR_RETURN);
105   static StatusOr<ScopedLocalRef<jobjectArray>> NewObjectArray(
106       JNIEnv* env, jsize length, jclass element_class,
107       jobject initial_element = nullptr);
108   static StatusOr<ScopedLocalRef<jbyteArray>> NewByteArray(JNIEnv* env,
109                                                            jsize length);
110   static StatusOr<ScopedLocalRef<jintArray>> NewIntArray(JNIEnv* env,
111                                                          jsize length);
112   static StatusOr<ScopedLocalRef<jstring>> NewStringUTF(JNIEnv* env,
113                                                         const char* bytes);
114   static StatusOr<ScopedLocalRef<jfloatArray>> NewFloatArray(JNIEnv* env,
115                                                              jsize length);
116 
117   static StatusOr<jsize> GetArrayLength(JNIEnv* env, jarray array);
118 
119   static Status SetObjectArrayElement(JNIEnv* env, jobjectArray array,
120                                       jsize index, jobject val);
121 
122   static Status GetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start,
123                                    jsize len, jbyte* buf);
124 
125   static Status SetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start,
126                                    jsize len, const jbyte* buf);
127 
128   static Status SetIntArrayRegion(JNIEnv* env, jintArray array, jsize start,
129                                   jsize len, const jint* buf);
130 
131   static Status SetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start,
132                                     jsize len, const jfloat* buf);
133 
134   // Call* methods.
135   TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(CallObjectMethod, jobject,
136                                                   jobject, TC3_JNI_NO_CHECK);
137   TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(CallStaticObjectMethod,
138                                                   jobject, jclass,
139                                                   TC3_JNI_NO_CHECK);
140   static Status CallVoidMethod(JNIEnv* env, jobject object, jmethodID method_id,
141                                ...);
142   static StatusOr<bool> CallBooleanMethod(JNIEnv* env, jobject object,
143                                           jmethodID method_id, ...);
144   static StatusOr<int32_t> CallIntMethod(JNIEnv* env, jobject object,
145                                          jmethodID method_id, ...);
146   static StatusOr<int64_t> CallLongMethod(JNIEnv* env, jobject object,
147                                           jmethodID method_id, ...);
148   static StatusOr<float> CallFloatMethod(JNIEnv* env, jobject object,
149                                          jmethodID method_id, ...);
150   static StatusOr<double> CallDoubleMethod(JNIEnv* env, jobject object,
151                                            jmethodID method_id, ...);
152 
153   template <class T>
154   static StatusOr<T> CallStaticIntMethod(JNIEnv* env,
155                                          bool print_exception_on_error,
156                                          jclass clazz, jmethodID method_id,
157                                          ...);
158 };
159 
160 template <typename T>
GetObjectArrayElement(JNIEnv * env,jobjectArray array,jsize index)161 StatusOr<ScopedLocalRef<T>> JniHelper::GetObjectArrayElement(JNIEnv* env,
162                                                              jobjectArray array,
163                                                              jsize index) {
164   TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN;
165   ScopedLocalRef<T> result(
166       reinterpret_cast<T>(env->GetObjectArrayElement(array, index)), env);
167 
168   TC3_NO_EXCEPTION_OR_RETURN;
169   return result;
170 }
171 
172 template <class T>
CallStaticIntMethod(JNIEnv * env,bool print_exception_on_error,jclass clazz,jmethodID method_id,...)173 StatusOr<T> JniHelper::CallStaticIntMethod(JNIEnv* env,
174                                            bool print_exception_on_error,
175                                            jclass clazz, jmethodID method_id,
176                                            ...) {
177   va_list args;
178   va_start(args, method_id);
179   jint result = env->CallStaticIntMethodV(clazz, method_id, args);
180   va_end(args);
181 
182   if (JniExceptionCheckAndClear(env, print_exception_on_error)) {
183     return {Status::UNKNOWN};
184   }
185 
186   return result;
187 }
188 
189 // Converts Java byte[] object to std::string.
190 StatusOr<std::string> JByteArrayToString(JNIEnv* env, jbyteArray array);
191 
192 // Converts Java String object to UTF8-encoded std::string.
193 StatusOr<std::string> JStringToUtf8String(JNIEnv* env, jstring jstr);
194 
195 }  // namespace libtextclassifier3
196 
197 #endif  // ICING_TEXT_CLASSIFIER_LIB3_UTILS_JAVA_JNI_HELPER_H_
198