Marc Rousavy ef4e9fabf9
fix: Unwrap boxed JNI types directly (#2337)
* fix: Unwrap boxed JNI types directly

* Update JSIJNIConversion.cpp
2024-01-02 14:13:47 +01:00

166 lines
5.5 KiB
C++

//
// Created by Marc Rousavy on 22.06.21.
//
#include "JSIJNIConversion.h"
#include <android/log.h>
#include <fbjni/fbjni.h>
#include <jni.h>
#include <jsi/jsi.h>
#include <memory>
#include <string>
#include <utility>
#include "FrameHostObject.h"
#include "JFrame.h"
namespace vision {
using namespace facebook;
jni::local_ref<jobject> JSIJNIConversion::convertJSIValueToJNIObject(jsi::Runtime& runtime, const jsi::Value& value) {
if (value.isNull() || value.isUndefined()) {
// null
return nullptr;
} else if (value.isBool()) {
// Boolean
bool boolean = value.getBool();
return JBoolean::valueOf(boolean);
} else if (value.isNumber()) {
// Double
double number = value.getNumber();
return jni::JDouble::valueOf(number);
} else if (value.isString()) {
// String
std::string string = value.getString(runtime).utf8(runtime);
return jni::make_jstring(string);
} else if (value.isObject()) {
// Object
auto valueAsObject = value.getObject(runtime);
if (valueAsObject.isArray(runtime)) {
// List<Object>
jsi::Array array = valueAsObject.getArray(runtime);
size_t size = array.size(runtime);
jni::local_ref<JArrayList<jobject>> arrayList = jni::JArrayList<jobject>::create(static_cast<int>(size));
for (size_t i = 0; i < size; i++) {
jsi::Value item = array.getValueAtIndex(runtime, i);
jni::local_ref<jobject> jniItem = convertJSIValueToJNIObject(runtime, item);
arrayList->add(jniItem);
}
return arrayList;
} else if (valueAsObject.isHostObject(runtime)) {
throw std::runtime_error("You can't pass HostObjects here.");
} else {
// Map<String, Object>
jsi::Array propertyNames = valueAsObject.getPropertyNames(runtime);
size_t size = propertyNames.size(runtime);
jni::local_ref<JHashMap<jstring, jobject>> hashMap = jni::JHashMap<jstring, jobject>::create();
for (size_t i = 0; i < size; i++) {
jsi::String propName = propertyNames.getValueAtIndex(runtime, i).asString(runtime);
jsi::Value item = valueAsObject.getProperty(runtime, propName);
jni::local_ref<jstring> key = jni::make_jstring(propName.utf8(runtime));
jni::local_ref<jobject> jniItem = convertJSIValueToJNIObject(runtime, item);
hashMap->put(key, jniItem);
}
return hashMap;
}
} else {
auto stringRepresentation = value.toString(runtime).utf8(runtime);
throw std::runtime_error("Failed to convert jsi::Value to JNI value - unsupported type!" + stringRepresentation);
}
}
jni::local_ref<jni::JMap<jstring, jobject>> JSIJNIConversion::convertJSIObjectToJNIMap(jsi::Runtime& runtime, const jsi::Object& object) {
auto propertyNames = object.getPropertyNames(runtime);
auto size = propertyNames.size(runtime);
auto hashMap = jni::JHashMap<jstring, jobject>::create();
for (size_t i = 0; i < size; i++) {
jsi::String propName = propertyNames.getValueAtIndex(runtime, i).asString(runtime);
jsi::Value value = object.getProperty(runtime, propName);
jni::local_ref<jstring> key = jni::make_jstring(propName.utf8(runtime));
jni::local_ref<jobject> jniValue = convertJSIValueToJNIObject(runtime, value);
hashMap->put(key, jniValue);
}
return hashMap;
}
jsi::Value JSIJNIConversion::convertJNIObjectToJSIValue(jsi::Runtime& runtime, const jni::local_ref<jobject>& object) {
if (object == nullptr) {
// null
return jsi::Value::undefined();
} else if (object->isInstanceOf(jni::JBoolean::javaClassStatic())) {
// Boolean
auto boxed = static_ref_cast<JBoolean>(object);
bool value = boxed->value();
return jsi::Value(value);
} else if (object->isInstanceOf(jni::JDouble::javaClassStatic())) {
// Double
auto boxed = static_ref_cast<JDouble>(object);
double value = boxed->value();
return jsi::Value(value);
} else if (object->isInstanceOf(jni::JInteger::javaClassStatic())) {
// Integer
auto boxed = static_ref_cast<JInteger>(object);
return jsi::Value(boxed->value());
} else if (object->isInstanceOf(jni::JString::javaClassStatic())) {
// String
return jsi::String::createFromUtf8(runtime, object->toString());
} else if (object->isInstanceOf(JList<jobject>::javaClassStatic())) {
// List<E>
auto arrayList = static_ref_cast<JList<jobject>>(object);
auto size = arrayList->size();
auto result = jsi::Array(runtime, size);
size_t i = 0;
for (const auto& item : *arrayList) {
result.setValueAtIndex(runtime, i, convertJNIObjectToJSIValue(runtime, item));
i++;
}
return result;
} else if (object->isInstanceOf(JMap<jstring, jobject>::javaClassStatic())) {
// Map<K, V>
auto map = static_ref_cast<JMap<jstring, jobject>>(object);
auto result = jsi::Object(runtime);
for (const auto& entry : *map) {
auto key = entry.first->toString();
auto value = entry.second;
auto jsiValue = convertJNIObjectToJSIValue(runtime, value);
result.setProperty(runtime, key.c_str(), jsiValue);
}
return result;
} else if (object->isInstanceOf(JFrame::javaClassStatic())) {
// Frame
auto frame = static_ref_cast<JFrame>(object);
// box into HostObject
auto hostObject = std::make_shared<FrameHostObject>(frame);
return jsi::Object::createFromHostObject(runtime, hostObject);
}
auto type = object->getClass()->toString();
auto message = "Received unknown JNI type \"" + type + "\"! Cannot convert to jsi::Value.";
__android_log_write(ANDROID_LOG_ERROR, "VisionCamera", message.c_str());
throw std::runtime_error(message);
}
} // namespace vision