blob: 0a515a06012e43bc29c980b56fb4136612b50919 [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* 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.
*/
#pragma once
#include <jni.h>
#include <lib/core/CHIPError.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/TypeTraits.h>
#include <string>
namespace chip {
class JniReferences
{
public:
// No copy, move or assignment.
JniReferences(const JniReferences &) = delete;
JniReferences(const JniReferences &&) = delete;
JniReferences & operator=(const JniReferences &) = delete;
static JniReferences & GetInstance()
{
static JniReferences jniReferences;
return jniReferences;
}
/**
* Set the JavaVM.
*
* we need clsType in context to get ClassLoader
*
* This must be called before GetEnvForCurrentThread() or GetClassRef().
*/
void SetJavaVm(JavaVM * jvm, const char * clsType);
/**
* Returns a JNIEnv for the current thread.
*
* This must be called after SetJavaVm(). If the current thread is not attached to the JVM, this method will attach the thread
* first, then retrieve the JNIEnv.
*/
JNIEnv * GetEnvForCurrentThread();
/**
* @brief
* Creates a jclass reference to the given class type.
*
* This must be called after SetJavaVm().
*
* @param[in] env The JNIEnv for finding a Java class and creating a new Java reference.
* @param[in] clsType The fully-qualified Java class name to find, e.g. java/lang/IllegalStateException.
* @param[out] outCls A Java reference to the class matching clsType.
*/
CHIP_ERROR GetClassRef(JNIEnv * env, const char * clsType, jclass & outCls);
CHIP_ERROR FindMethod(JNIEnv * env, jobject object, const char * methodName, const char * methodSignature,
jmethodID * methodId);
void CallVoidInt(JNIEnv * env, jobject object, const char * methodName, jint argument);
CHIP_ERROR N2J_ByteArray(JNIEnv * env, const uint8_t * inArray, jsize inArrayLen, jbyteArray & outArray);
void ReportError(JNIEnv * env, CHIP_ERROR cbErr, const char * functName);
void ThrowError(JNIEnv * env, jclass exceptionCls, CHIP_ERROR errToThrow);
/**
* Creates a java.util.Optional wrapping the specified jobject. If the wrapped jobject is null, an empty
* Optional will be returned.
*/
CHIP_ERROR CreateOptional(jobject objectToWrap, jobject & outOptional);
/**
* Retrieve the value of a java.util.Optional, or nullptr if the Optional is empty.
*/
CHIP_ERROR GetOptionalValue(jobject optionalObj, jobject & optionalValue);
/**
* Get a primitive jint from the Java boxed type Integer, using intValue().
*/
jint IntegerToPrimitive(jobject boxedObject);
/**
* Get a primitive jlong from the Java boxed type Long, using longValue().
*/
jlong LongToPrimitive(jobject boxedObject);
/**
* Get a primitive jboolean from the Java boxed type Booelan, using booleanValue().
*/
jboolean BooleanToPrimitive(jobject boxedObject);
/**
* Get a primitive jfloat from the Java boxed type Float, using floatValue().
*/
jfloat FloatToPrimitive(jobject boxedObject);
/**
* Get a primitive jfloat from the Java boxed type Double, using doubleValue().
*/
jdouble DoubleToPrimitive(jobject boxedObject);
CHIP_ERROR CreateArrayList(jobject & outList);
CHIP_ERROR AddToList(jobject list, jobject objectToAdd);
CHIP_ERROR GetListSize(jobject list, jint & size);
CHIP_ERROR GetListItem(jobject list, jint index, jobject & outItem);
CHIP_ERROR CreateHashMap(jobject & outMap);
CHIP_ERROR PutInMap(jobject map, jobject key, jobject value);
CHIP_ERROR GetObjectField(jobject objectToRead, const char * name, const char * signature, jobject & outObject);
/**
* Call a void method with no arguments named "OnSubscriptionEstablished" on the provided jobject.
*/
CHIP_ERROR CallSubscriptionEstablished(jobject javaCallback);
/**
* Creates a boxed type (e.g. java.lang.Integer) based on the the class name ("java/lang/Integer"), constructor JNI signature
* ("(I)V"), and value.
*/
template <class T, typename std::enable_if_t<!std::is_enum<T>::value, int> = 0>
CHIP_ERROR CreateBoxedObject(std::string boxedTypeClsName, std::string constructorSignature, T value, jobject & outObj)
{
JNIEnv * env = GetEnvForCurrentThread();
CHIP_ERROR err = CHIP_NO_ERROR;
jclass boxedTypeCls;
err = GetClassRef(env, boxedTypeClsName.c_str(), boxedTypeCls);
VerifyOrReturnError(err == CHIP_NO_ERROR, err);
jmethodID boxedTypeConstructor = env->GetMethodID(boxedTypeCls, "<init>", constructorSignature.c_str());
outObj = env->NewObject(boxedTypeCls, boxedTypeConstructor, value);
env->DeleteGlobalRef(boxedTypeCls);
return err;
}
/**
* Handling for strongly-typed enums.
*/
template <class T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
CHIP_ERROR CreateBoxedObject(std::string boxedTypeClsName, std::string constructorSignature, T value, jobject & outObj)
{
return CreateBoxedObject(boxedTypeClsName, constructorSignature, chip::to_underlying(value), outObj);
}
private:
JniReferences() {}
JavaVM * mJvm = nullptr;
jobject mClassLoader = nullptr;
jmethodID mFindClassMethod = nullptr;
jclass mHashMapClass = nullptr;
jclass mListClass = nullptr;
jclass mArrayListClass = nullptr;
};
} // namespace chip