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