/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Utility class that provides similar calls like JNIEnv, but performs // additional checks on them, so that it's harder to use them incorrectly. #ifndef LIBTEXTCLASSIFIER_UTILS_JAVA_JNI_HELPER_H_ #define LIBTEXTCLASSIFIER_UTILS_JAVA_JNI_HELPER_H_ #include #include #include "utils/base/status.h" #include "utils/base/statusor.h" #include "utils/java/jni-base.h" #define TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN \ if (!EnsureLocalCapacity(env, 1)) { \ TC3_LOG(ERROR) << "EnsureLocalCapacity(1) failed."; \ return {Status::UNKNOWN}; \ } #define TC3_NO_EXCEPTION_OR_RETURN \ if (JniExceptionCheckAndClear(env)) { \ return {Status::UNKNOWN}; \ } #define TC3_NOT_NULL_OR_RETURN \ if (result == nullptr) { \ return {Status::UNKNOWN}; \ } #define TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD( \ METHOD_NAME, RETURN_TYPE, INPUT_TYPE, POST_CHECK) \ template \ static StatusOr> METHOD_NAME( \ JNIEnv* env, INPUT_TYPE object, jmethodID method_id, ...) { \ TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN; \ \ va_list args; \ va_start(args, method_id); \ ScopedLocalRef result( \ reinterpret_cast(env->METHOD_NAME##V(object, method_id, args)), \ env); \ POST_CHECK \ va_end(args); \ \ TC3_NO_EXCEPTION_OR_RETURN; \ return result; \ } #define TC3_JNI_NO_CHECK \ {} namespace libtextclassifier3 { class JniHelper { public: // Misc methods. static StatusOr> FindClass(JNIEnv* env, const char* class_name); static StatusOr> GetObjectClass(JNIEnv* env, jobject object); template static StatusOr> GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index); static StatusOr GetMethodID(JNIEnv* env, jclass clazz, const char* method_name, const char* signature); static StatusOr GetStaticMethodID(JNIEnv* env, jclass clazz, const char* method_name, const char* signature); static StatusOr GetFieldID(JNIEnv* env, jclass clazz, const char* field_name, const char* signature); static StatusOr GetStaticFieldID(JNIEnv* env, jclass clazz, const char* field_name, const char* signature); static StatusOr> GetStaticObjectField( JNIEnv* env, jclass class_name, jfieldID field_id); static StatusOr GetStaticIntField(JNIEnv* env, jclass class_name, jfieldID field_id); // New* methods. TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(NewObject, jobject, jclass, TC3_NOT_NULL_OR_RETURN); static StatusOr> NewObjectArray( JNIEnv* env, jsize length, jclass element_class, jobject initial_element = nullptr); static StatusOr> NewByteArray(JNIEnv* env, jsize length); static StatusOr> NewIntArray(JNIEnv* env, jsize length); static StatusOr> NewStringUTF(JNIEnv* env, const char* bytes); static StatusOr> NewFloatArray(JNIEnv* env, jsize length); static StatusOr GetArrayLength(JNIEnv* env, jarray array); static Status SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject val); static Status GetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize len, jbyte* buf); static Status SetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize len, const jbyte* buf); static Status SetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize len, const jint* buf); static Status SetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize len, const jfloat* buf); // Call* methods. TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(CallObjectMethod, jobject, jobject, TC3_JNI_NO_CHECK); TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(CallStaticObjectMethod, jobject, jclass, TC3_JNI_NO_CHECK); static Status CallVoidMethod(JNIEnv* env, jobject object, jmethodID method_id, ...); static StatusOr CallBooleanMethod(JNIEnv* env, jobject object, jmethodID method_id, ...); static StatusOr CallIntMethod(JNIEnv* env, jobject object, jmethodID method_id, ...); static StatusOr CallLongMethod(JNIEnv* env, jobject object, jmethodID method_id, ...); static StatusOr CallFloatMethod(JNIEnv* env, jobject object, jmethodID method_id, ...); static StatusOr CallDoubleMethod(JNIEnv* env, jobject object, jmethodID method_id, ...); template static StatusOr CallStaticIntMethod(JNIEnv* env, bool print_exception_on_error, jclass clazz, jmethodID method_id, ...); }; template StatusOr> JniHelper::GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) { TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN; ScopedLocalRef result( reinterpret_cast(env->GetObjectArrayElement(array, index)), env); TC3_NO_EXCEPTION_OR_RETURN; return result; } template StatusOr JniHelper::CallStaticIntMethod(JNIEnv* env, bool print_exception_on_error, jclass clazz, jmethodID method_id, ...) { va_list args; va_start(args, method_id); jint result = env->CallStaticIntMethodV(clazz, method_id, args); va_end(args); if (JniExceptionCheckAndClear(env, print_exception_on_error)) { return {Status::UNKNOWN}; } return result; } // Converts Java byte[] object to std::string. StatusOr JByteArrayToString(JNIEnv* env, jbyteArray array); // Converts Java String object to UTF8-encoded std::string. StatusOr JStringToUtf8String(JNIEnv* env, jstring jstr); } // namespace libtextclassifier3 #endif // LIBTEXTCLASSIFIER_UTILS_JAVA_JNI_HELPER_H_