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