diff --git a/src/lib/support/JniReferences.cpp b/src/lib/support/JniReferences.cpp index b6919f8c076b4a..f07837ade467bd 100644 --- a/src/lib/support/JniReferences.cpp +++ b/src/lib/support/JniReferences.cpp @@ -21,7 +21,6 @@ #include <lib/support/CodeUtils.h> #include <lib/support/JniReferences.h> #include <lib/support/JniTypeWrappers.h> -#include <string> namespace chip { @@ -36,7 +35,7 @@ void JniReferences::SetJavaVm(JavaVM * jvm, const char * clsType) JNIEnv * env = GetEnvForCurrentThread(); // Any chip.devicecontroller.* class will work here - just need something to call getClassLoader() on. jclass chipClass = env->FindClass(clsType); - VerifyOrReturn(chipClass != nullptr, ChipLogError(Support, "clsType can not be found")); + VerifyOrReturn(chipClass != nullptr, ChipLogError(Support, "clsType can not found")); jclass classClass = env->FindClass("java/lang/Class"); jclass classLoaderClass = env->FindClass("java/lang/ClassLoader"); @@ -48,36 +47,6 @@ void JniReferences::SetJavaVm(JavaVM * jvm, const char * clsType) chip::JniReferences::GetInstance().GetClassRef(env, "java/util/List", mListClass); chip::JniReferences::GetInstance().GetClassRef(env, "java/util/ArrayList", mArrayListClass); chip::JniReferences::GetInstance().GetClassRef(env, "java/util/HashMap", mHashMapClass); - - // Determine if the Java code has proper Java 8 support or not. - // The class and method chosen here are arbitrary, all we care about is - // looking up any method that has an Optional parameter. - jclass controllerParamsClass = env->FindClass("chip/devicecontroller/ControllerParams"); - VerifyOrReturn(controllerParamsClass != nullptr, ChipLogError(Support, "controllerParamsClass is nullptr")); - - jmethodID getCountryCodeMethod = env->GetMethodID(controllerParamsClass, "getCountryCode", "()Ljava/util/Optional;"); - if (getCountryCodeMethod == nullptr) - { - // GetMethodID will have thrown an exception previously if it returned nullptr. - env->ExceptionClear(); - VerifyOrReturn(env->GetMethodID(controllerParamsClass, "getCountryCode", "()Lj$/util/Optional;") != nullptr, - ChipLogError(Support, "Method getCountryCode can not be found")); - use_java8_optional = false; - } - else - { - use_java8_optional = true; - } - - if (use_java8_optional) - { - chip::JniReferences::GetInstance().GetClassRef(env, "java/util/Optional", mOptionalClass); - } - else - { - chip::JniReferences::GetInstance().GetClassRef(env, "j$/util/Optional", mOptionalClass); - } - VerifyOrReturn(mOptionalClass != nullptr, ChipLogError(Support, "mOptionalClass is nullptr")); } JNIEnv * JniReferences::GetEnvForCurrentThread() @@ -121,11 +90,11 @@ CHIP_ERROR JniReferences::GetLocalClassRef(JNIEnv * env, const char * clsType, j { jclass cls = nullptr; - // Try `j$/util/Optional` when enabling Java8. Check whether mOptionalClass - // is null because this method is used to originally set mOptionalClass. - if (mOptionalClass != nullptr && (strcmp(clsType, "java/util/Optional") == 0 || strcmp(clsType, "j$/util/Optional") == 0)) + // Try `j$/util/Optional` when enabling Java8. + if (strcmp(clsType, "java/util/Optional") == 0) { - cls = mOptionalClass; + cls = env->FindClass("j$/util/Optional"); + env->ExceptionClear(); } if (cls == nullptr) @@ -160,18 +129,6 @@ CHIP_ERROR JniReferences::N2J_ByteArray(JNIEnv * env, const uint8_t * inArray, j return err; } -static std::string StrReplaceAll(const std::string & source, const std::string & from, const std::string & to) -{ - std::string newString = source; - size_t pos = 0; - while ((pos = newString.find(from, pos)) != std::string::npos) - { - newString.replace(pos, from.length(), to); - pos += to.length(); - } - return newString; -} - CHIP_ERROR JniReferences::FindMethod(JNIEnv * env, jobject object, const char * methodName, const char * methodSignature, jmethodID * methodId) { @@ -189,14 +146,21 @@ CHIP_ERROR JniReferences::FindMethod(JNIEnv * env, jobject object, const char * return CHIP_NO_ERROR; } - std::string method_signature = methodSignature; - if (!use_java8_optional) + // Try `j$` when enabling Java8. + std::string methodSignature_java8_str(methodSignature); + size_t pos = methodSignature_java8_str.find("java/util/Optional"); + if (pos != std::string::npos) { - method_signature = StrReplaceAll(method_signature, "java/util/Optional", "j$/util/Optional"); + // Replace all "java/util/Optional" with "j$/util/Optional". + while (pos != std::string::npos) + { + methodSignature_java8_str.replace(pos, strlen("java/util/Optional"), "j$/util/Optional"); + pos = methodSignature_java8_str.find("java/util/Optional"); + } + *methodId = env->GetMethodID(javaClass, methodName, methodSignature_java8_str.c_str()); + env->ExceptionClear(); } - *methodId = env->GetMethodID(javaClass, methodName, method_signature.data()); - VerifyOrReturnError(*methodId != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); return CHIP_NO_ERROR; @@ -262,23 +226,24 @@ void JniReferences::ThrowError(JNIEnv * env, jclass exceptionCls, CHIP_ERROR err CHIP_ERROR JniReferences::CreateOptional(jobject objectToWrap, jobject & outOptional) { - VerifyOrReturnError(mOptionalClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); + JNIEnv * env = GetEnvForCurrentThread(); + jclass optionalCls; + chip::JniReferences::GetInstance().GetClassRef(env, "java/util/Optional", optionalCls); + VerifyOrReturnError(optionalCls != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); + chip::JniClass jniClass(optionalCls); - JNIEnv * const env = GetEnvForCurrentThread(); - VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NO_ENV); + jmethodID ofMethod = env->GetStaticMethodID(optionalCls, "ofNullable", "(Ljava/lang/Object;)Ljava/util/Optional;"); + env->ExceptionClear(); - jmethodID ofMethod = nullptr; - if (use_java8_optional) + // Try `Lj$/util/Optional;` when enabling Java8. + if (ofMethod == nullptr) { - ofMethod = env->GetStaticMethodID(mOptionalClass, "ofNullable", "(Ljava/lang/Object;)Ljava/util/Optional;"); - } - else - { - ofMethod = env->GetStaticMethodID(mOptionalClass, "ofNullable", "(Ljava/lang/Object;)Lj$/util/Optional;"); + ofMethod = env->GetStaticMethodID(optionalCls, "ofNullable", "(Ljava/lang/Object;)Lj$/util/Optional;"); + env->ExceptionClear(); } - VerifyOrReturnError(ofMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); - outOptional = env->CallStaticObjectMethod(mOptionalClass, ofMethod, objectToWrap); + VerifyOrReturnError(ofMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); + outOptional = env->CallStaticObjectMethod(optionalCls, ofMethod, objectToWrap); VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); @@ -287,12 +252,13 @@ CHIP_ERROR JniReferences::CreateOptional(jobject objectToWrap, jobject & outOpti CHIP_ERROR JniReferences::GetOptionalValue(jobject optionalObj, jobject & optionalValue) { - VerifyOrReturnError(mOptionalClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); - - JNIEnv * const env = GetEnvForCurrentThread(); - VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NO_ENV); + JNIEnv * env = GetEnvForCurrentThread(); + jclass optionalCls; + chip::JniReferences::GetInstance().GetClassRef(env, "java/util/Optional", optionalCls); + VerifyOrReturnError(optionalCls != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); + chip::JniClass jniClass(optionalCls); - jmethodID isPresentMethod = env->GetMethodID(mOptionalClass, "isPresent", "()Z"); + jmethodID isPresentMethod = env->GetMethodID(optionalCls, "isPresent", "()Z"); VerifyOrReturnError(isPresentMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); jboolean isPresent = optionalObj && env->CallBooleanMethod(optionalObj, isPresentMethod); @@ -302,7 +268,7 @@ CHIP_ERROR JniReferences::GetOptionalValue(jobject optionalObj, jobject & option return CHIP_NO_ERROR; } - jmethodID getMethod = env->GetMethodID(mOptionalClass, "get", "()Ljava/lang/Object;"); + jmethodID getMethod = env->GetMethodID(optionalCls, "get", "()Ljava/lang/Object;"); VerifyOrReturnError(getMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); optionalValue = env->CallObjectMethod(optionalObj, getMethod); return CHIP_NO_ERROR; diff --git a/src/lib/support/JniReferences.h b/src/lib/support/JniReferences.h index 4abef990822b0c..9a0fea52019040 100644 --- a/src/lib/support/JniReferences.h +++ b/src/lib/support/JniReferences.h @@ -190,12 +190,8 @@ class JniReferences jobject mClassLoader = nullptr; jmethodID mFindClassMethod = nullptr; - // These are global refs and therefore safe to persist. jclass mHashMapClass = nullptr; jclass mListClass = nullptr; jclass mArrayListClass = nullptr; - jclass mOptionalClass = nullptr; - - bool use_java8_optional = false; }; } // namespace chip