Extract all NativeArray/NativeMap from OnLoad.cpp
Summary: These will, eventually, need to be moved to the new bridge and so must become standalone things. For *NativeArray, this is almost just moving them out into their own .h/.cpp files. The *NativeMaps are updated to be hybrids instead of countables (in addition to getting their own .h/.cpp). Reviewed By: mhorowitz Differential Revision: D3325169 fbshipit-source-id: 40cfcab92b3fb2310bcd4de8f39e82f85d404abd
This commit is contained in:
parent
0d1d7ba2b7
commit
886a558f75
|
@ -9,7 +9,7 @@
|
|||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import com.facebook.jni.Countable;
|
||||
import com.facebook.jni.HybridData;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
|
@ -17,18 +17,18 @@ import com.facebook.soloader.SoLoader;
|
|||
* Base class for a Map whose keys and values are stored in native code (C++).
|
||||
*/
|
||||
@DoNotStrip
|
||||
public abstract class NativeMap extends Countable {
|
||||
|
||||
public abstract class NativeMap {
|
||||
static {
|
||||
SoLoader.loadLibrary(ReactBridge.REACT_NATIVE_LIB);
|
||||
}
|
||||
|
||||
public NativeMap() {
|
||||
initialize();
|
||||
public NativeMap(HybridData hybridData) {
|
||||
mHybridData = hybridData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public native String toString();
|
||||
|
||||
private native void initialize();
|
||||
@DoNotStrip
|
||||
private HybridData mHybridData;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import com.facebook.jni.Countable;
|
||||
import com.facebook.jni.HybridData;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
|
@ -27,6 +27,10 @@ public class ReadableNativeMap extends NativeMap implements ReadableMap {
|
|||
SoLoader.loadLibrary(ReactBridge.REACT_NATIVE_LIB);
|
||||
}
|
||||
|
||||
protected ReadableNativeMap(HybridData hybridData) {
|
||||
super(hybridData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public native boolean hasKey(String name);
|
||||
@Override
|
||||
|
@ -51,7 +55,7 @@ public class ReadableNativeMap extends NativeMap implements ReadableMap {
|
|||
return new ReadableNativeMapKeySetIterator(this);
|
||||
}
|
||||
|
||||
public HashMap<String, Object>toHashMap() {
|
||||
public HashMap<String, Object> toHashMap() {
|
||||
ReadableMapKeySetIterator iterator = keySetIterator();
|
||||
HashMap<String, Object> hashMap = new HashMap<>();
|
||||
|
||||
|
@ -87,14 +91,17 @@ public class ReadableNativeMap extends NativeMap implements ReadableMap {
|
|||
* Implementation of a {@link ReadableNativeMap} iterator in native memory.
|
||||
*/
|
||||
@DoNotStrip
|
||||
private static class ReadableNativeMapKeySetIterator extends Countable
|
||||
implements ReadableMapKeySetIterator {
|
||||
private static class ReadableNativeMapKeySetIterator implements ReadableMapKeySetIterator {
|
||||
@DoNotStrip
|
||||
private final HybridData mHybridData;
|
||||
|
||||
private final ReadableNativeMap mReadableNativeMap;
|
||||
// Need to hold a strong ref to the map so that our native references remain valid.
|
||||
@DoNotStrip
|
||||
private final ReadableNativeMap mMap;
|
||||
|
||||
public ReadableNativeMapKeySetIterator(ReadableNativeMap readableNativeMap) {
|
||||
mReadableNativeMap = readableNativeMap;
|
||||
initialize(mReadableNativeMap);
|
||||
mMap = readableNativeMap;
|
||||
mHybridData = initHybrid(readableNativeMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -102,6 +109,6 @@ public class ReadableNativeMap extends NativeMap implements ReadableMap {
|
|||
@Override
|
||||
public native String nextKey();
|
||||
|
||||
private native void initialize(ReadableNativeMap readableNativeMap);
|
||||
private static native HybridData initHybrid(ReadableNativeMap readableNativeMap);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class WritableNativeArray extends ReadableNativeArray implements Writable
|
|||
pushNativeMap((WritableNativeMap) map);
|
||||
}
|
||||
|
||||
private native static HybridData initHybrid();
|
||||
private static native HybridData initHybrid();
|
||||
private native void pushNativeArray(WritableNativeArray array);
|
||||
private native void pushNativeMap(WritableNativeMap map);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import com.facebook.jni.HybridData;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
@ -20,7 +21,6 @@ import com.facebook.soloader.SoLoader;
|
|||
*/
|
||||
@DoNotStrip
|
||||
public class WritableNativeMap extends ReadableNativeMap implements WritableMap {
|
||||
|
||||
static {
|
||||
SoLoader.loadLibrary(ReactBridge.REACT_NATIVE_LIB);
|
||||
}
|
||||
|
@ -59,6 +59,12 @@ public class WritableNativeMap extends ReadableNativeMap implements WritableMap
|
|||
mergeNativeMap((ReadableNativeMap) source);
|
||||
}
|
||||
|
||||
public WritableNativeMap() {
|
||||
super(initHybrid());
|
||||
}
|
||||
|
||||
private static native HybridData initHybrid();
|
||||
|
||||
private native void putNativeMap(String key, WritableNativeMap value);
|
||||
private native void putNativeArray(String key, WritableNativeArray value);
|
||||
private native void mergeNativeMap(ReadableNativeMap source);
|
||||
|
|
|
@ -7,13 +7,19 @@ LOCAL_MODULE := libreactnativejni
|
|||
LOCAL_SRC_FILES := \
|
||||
JExecutorToken.cpp \
|
||||
JMessageQueueThread.cpp \
|
||||
JniJSModulesUnbundle.cpp \
|
||||
JSCPerfLogging.cpp \
|
||||
JSLoader.cpp \
|
||||
JSLogging.cpp \
|
||||
JniJSModulesUnbundle.cpp \
|
||||
NativeArray.cpp \
|
||||
NativeCommon.cpp \
|
||||
NativeMap.cpp \
|
||||
OnLoad.cpp \
|
||||
ProxyExecutor.cpp \
|
||||
ReadableNativeArray.cpp \
|
||||
ReadableNativeMap.cpp \
|
||||
WritableNativeArray.cpp \
|
||||
WritableNativeMap.cpp \
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../.. $(LOCAL_PATH)/..
|
||||
|
|
|
@ -31,11 +31,17 @@ jni_library(
|
|||
'JMessageQueueThread.cpp',
|
||||
'JSCPerfLogging.cpp',
|
||||
'JSLoader.cpp',
|
||||
'JSLogging.cpp',
|
||||
'JniJSModulesUnbundle.cpp',
|
||||
'NativeArray.cpp',
|
||||
'NativeCommon.cpp',
|
||||
'NativeMap.cpp',
|
||||
'OnLoad.cpp',
|
||||
'ProxyExecutor.cpp',
|
||||
'JSLogging.cpp',
|
||||
'ReadableNativeArray.cpp',
|
||||
'ReadableNativeMap.cpp',
|
||||
'WritableNativeArray.cpp',
|
||||
'WritableNativeMap.cpp',
|
||||
],
|
||||
headers = [
|
||||
'JSLoader.h',
|
||||
|
@ -50,8 +56,13 @@ jni_library(
|
|||
'WebWorkers.h',
|
||||
],
|
||||
exported_headers = [
|
||||
'NativeCommon.h',
|
||||
'NativeArray.h',
|
||||
'NativeMap.h',
|
||||
'ReadableNativeArray.h',
|
||||
'ReadableNativeMap.h',
|
||||
'WritableNativeArray.h',
|
||||
'WritableNativeMap.h',
|
||||
],
|
||||
preprocessor_flags = [
|
||||
'-DLOG_TAG="ReactNativeJNI"',
|
||||
|
|
|
@ -5,23 +5,24 @@
|
|||
#include <fb/fbjni.h>
|
||||
#include <folly/json.h>
|
||||
|
||||
#include "NativeCommon.h"
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
NativeArray::NativeArray(folly::dynamic a)
|
||||
: array(std::move(a)) {
|
||||
if (!array.isArray()) {
|
||||
jni::throwNewJavaException("com/facebook/react/bridge/UnexpectedNativeTypeException",
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass,
|
||||
"expected Array, got a %s", array.typeName());
|
||||
}
|
||||
}
|
||||
|
||||
jstring NativeArray::toString() {
|
||||
if (isConsumed) {
|
||||
jni::throwNewJavaException("com/facebook/react/bridge/ObjectAlreadyConsumedException",
|
||||
"Array already consumed");
|
||||
}
|
||||
return jni::make_jstring(folly::toJson(array).c_str()).release();
|
||||
local_ref<jstring> NativeArray::toString() {
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Array already consumed");
|
||||
return make_jstring(folly::toJson(array).c_str());
|
||||
}
|
||||
|
||||
void NativeArray::registerNatives() {
|
||||
|
|
|
@ -17,7 +17,7 @@ class NativeArray : public jni::HybridClass<NativeArray> {
|
|||
bool isConsumed = false;
|
||||
folly::dynamic array;
|
||||
|
||||
jstring toString();
|
||||
jni::local_ref<jstring> toString();
|
||||
|
||||
static void registerNatives();
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include "NativeCommon.h"
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
namespace exceptions {
|
||||
const char *gUnexpectedNativeTypeExceptionClass =
|
||||
"com/facebook/react/bridge/UnexpectedNativeTypeException";
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
local_ref<ReadableType> getTypeField(const char* fieldName) {
|
||||
static auto cls = ReadableType::javaClassStatic();
|
||||
auto field = cls->getStaticField<ReadableType::javaobject>(fieldName);
|
||||
return cls->getStaticFieldValue(field);
|
||||
}
|
||||
|
||||
alias_ref<ReadableType> getNullValue() {
|
||||
static alias_ref<ReadableType> val = make_global(getTypeField("Null")).release();
|
||||
return val;
|
||||
}
|
||||
|
||||
alias_ref<ReadableType> getBooleanValue() {
|
||||
static alias_ref<ReadableType> val = make_global(getTypeField("Boolean")).release();
|
||||
return val;
|
||||
}
|
||||
|
||||
alias_ref<ReadableType> getNumberValue() {
|
||||
static alias_ref<ReadableType> val = make_global(getTypeField("Number")).release();
|
||||
return val;
|
||||
}
|
||||
|
||||
alias_ref<ReadableType> getStringValue() {
|
||||
static alias_ref<ReadableType> val = make_global(getTypeField("String")).release();
|
||||
return val;
|
||||
}
|
||||
|
||||
alias_ref<ReadableType> getMapValue() {
|
||||
static alias_ref<ReadableType> val = make_global(getTypeField("Map")).release();
|
||||
return val;
|
||||
}
|
||||
|
||||
alias_ref<ReadableType> getArrayValue() {
|
||||
static alias_ref<ReadableType> val = make_global(getTypeField("Array")).release();
|
||||
return val;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
local_ref<ReadableType> ReadableType::getType(folly::dynamic::Type type) {
|
||||
switch (type) {
|
||||
case folly::dynamic::Type::NULLT:
|
||||
return make_local(getNullValue());
|
||||
case folly::dynamic::Type::BOOL:
|
||||
return make_local(getBooleanValue());
|
||||
case folly::dynamic::Type::DOUBLE:
|
||||
case folly::dynamic::Type::INT64:
|
||||
return make_local(getNumberValue());
|
||||
case folly::dynamic::Type::STRING:
|
||||
return make_local(getStringValue());
|
||||
case folly::dynamic::Type::OBJECT:
|
||||
return make_local(getMapValue());
|
||||
case folly::dynamic::Type::ARRAY:
|
||||
return make_local(getArrayValue());
|
||||
default:
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass, "Unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fb/fbjni.h>
|
||||
#include <folly/dynamic.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
struct ReadableType : public jni::JavaClass<ReadableType> {
|
||||
static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/ReadableType;";
|
||||
|
||||
static jni::local_ref<ReadableType> getType(folly::dynamic::Type type);
|
||||
};
|
||||
|
||||
namespace exceptions {
|
||||
|
||||
extern const char *gUnexpectedNativeTypeExceptionClass;
|
||||
|
||||
template <typename T>
|
||||
void throwIfObjectAlreadyConsumed(const T& t, const char* msg) {
|
||||
if (t->isConsumed) {
|
||||
jni::throwNewJavaException("com/facebook/react/bridge/ObjectAlreadyConsumedException", msg);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace exceptions
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include "NativeMap.h"
|
||||
|
||||
#include "NativeCommon.h"
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
std::string NativeMap::toString() {
|
||||
throwIfConsumed();
|
||||
return ("{ NativeMap: " + folly::toJson(map_) + " }").c_str();
|
||||
}
|
||||
|
||||
void NativeMap::registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod("toString", NativeMap::toString),
|
||||
});
|
||||
}
|
||||
|
||||
void NativeMap::throwIfConsumed() {
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Map already consumed");
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fb/fbjni.h>
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class NativeMap : public jni::HybridClass<NativeMap> {
|
||||
public:
|
||||
static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/NativeMap;";
|
||||
|
||||
explicit NativeMap(folly::dynamic s) : isConsumed(false), map_(s) {}
|
||||
|
||||
std::string toString();
|
||||
|
||||
bool isConsumed;
|
||||
void throwIfConsumed();
|
||||
|
||||
static void registerNatives();
|
||||
protected:
|
||||
|
||||
folly::dynamic map_;
|
||||
|
||||
friend HybridBase;
|
||||
friend class ReadableNativeMapKeySetIterator;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -22,6 +22,7 @@
|
|||
#include "JExecutorTokenFactory.h"
|
||||
#include "JNativeRunnable.h"
|
||||
#include "JSLoader.h"
|
||||
#include "NativeCommon.h"
|
||||
#include "ReadableNativeArray.h"
|
||||
#include "ProxyExecutor.h"
|
||||
#include "OnLoad.h"
|
||||
|
@ -30,6 +31,7 @@
|
|||
#include "JSLogging.h"
|
||||
#include "JSCPerfLogging.h"
|
||||
#include "WebWorkers.h"
|
||||
#include "WritableNativeMap.h"
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef WITH_FBSYSTRACE
|
||||
|
@ -42,492 +44,6 @@ using namespace facebook::jni;
|
|||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
static jclass gReadableNativeMapClass;
|
||||
static jmethodID gReadableNativeMapCtor;
|
||||
|
||||
namespace exceptions {
|
||||
|
||||
static const char *gUnexpectedNativeTypeExceptionClass =
|
||||
"com/facebook/react/bridge/UnexpectedNativeTypeException";
|
||||
|
||||
template <typename T>
|
||||
void throwIfObjectAlreadyConsumed(const T& t, const char* msg) {
|
||||
if (t->isConsumed) {
|
||||
throwNewJavaException("com/facebook/react/bridge/ObjectAlreadyConsumedException", msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct NativeMap : public Countable {
|
||||
// Whether this map has been added to another array or map and no longer has a valid map value
|
||||
bool isConsumed = false;
|
||||
folly::dynamic map = folly::dynamic::object;
|
||||
};
|
||||
|
||||
struct ReadableNativeMapKeySetIterator : public Countable {
|
||||
folly::dynamic::const_item_iterator iterator;
|
||||
RefPtr<NativeMap> mapRef;
|
||||
|
||||
ReadableNativeMapKeySetIterator(folly::dynamic::const_item_iterator&& it,
|
||||
const RefPtr<NativeMap>& mapRef_)
|
||||
: iterator(std::move(it))
|
||||
, mapRef(mapRef_) {}
|
||||
};
|
||||
|
||||
static jobject createReadableNativeMapWithContents(JNIEnv* env, folly::dynamic map) {
|
||||
if (map.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!map.isObject()) {
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass,
|
||||
"expected Map, got a %s", map.typeName());
|
||||
}
|
||||
|
||||
jobject jnewMap = env->NewObject(gReadableNativeMapClass, gReadableNativeMapCtor);
|
||||
if (env->ExceptionCheck()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto nativeMap = extractRefPtr<NativeMap>(env, jnewMap);
|
||||
nativeMap->map = std::move(map);
|
||||
return jnewMap;
|
||||
}
|
||||
|
||||
namespace type {
|
||||
|
||||
static jclass gReadableReactType;
|
||||
static jobject gTypeNullValue;
|
||||
static jobject gTypeBooleanValue;
|
||||
static jobject gTypeNumberValue;
|
||||
static jobject gTypeStringValue;
|
||||
static jobject gTypeMapValue;
|
||||
static jobject gTypeArrayValue;
|
||||
|
||||
static jobject getTypeValue(JNIEnv* env, const char* fieldName) {
|
||||
jfieldID fieldID = env->GetStaticFieldID(
|
||||
gReadableReactType, fieldName, "Lcom/facebook/react/bridge/ReadableType;");
|
||||
jobject typeValue = env->GetStaticObjectField(gReadableReactType, fieldID);
|
||||
return env->NewGlobalRef(typeValue);
|
||||
}
|
||||
|
||||
static void initialize(JNIEnv* env) {
|
||||
gTypeNullValue = getTypeValue(env, "Null");
|
||||
gTypeBooleanValue = getTypeValue(env, "Boolean");
|
||||
gTypeNumberValue = getTypeValue(env, "Number");
|
||||
gTypeStringValue = getTypeValue(env, "String");
|
||||
gTypeMapValue = getTypeValue(env, "Map");
|
||||
gTypeArrayValue = getTypeValue(env, "Array");
|
||||
}
|
||||
|
||||
static jobject getType(folly::dynamic::Type type) {
|
||||
switch (type) {
|
||||
case folly::dynamic::Type::NULLT:
|
||||
return type::gTypeNullValue;
|
||||
case folly::dynamic::Type::BOOL:
|
||||
return type::gTypeBooleanValue;
|
||||
case folly::dynamic::Type::DOUBLE:
|
||||
case folly::dynamic::Type::INT64:
|
||||
return type::gTypeNumberValue;
|
||||
case folly::dynamic::Type::STRING:
|
||||
return type::gTypeStringValue;
|
||||
case folly::dynamic::Type::OBJECT:
|
||||
return type::gTypeMapValue;
|
||||
case folly::dynamic::Type::ARRAY:
|
||||
return type::gTypeArrayValue;
|
||||
default:
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass, "Unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// This attribute exports the ctor symbol, so ReadableNativeArray to be
|
||||
// constructed from other DSOs.
|
||||
__attribute__((visibility("default")))
|
||||
ReadableNativeArray::ReadableNativeArray(folly::dynamic array)
|
||||
: HybridBase(std::move(array)) {}
|
||||
|
||||
void ReadableNativeArray::mapException(const std::exception& ex) {
|
||||
if (dynamic_cast<const folly::TypeError*>(&ex) != nullptr) {
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
jint ReadableNativeArray::getSize() {
|
||||
return array.size();
|
||||
}
|
||||
|
||||
jboolean ReadableNativeArray::isNull(jint index) {
|
||||
return array.at(index).isNull() ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
jboolean ReadableNativeArray::getBoolean(jint index) {
|
||||
return array.at(index).getBool() ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
jdouble ReadableNativeArray::getDouble(jint index) {
|
||||
const folly::dynamic& val = array.at(index);
|
||||
if (val.isInt()) {
|
||||
return val.getInt();
|
||||
}
|
||||
return val.getDouble();
|
||||
}
|
||||
|
||||
jint ReadableNativeArray::getInt(jint index) {
|
||||
auto integer = array.at(index).getInt();
|
||||
static_assert(std::is_same<decltype(integer), int64_t>::value,
|
||||
"folly::dynamic int is not int64_t");
|
||||
jint javaint = static_cast<jint>(integer);
|
||||
if (integer != javaint) {
|
||||
throwNewJavaException(
|
||||
exceptions::gUnexpectedNativeTypeExceptionClass,
|
||||
"Value '%lld' doesn't fit into a 32 bit signed int", integer);
|
||||
}
|
||||
return javaint;
|
||||
}
|
||||
|
||||
const char* ReadableNativeArray::getString(jint index) {
|
||||
const folly::dynamic& dyn = array.at(index);
|
||||
if (dyn.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
return dyn.getString().c_str();
|
||||
}
|
||||
|
||||
jni::local_ref<ReadableNativeArray::jhybridobject> ReadableNativeArray::getArray(jint index) {
|
||||
auto& elem = array.at(index);
|
||||
if (elem.isNull()) {
|
||||
return jni::local_ref<ReadableNativeArray::jhybridobject>(nullptr);
|
||||
} else {
|
||||
return ReadableNativeArray::newObjectCxxArgs(elem);
|
||||
}
|
||||
}
|
||||
|
||||
// Export getMap() so we can workaround constructing ReadableNativeMap
|
||||
__attribute__((visibility("default")))
|
||||
jobject ReadableNativeArray::getMap(jint index) {
|
||||
return createReadableNativeMapWithContents(Environment::current(), array.at(index));
|
||||
}
|
||||
|
||||
jobject ReadableNativeArray::getType(jint index) {
|
||||
return type::getType(array.at(index).type());
|
||||
}
|
||||
|
||||
void ReadableNativeArray::registerNatives() {
|
||||
jni::registerNatives("com/facebook/react/bridge/ReadableNativeArray", {
|
||||
makeNativeMethod("size", ReadableNativeArray::getSize),
|
||||
makeNativeMethod("isNull", ReadableNativeArray::isNull),
|
||||
makeNativeMethod("getBoolean", ReadableNativeArray::getBoolean),
|
||||
makeNativeMethod("getDouble", ReadableNativeArray::getDouble),
|
||||
makeNativeMethod("getInt", ReadableNativeArray::getInt),
|
||||
makeNativeMethod("getString", ReadableNativeArray::getString),
|
||||
makeNativeMethod("getArray", ReadableNativeArray::getArray),
|
||||
makeNativeMethod("getMap", "(I)Lcom/facebook/react/bridge/ReadableNativeMap;",
|
||||
ReadableNativeArray::getMap),
|
||||
makeNativeMethod("getType", "(I)Lcom/facebook/react/bridge/ReadableType;",
|
||||
ReadableNativeArray::getType),
|
||||
});
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct WritableNativeArray
|
||||
: public jni::HybridClass<WritableNativeArray, ReadableNativeArray> {
|
||||
static constexpr const char* kJavaDescriptor = "Lcom/facebook/react/bridge/WritableNativeArray;";
|
||||
|
||||
WritableNativeArray()
|
||||
: HybridBase(folly::dynamic::array()) {}
|
||||
|
||||
static local_ref<jhybriddata> initHybrid(alias_ref<jclass>) {
|
||||
return makeCxxInstance();
|
||||
}
|
||||
|
||||
void pushNull() {
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Array already consumed");
|
||||
array.push_back(nullptr);
|
||||
}
|
||||
|
||||
void pushBoolean(jboolean value) {
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Array already consumed");
|
||||
array.push_back(value == JNI_TRUE);
|
||||
}
|
||||
|
||||
void pushDouble(jdouble value) {
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Receiving array already consumed");
|
||||
array.push_back(value);
|
||||
}
|
||||
|
||||
void pushInt(jint value) {
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Receiving array already consumed");
|
||||
array.push_back(value);
|
||||
}
|
||||
|
||||
void pushString(jstring value) {
|
||||
if (value == NULL) {
|
||||
pushNull();
|
||||
return;
|
||||
}
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Receiving array already consumed");
|
||||
array.push_back(wrap_alias(value)->toStdString());
|
||||
}
|
||||
|
||||
void pushNativeArray(WritableNativeArray* otherArray) {
|
||||
if (otherArray == NULL) {
|
||||
pushNull();
|
||||
return;
|
||||
}
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Receiving array already consumed");
|
||||
exceptions::throwIfObjectAlreadyConsumed(otherArray, "Array to push already consumed");
|
||||
array.push_back(std::move(otherArray->array));
|
||||
otherArray->isConsumed = true;
|
||||
}
|
||||
|
||||
void pushNativeMap(jobject jmap) {
|
||||
if (jmap == NULL) {
|
||||
pushNull();
|
||||
return;
|
||||
}
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Receiving array already consumed");
|
||||
auto map = extractRefPtr<NativeMap>(Environment::current(), jmap);
|
||||
exceptions::throwIfObjectAlreadyConsumed(map, "Map to push already consumed");
|
||||
array.push_back(std::move(map->map));
|
||||
map->isConsumed = true;
|
||||
}
|
||||
|
||||
static void registerNatives() {
|
||||
jni::registerNatives("com/facebook/react/bridge/WritableNativeArray", {
|
||||
makeNativeMethod("initHybrid", WritableNativeArray::initHybrid),
|
||||
makeNativeMethod("pushNull", WritableNativeArray::pushNull),
|
||||
makeNativeMethod("pushBoolean", WritableNativeArray::pushBoolean),
|
||||
makeNativeMethod("pushDouble", WritableNativeArray::pushDouble),
|
||||
makeNativeMethod("pushInt", WritableNativeArray::pushInt),
|
||||
makeNativeMethod("pushString", WritableNativeArray::pushString),
|
||||
makeNativeMethod("pushNativeArray", WritableNativeArray::pushNativeArray),
|
||||
makeNativeMethod("pushNativeMap", "(Lcom/facebook/react/bridge/WritableNativeMap;)V",
|
||||
WritableNativeArray::pushNativeMap),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace map {
|
||||
|
||||
static void initialize(JNIEnv* env, jobject obj) {
|
||||
auto map = createNew<NativeMap>();
|
||||
setCountableForJava(env, obj, std::move(map));
|
||||
}
|
||||
|
||||
static jstring toString(JNIEnv* env, jobject obj) {
|
||||
auto nativeMap = extractRefPtr<NativeMap>(env, obj);
|
||||
exceptions::throwIfObjectAlreadyConsumed(nativeMap, "Map already consumed");
|
||||
LocalString string(
|
||||
("{ NativeMap: " + folly::toJson(nativeMap->map) + " }").c_str());
|
||||
return static_cast<jstring>(env->NewLocalRef(string.string()));
|
||||
}
|
||||
|
||||
namespace writable {
|
||||
|
||||
static void putNull(JNIEnv* env, jobject obj, jstring key) {
|
||||
auto map = extractRefPtr<NativeMap>(env, obj);
|
||||
exceptions::throwIfObjectAlreadyConsumed(map, "Receiving map already consumed");
|
||||
map->map.insert(fromJString(env, key), nullptr);
|
||||
}
|
||||
|
||||
static void putBoolean(JNIEnv* env, jobject obj, jstring key, jboolean value) {
|
||||
auto map = extractRefPtr<NativeMap>(env, obj);
|
||||
exceptions::throwIfObjectAlreadyConsumed(map, "Receiving map already consumed");
|
||||
map->map.insert(fromJString(env, key), value == JNI_TRUE);
|
||||
}
|
||||
|
||||
static void putDouble(JNIEnv* env, jobject obj, jstring key, jdouble value) {
|
||||
auto map = extractRefPtr<NativeMap>(env, obj);
|
||||
exceptions::throwIfObjectAlreadyConsumed(map, "Receiving map already consumed");
|
||||
map->map.insert(fromJString(env, key), value);
|
||||
}
|
||||
|
||||
static void putInt(JNIEnv* env, jobject obj, jstring key, jint value) {
|
||||
auto map = extractRefPtr<NativeMap>(env, obj);
|
||||
exceptions::throwIfObjectAlreadyConsumed(map, "Receiving map already consumed");
|
||||
map->map.insert(fromJString(env, key), value);
|
||||
}
|
||||
|
||||
static void putString(JNIEnv* env, jobject obj, jstring key, jstring value) {
|
||||
if (value == NULL) {
|
||||
putNull(env, obj, key);
|
||||
return;
|
||||
}
|
||||
auto map = extractRefPtr<NativeMap>(env, obj);
|
||||
exceptions::throwIfObjectAlreadyConsumed(map, "Receiving map already consumed");
|
||||
map->map.insert(fromJString(env, key), fromJString(env, value));
|
||||
}
|
||||
|
||||
static void putArray(JNIEnv* env, jobject obj, jstring key,
|
||||
WritableNativeArray::jhybridobject value) {
|
||||
if (value == NULL) {
|
||||
putNull(env, obj, key);
|
||||
return;
|
||||
}
|
||||
auto parentMap = extractRefPtr<NativeMap>(env, obj);
|
||||
exceptions::throwIfObjectAlreadyConsumed(parentMap, "Receiving map already consumed");
|
||||
auto arrayValue = cthis(wrap_alias(value));
|
||||
exceptions::throwIfObjectAlreadyConsumed(arrayValue, "Array to put already consumed");
|
||||
parentMap->map.insert(fromJString(env, key), std::move(arrayValue->array));
|
||||
arrayValue->isConsumed = true;
|
||||
}
|
||||
|
||||
static void putMap(JNIEnv* env, jobject obj, jstring key, jobject value) {
|
||||
if (value == NULL) {
|
||||
putNull(env, obj, key);
|
||||
return;
|
||||
}
|
||||
auto parentMap = extractRefPtr<NativeMap>(env, obj);
|
||||
exceptions::throwIfObjectAlreadyConsumed(parentMap, "Receiving map already consumed");
|
||||
auto mapValue = extractRefPtr<NativeMap>(env, value);
|
||||
exceptions::throwIfObjectAlreadyConsumed(mapValue, "Map to put already consumed");
|
||||
parentMap->map.insert(fromJString(env, key), std::move(mapValue->map));
|
||||
mapValue->isConsumed = true;
|
||||
}
|
||||
|
||||
static void mergeMap(JNIEnv* env, jobject obj, jobject source) {
|
||||
auto sourceMap = extractRefPtr<NativeMap>(env, source);
|
||||
exceptions::throwIfObjectAlreadyConsumed(sourceMap, "Source map already consumed");
|
||||
auto destMap = extractRefPtr<NativeMap>(env, obj);
|
||||
exceptions::throwIfObjectAlreadyConsumed(destMap, "Destination map already consumed");
|
||||
|
||||
// std::map#insert doesn't overwrite the value, therefore we need to clean values for keys
|
||||
// that already exists before merging dest map into source map
|
||||
for (auto sourceIt : sourceMap->map.items()) {
|
||||
destMap->map.erase(sourceIt.first);
|
||||
destMap->map.insert(std::move(sourceIt.first), std::move(sourceIt.second));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace writable
|
||||
|
||||
namespace readable {
|
||||
|
||||
static const char *gNoSuchKeyExceptionClass = "com/facebook/react/bridge/NoSuchKeyException";
|
||||
|
||||
static jboolean hasKey(JNIEnv* env, jobject obj, jstring keyName) {
|
||||
auto nativeMap = extractRefPtr<NativeMap>(env, obj);
|
||||
auto& map = nativeMap->map;
|
||||
bool found = map.find(fromJString(env, keyName)) != map.items().end();
|
||||
return found ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
static const folly::dynamic& getMapValue(JNIEnv* env, jobject obj, jstring keyName) {
|
||||
auto nativeMap = extractRefPtr<NativeMap>(env, obj);
|
||||
std::string key = fromJString(env, keyName);
|
||||
try {
|
||||
return nativeMap->map.at(key);
|
||||
} catch (const std::out_of_range& ex) {
|
||||
throwNewJavaException(gNoSuchKeyExceptionClass, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
static jboolean isNull(JNIEnv* env, jobject obj, jstring keyName) {
|
||||
return getMapValue(env, obj, keyName).isNull() ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
static jboolean getBooleanKey(JNIEnv* env, jobject obj, jstring keyName) {
|
||||
try {
|
||||
return getMapValue(env, obj, keyName).getBool() ? JNI_TRUE : JNI_FALSE;
|
||||
} catch (const folly::TypeError& ex) {
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
static jdouble getDoubleKey(JNIEnv* env, jobject obj, jstring keyName) {
|
||||
const folly::dynamic& val = getMapValue(env, obj, keyName);
|
||||
if (val.isInt()) {
|
||||
return val.getInt();
|
||||
}
|
||||
try {
|
||||
return val.getDouble();
|
||||
} catch (const folly::TypeError& ex) {
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
static jint getIntKey(JNIEnv* env, jobject obj, jstring keyName) {
|
||||
try {
|
||||
auto integer = getMapValue(env, obj, keyName).getInt();
|
||||
jint javaint = static_cast<jint>(integer);
|
||||
if (integer != javaint) {
|
||||
throwNewJavaException(
|
||||
exceptions::gUnexpectedNativeTypeExceptionClass,
|
||||
"Value '%lld' doesn't fit into a 32 bit signed int", integer);
|
||||
}
|
||||
return javaint;
|
||||
} catch (const folly::TypeError& ex) {
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
static jstring getStringKey(JNIEnv* env, jobject obj, jstring keyName) {
|
||||
const folly::dynamic& val = getMapValue(env, obj, keyName);
|
||||
if (val.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
try {
|
||||
LocalString value(val.getString().c_str());
|
||||
return static_cast<jstring>(env->NewLocalRef(value.string()));
|
||||
} catch (const folly::TypeError& ex) {
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
static jni::local_ref<ReadableNativeArray::jhybridobject> getArrayKey(
|
||||
jni::alias_ref<jobject> obj, jstring keyName) {
|
||||
auto& value = getMapValue(Environment::current(), obj.get(), keyName);
|
||||
if (value.isNull()) {
|
||||
return jni::local_ref<ReadableNativeArray::jhybridobject>(nullptr);
|
||||
} else {
|
||||
return ReadableNativeArray::newObjectCxxArgs(value);
|
||||
}
|
||||
}
|
||||
|
||||
static jobject getMapKey(JNIEnv* env, jobject obj, jstring keyName) {
|
||||
return createReadableNativeMapWithContents(env, getMapValue(env, obj, keyName));
|
||||
}
|
||||
|
||||
static jobject getValueType(JNIEnv* env, jobject obj, jstring keyName) {
|
||||
return type::getType(getMapValue(env, obj, keyName).type());
|
||||
}
|
||||
|
||||
} // namespace readable
|
||||
|
||||
namespace iterator {
|
||||
|
||||
static void initialize(JNIEnv* env, jobject obj, jobject nativeMapObj) {
|
||||
auto nativeMap = extractRefPtr<NativeMap>(env, nativeMapObj);
|
||||
auto mapIterator = createNew<ReadableNativeMapKeySetIterator>(
|
||||
nativeMap->map.items().begin(), nativeMap);
|
||||
setCountableForJava(env, obj, std::move(mapIterator));
|
||||
}
|
||||
|
||||
static jboolean hasNextKey(JNIEnv* env, jobject obj) {
|
||||
auto nativeIterator = extractRefPtr<ReadableNativeMapKeySetIterator>(env, obj);
|
||||
return ((nativeIterator->iterator != nativeIterator->mapRef.get()->map.items().end())
|
||||
? JNI_TRUE : JNI_FALSE);
|
||||
}
|
||||
|
||||
static jstring getNextKey(JNIEnv* env, jobject obj) {
|
||||
auto nativeIterator = extractRefPtr<ReadableNativeMapKeySetIterator>(env, obj);
|
||||
if (JNI_FALSE == hasNextKey(env, obj)) {
|
||||
throwNewJavaException("com/facebook/react/bridge/InvalidIteratorException",
|
||||
"No such element exists");
|
||||
}
|
||||
LocalString value(nativeIterator->iterator->first.c_str());
|
||||
++nativeIterator->iterator;
|
||||
return static_cast<jstring>(env->NewLocalRef(value.string()));
|
||||
}
|
||||
|
||||
} // namespace iterator
|
||||
} // namespace map
|
||||
|
||||
namespace {
|
||||
|
||||
namespace runnable {
|
||||
|
@ -758,7 +274,7 @@ static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager,
|
|||
static void loadScriptFromFile(JNIEnv* env, jobject obj, jstring fileName, jstring sourceURL) {
|
||||
jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
|
||||
|
||||
auto bridge = jni::extractRefPtr<CountableBridge>(env, obj);
|
||||
auto bridge = extractRefPtr<CountableBridge>(env, obj);
|
||||
auto fileNameStr = fileName == NULL ? "" : fromJString(env, fileName);
|
||||
env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromFile_start"));
|
||||
auto script = fileName == NULL ? "" : react::loadScriptFromFile(fileNameStr);
|
||||
|
@ -769,7 +285,7 @@ static void loadScriptFromFile(JNIEnv* env, jobject obj, jstring fileName, jstri
|
|||
"sourceURL", sourceURLStr);
|
||||
#endif
|
||||
env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromFile_read"));
|
||||
loadApplicationScript(bridge, script, jni::fromJString(env, sourceURL));
|
||||
loadApplicationScript(bridge, script, fromJString(env, sourceURL));
|
||||
if (env->ExceptionCheck()) {
|
||||
return;
|
||||
}
|
||||
|
@ -902,17 +418,14 @@ private:
|
|||
folly::dynamic m_jscConfig;
|
||||
};
|
||||
|
||||
static void createJSCExecutor(JNIEnv *env, jobject obj, jobject jscConfig) {
|
||||
auto nativeMap = extractRefPtr<NativeMap>(env, jscConfig);
|
||||
exceptions::throwIfObjectAlreadyConsumed(nativeMap, "Map to push already consumed");
|
||||
auto executor = createNew<CountableJSCExecutorFactory>(std::move(nativeMap->map));
|
||||
nativeMap->isConsumed = true;
|
||||
setCountableForJava(env, obj, std::move(executor));
|
||||
static void createJSCExecutor(alias_ref<jobject> obj, WritableNativeMap* jscConfig) {
|
||||
auto executor = createNew<CountableJSCExecutorFactory>(jscConfig->consume());
|
||||
setCountableForJava(Environment::current(), obj.get(), std::move(executor));
|
||||
}
|
||||
|
||||
static void createProxyExecutor(JNIEnv *env, jobject obj, jobject executorInstance) {
|
||||
auto executor =
|
||||
createNew<ProxyExecutorOneTimeFactory>(jni::make_global(jni::adopt_local(executorInstance)));
|
||||
createNew<ProxyExecutorOneTimeFactory>(make_global(adopt_local(executorInstance)));
|
||||
setCountableForJava(env, obj, std::move(executor));
|
||||
}
|
||||
|
||||
|
@ -943,68 +456,19 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|||
PerfLogging::installNativeHooks = addNativePerfLoggingHooks;
|
||||
JSLogging::nativeHook = nativeLoggingHook;
|
||||
|
||||
// get the current env
|
||||
JNIEnv* env = Environment::current();
|
||||
|
||||
auto readableTypeClass = findClassLocal("com/facebook/react/bridge/ReadableType");
|
||||
type::gReadableReactType = (jclass)env->NewGlobalRef(readableTypeClass.get());
|
||||
type::initialize(env);
|
||||
|
||||
NativeArray::registerNatives();
|
||||
ReadableNativeArray::registerNatives();
|
||||
WritableNativeArray::registerNatives();
|
||||
JNativeRunnable::registerNatives();
|
||||
registerJSLoaderNatives();
|
||||
|
||||
registerNatives("com/facebook/react/bridge/NativeMap", {
|
||||
makeNativeMethod("initialize", map::initialize),
|
||||
makeNativeMethod("toString", map::toString),
|
||||
});
|
||||
|
||||
jclass readableMapClass = env->FindClass("com/facebook/react/bridge/ReadableNativeMap");
|
||||
gReadableNativeMapClass = (jclass)env->NewGlobalRef(readableMapClass);
|
||||
gReadableNativeMapCtor = env->GetMethodID(readableMapClass, "<init>", "()V");
|
||||
wrap_alias(readableMapClass)->registerNatives({
|
||||
makeNativeMethod("hasKey", map::readable::hasKey),
|
||||
makeNativeMethod("isNull", map::readable::isNull),
|
||||
makeNativeMethod("getBoolean", map::readable::getBooleanKey),
|
||||
makeNativeMethod("getDouble", map::readable::getDoubleKey),
|
||||
makeNativeMethod("getInt", map::readable::getIntKey),
|
||||
makeNativeMethod("getString", map::readable::getStringKey),
|
||||
makeNativeMethod("getArray", map::readable::getArrayKey),
|
||||
makeNativeMethod(
|
||||
"getMap", "(Ljava/lang/String;)Lcom/facebook/react/bridge/ReadableNativeMap;",
|
||||
map::readable::getMapKey),
|
||||
makeNativeMethod(
|
||||
"getType", "(Ljava/lang/String;)Lcom/facebook/react/bridge/ReadableType;",
|
||||
map::readable::getValueType),
|
||||
});
|
||||
|
||||
registerNatives("com/facebook/react/bridge/WritableNativeMap", {
|
||||
makeNativeMethod("putNull", map::writable::putNull),
|
||||
makeNativeMethod("putBoolean", map::writable::putBoolean),
|
||||
makeNativeMethod("putDouble", map::writable::putDouble),
|
||||
makeNativeMethod("putInt", map::writable::putInt),
|
||||
makeNativeMethod("putString", map::writable::putString),
|
||||
makeNativeMethod("putNativeArray", map::writable::putArray),
|
||||
makeNativeMethod(
|
||||
"putNativeMap", "(Ljava/lang/String;Lcom/facebook/react/bridge/WritableNativeMap;)V",
|
||||
map::writable::putMap),
|
||||
makeNativeMethod(
|
||||
"mergeNativeMap", "(Lcom/facebook/react/bridge/ReadableNativeMap;)V",
|
||||
map::writable::mergeMap)
|
||||
});
|
||||
|
||||
registerNatives("com/facebook/react/bridge/ReadableNativeMap$ReadableNativeMapKeySetIterator", {
|
||||
makeNativeMethod("initialize", "(Lcom/facebook/react/bridge/ReadableNativeMap;)V",
|
||||
map::iterator::initialize),
|
||||
makeNativeMethod("hasNextKey", map::iterator::hasNextKey),
|
||||
makeNativeMethod("nextKey", map::iterator::getNextKey),
|
||||
});
|
||||
NativeMap::registerNatives();
|
||||
ReadableNativeMap::registerNatives();
|
||||
WritableNativeMap::registerNatives();
|
||||
ReadableNativeMapKeySetIterator::registerNatives();
|
||||
|
||||
registerNatives("com/facebook/react/bridge/JSCJavaScriptExecutor", {
|
||||
makeNativeMethod("initialize", "(Lcom/facebook/react/bridge/WritableNativeMap;)V",
|
||||
executors::createJSCExecutor),
|
||||
makeNativeMethod("initialize", executors::createJSCExecutor),
|
||||
});
|
||||
|
||||
registerNatives("com/facebook/react/bridge/ProxyJavaScriptExecutor", {
|
||||
|
@ -1013,6 +477,9 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|||
executors::createProxyExecutor),
|
||||
});
|
||||
|
||||
// get the current env
|
||||
JNIEnv* env = Environment::current();
|
||||
|
||||
jclass callbackClass = env->FindClass("com/facebook/react/bridge/ReactCallback");
|
||||
bridge::gCallbackMethod = env->GetMethodID(callbackClass, "call", "(Lcom/facebook/react/bridge/ExecutorToken;IILcom/facebook/react/bridge/ReadableNativeArray;)V");
|
||||
bridge::gOnBatchCompleteMethod = env->GetMethodID(callbackClass, "onBatchComplete", "()V");
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include "ReadableNativeArray.h"
|
||||
|
||||
#include "ReadableNativeMap.h"
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
|
||||
// This attribute exports the ctor symbol, so ReadableNativeArray to be
|
||||
// constructed from other DSOs.
|
||||
__attribute__((visibility("default")))
|
||||
ReadableNativeArray::ReadableNativeArray(folly::dynamic array)
|
||||
: HybridBase(std::move(array)) {}
|
||||
|
||||
void ReadableNativeArray::mapException(const std::exception& ex) {
|
||||
if (dynamic_cast<const folly::TypeError*>(&ex) != nullptr) {
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
jint ReadableNativeArray::getSize() {
|
||||
return array.size();
|
||||
}
|
||||
|
||||
jboolean ReadableNativeArray::isNull(jint index) {
|
||||
return array.at(index).isNull() ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
jboolean ReadableNativeArray::getBoolean(jint index) {
|
||||
return array.at(index).getBool() ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
jdouble ReadableNativeArray::getDouble(jint index) {
|
||||
const folly::dynamic& val = array.at(index);
|
||||
if (val.isInt()) {
|
||||
return val.getInt();
|
||||
}
|
||||
return val.getDouble();
|
||||
}
|
||||
|
||||
jint ReadableNativeArray::getInt(jint index) {
|
||||
auto integer = array.at(index).getInt();
|
||||
static_assert(std::is_same<decltype(integer), int64_t>::value,
|
||||
"folly::dynamic int is not int64_t");
|
||||
jint javaint = static_cast<jint>(integer);
|
||||
if (integer != javaint) {
|
||||
throwNewJavaException(
|
||||
exceptions::gUnexpectedNativeTypeExceptionClass,
|
||||
"Value '%lld' doesn't fit into a 32 bit signed int", integer);
|
||||
}
|
||||
return javaint;
|
||||
}
|
||||
|
||||
const char* ReadableNativeArray::getString(jint index) {
|
||||
const folly::dynamic& dyn = array.at(index);
|
||||
if (dyn.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
return dyn.getString().c_str();
|
||||
}
|
||||
|
||||
local_ref<ReadableNativeArray::jhybridobject> ReadableNativeArray::getArray(jint index) {
|
||||
auto& elem = array.at(index);
|
||||
if (elem.isNull()) {
|
||||
return local_ref<ReadableNativeArray::jhybridobject>(nullptr);
|
||||
} else {
|
||||
return ReadableNativeArray::newObjectCxxArgs(elem);
|
||||
}
|
||||
}
|
||||
|
||||
local_ref<ReadableType> ReadableNativeArray::getType(jint index) {
|
||||
return ReadableType::getType(array.at(index).type());
|
||||
}
|
||||
|
||||
// Export getMap() so we can workaround constructing ReadableNativeMap
|
||||
__attribute__((visibility("default")))
|
||||
local_ref<NativeMap::jhybridobject> ReadableNativeArray::getMap(jint index) {
|
||||
// TODO(cjhopman): ... this moves the map?!?
|
||||
return ReadableNativeMap::createWithContents(std::move(array.at(index)));
|
||||
}
|
||||
|
||||
void ReadableNativeArray::registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod("size", ReadableNativeArray::getSize),
|
||||
makeNativeMethod("isNull", ReadableNativeArray::isNull),
|
||||
makeNativeMethod("getBoolean", ReadableNativeArray::getBoolean),
|
||||
makeNativeMethod("getDouble", ReadableNativeArray::getDouble),
|
||||
makeNativeMethod("getInt", ReadableNativeArray::getInt),
|
||||
makeNativeMethod("getString", ReadableNativeArray::getString),
|
||||
makeNativeMethod("getArray", ReadableNativeArray::getArray),
|
||||
makeNativeMethod("getMap", jmethod_traits<ReadableNativeMap::jhybridobject(jint)>::descriptor(),
|
||||
ReadableNativeArray::getMap),
|
||||
makeNativeMethod("getType", ReadableNativeArray::getType),
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
#include "NativeArray.h"
|
||||
|
||||
#include "NativeCommon.h"
|
||||
#include "NativeMap.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
|
@ -26,8 +29,10 @@ class ReadableNativeArray : public jni::HybridClass<ReadableNativeArray, NativeA
|
|||
// careful.
|
||||
const char* getString(jint index);
|
||||
jni::local_ref<jhybridobject> getArray(jint index);
|
||||
jobject getMap(jint index);
|
||||
jobject getType(jint index);
|
||||
// This actually returns a ReadableNativeMap::JavaPart, but due to
|
||||
// limitations of fbjni, we can't specify that here.
|
||||
jni::local_ref<NativeMap::jhybridobject> getMap(jint index);
|
||||
jni::local_ref<ReadableType> getType(jint index);
|
||||
|
||||
static void registerNatives();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include "ReadableNativeMap.h"
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
namespace {
|
||||
const char *gNoSuchKeyExceptionClass = "com/facebook/react/bridge/NoSuchKeyException";
|
||||
} // namespace
|
||||
|
||||
void ReadableNativeMap::mapException(const std::exception& ex) {
|
||||
if (dynamic_cast<const folly::TypeError*>(&ex) != nullptr) {
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool ReadableNativeMap::hasKey(const std::string& key) {
|
||||
return map_.find(key) != map_.items().end();
|
||||
}
|
||||
|
||||
const folly::dynamic& ReadableNativeMap::getMapValue(const std::string& key) {
|
||||
try {
|
||||
return map_.at(key);
|
||||
} catch (const std::out_of_range& ex) {
|
||||
throwNewJavaException(gNoSuchKeyExceptionClass, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool ReadableNativeMap::isNull(const std::string& key) {
|
||||
return getMapValue(key).isNull();
|
||||
}
|
||||
|
||||
bool ReadableNativeMap::getBooleanKey(const std::string& key) {
|
||||
return getMapValue(key).getBool();
|
||||
}
|
||||
|
||||
double ReadableNativeMap::getDoubleKey(const std::string& key) {
|
||||
const folly::dynamic& val = getMapValue(key);
|
||||
if (val.isInt()) {
|
||||
return val.getInt();
|
||||
}
|
||||
return val.getDouble();
|
||||
}
|
||||
|
||||
jint ReadableNativeMap::getIntKey(const std::string& key) {
|
||||
auto integer = getMapValue(key).getInt();
|
||||
jint javaint = static_cast<jint>(integer);
|
||||
if (integer != javaint) {
|
||||
throwNewJavaException(
|
||||
exceptions::gUnexpectedNativeTypeExceptionClass,
|
||||
"Value '%lld' doesn't fit into a 32 bit signed int", integer);
|
||||
}
|
||||
return javaint;
|
||||
}
|
||||
|
||||
local_ref<jstring> ReadableNativeMap::getStringKey(const std::string& key) {
|
||||
const folly::dynamic& val = getMapValue(key);
|
||||
if (val.isNull()) {
|
||||
return local_ref<jstring>(nullptr);
|
||||
}
|
||||
return make_jstring(val.getString().c_str());
|
||||
}
|
||||
|
||||
local_ref<ReadableNativeArray::jhybridobject> ReadableNativeMap::getArrayKey(const std::string& key) {
|
||||
auto& value = getMapValue(key);
|
||||
if (value.isNull()) {
|
||||
return local_ref<ReadableNativeArray::jhybridobject>(nullptr);
|
||||
} else {
|
||||
return ReadableNativeArray::newObjectCxxArgs(value);
|
||||
}
|
||||
}
|
||||
|
||||
local_ref<ReadableNativeMap::jhybridobject> ReadableNativeMap::getMapKey(const std::string& key) {
|
||||
auto& value = getMapValue(key);
|
||||
if (value.isNull()) {
|
||||
return local_ref<ReadableNativeMap::jhybridobject>(nullptr);
|
||||
} else if (!value.isObject()) {
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass,
|
||||
"expected Map, got a %s", value.typeName());
|
||||
} else {
|
||||
return ReadableNativeMap::newObjectCxxArgs(value);
|
||||
}
|
||||
}
|
||||
|
||||
local_ref<ReadableType> ReadableNativeMap::getValueType(const std::string& key) {
|
||||
return ReadableType::getType(getMapValue(key).type());
|
||||
}
|
||||
|
||||
local_ref<ReadableNativeMap::jhybridobject> ReadableNativeMap::createWithContents(folly::dynamic&& map) {
|
||||
if (map.isNull()) {
|
||||
return local_ref<jhybridobject>(nullptr);
|
||||
}
|
||||
|
||||
if (!map.isObject()) {
|
||||
throwNewJavaException(exceptions::gUnexpectedNativeTypeExceptionClass,
|
||||
"expected Map, got a %s", map.typeName());
|
||||
}
|
||||
|
||||
return newObjectCxxArgs(std::move(map));
|
||||
}
|
||||
|
||||
void ReadableNativeMap::registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod("hasKey", ReadableNativeMap::hasKey),
|
||||
makeNativeMethod("isNull", ReadableNativeMap::isNull),
|
||||
makeNativeMethod("getBoolean", ReadableNativeMap::getBooleanKey),
|
||||
makeNativeMethod("getDouble", ReadableNativeMap::getDoubleKey),
|
||||
makeNativeMethod("getInt", ReadableNativeMap::getIntKey),
|
||||
makeNativeMethod("getString", ReadableNativeMap::getStringKey),
|
||||
makeNativeMethod("getArray", ReadableNativeMap::getArrayKey),
|
||||
makeNativeMethod("getMap", ReadableNativeMap::getMapKey),
|
||||
makeNativeMethod("getType", ReadableNativeMap::getValueType),
|
||||
});
|
||||
}
|
||||
|
||||
ReadableNativeMapKeySetIterator::ReadableNativeMapKeySetIterator(const folly::dynamic& map)
|
||||
: iter_(map.items().begin())
|
||||
, map_(map) {}
|
||||
|
||||
local_ref<ReadableNativeMapKeySetIterator::jhybriddata> ReadableNativeMapKeySetIterator::initHybrid(alias_ref<jclass>, ReadableNativeMap* nativeMap) {
|
||||
return makeCxxInstance(nativeMap->map_);
|
||||
}
|
||||
|
||||
bool ReadableNativeMapKeySetIterator::hasNextKey() {
|
||||
return iter_ != map_.items().end();
|
||||
}
|
||||
|
||||
local_ref<jstring> ReadableNativeMapKeySetIterator::nextKey() {
|
||||
if (!hasNextKey()) {
|
||||
throwNewJavaException("com/facebook/react/bridge/InvalidIteratorException",
|
||||
"No such element exists");
|
||||
}
|
||||
auto ret = make_jstring(iter_->first.c_str());
|
||||
++iter_;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ReadableNativeMapKeySetIterator::registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod("hasNextKey", ReadableNativeMapKeySetIterator::hasNextKey),
|
||||
makeNativeMethod("nextKey", ReadableNativeMapKeySetIterator::nextKey),
|
||||
makeNativeMethod("initHybrid", ReadableNativeMapKeySetIterator::initHybrid),
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fb/fbjni.h>
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
|
||||
#include "NativeCommon.h"
|
||||
#include "NativeMap.h"
|
||||
#include "ReadableNativeArray.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
struct WritableNativeMap;
|
||||
|
||||
struct ReadableNativeMap : jni::HybridClass<ReadableNativeMap, NativeMap> {
|
||||
static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/ReadableNativeMap;";
|
||||
|
||||
bool hasKey(const std::string& key);
|
||||
const folly::dynamic& getMapValue(const std::string& key);
|
||||
bool isNull(const std::string& key);
|
||||
bool getBooleanKey(const std::string& key);
|
||||
double getDoubleKey(const std::string& key);
|
||||
jint getIntKey(const std::string& key);
|
||||
jni::local_ref<jstring> getStringKey(const std::string& key);
|
||||
jni::local_ref<ReadableNativeArray::jhybridobject> getArrayKey(const std::string& key);
|
||||
jni::local_ref<jhybridobject> getMapKey(const std::string& key);
|
||||
jni::local_ref<ReadableType> getValueType(const std::string& key);
|
||||
static jni::local_ref<jhybridobject> createWithContents(folly::dynamic&& map);
|
||||
|
||||
static void mapException(const std::exception& ex);
|
||||
|
||||
static void registerNatives();
|
||||
|
||||
using HybridBase::HybridBase;
|
||||
friend HybridBase;
|
||||
friend class WritableNativeMap;
|
||||
};
|
||||
|
||||
struct ReadableNativeMapKeySetIterator : jni::HybridClass<ReadableNativeMapKeySetIterator> {
|
||||
static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/ReadableNativeMap$ReadableNativeMapKeySetIterator;";
|
||||
|
||||
ReadableNativeMapKeySetIterator(const folly::dynamic& map);
|
||||
|
||||
bool hasNextKey();
|
||||
jni::local_ref<jstring> nextKey();
|
||||
|
||||
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>, ReadableNativeMap* nativeMap);
|
||||
static void registerNatives();
|
||||
|
||||
folly::dynamic::const_item_iterator iter_;
|
||||
// The Java side holds a strong ref to the Java ReadableNativeMap.
|
||||
const folly::dynamic& map_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include "WritableNativeArray.h"
|
||||
|
||||
#include "WritableNativeMap.h"
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
WritableNativeArray::WritableNativeArray()
|
||||
: HybridBase(folly::dynamic::array()) {}
|
||||
|
||||
local_ref<WritableNativeArray::jhybriddata> WritableNativeArray::initHybrid(alias_ref<jclass>) {
|
||||
return makeCxxInstance();
|
||||
}
|
||||
|
||||
void WritableNativeArray::pushNull() {
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Array already consumed");
|
||||
array.push_back(nullptr);
|
||||
}
|
||||
|
||||
void WritableNativeArray::pushBoolean(jboolean value) {
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Array already consumed");
|
||||
array.push_back(value == JNI_TRUE);
|
||||
}
|
||||
|
||||
void WritableNativeArray::pushDouble(jdouble value) {
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Receiving array already consumed");
|
||||
array.push_back(value);
|
||||
}
|
||||
|
||||
void WritableNativeArray::pushInt(jint value) {
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Receiving array already consumed");
|
||||
array.push_back(value);
|
||||
}
|
||||
|
||||
void WritableNativeArray::pushString(jstring value) {
|
||||
if (value == NULL) {
|
||||
pushNull();
|
||||
return;
|
||||
}
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Receiving array already consumed");
|
||||
array.push_back(wrap_alias(value)->toStdString());
|
||||
}
|
||||
|
||||
void WritableNativeArray::pushNativeArray(WritableNativeArray* otherArray) {
|
||||
if (otherArray == NULL) {
|
||||
pushNull();
|
||||
return;
|
||||
}
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Receiving array already consumed");
|
||||
exceptions::throwIfObjectAlreadyConsumed(otherArray, "Array to push already consumed");
|
||||
array.push_back(std::move(otherArray->array));
|
||||
otherArray->isConsumed = true;
|
||||
}
|
||||
|
||||
void WritableNativeArray::pushNativeMap(WritableNativeMap* map) {
|
||||
if (map == NULL) {
|
||||
pushNull();
|
||||
return;
|
||||
}
|
||||
exceptions::throwIfObjectAlreadyConsumed(this, "Receiving array already consumed");
|
||||
map->throwIfConsumed();
|
||||
array.push_back(map->consume());
|
||||
}
|
||||
|
||||
void WritableNativeArray::registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod("initHybrid", WritableNativeArray::initHybrid),
|
||||
makeNativeMethod("pushNull", WritableNativeArray::pushNull),
|
||||
makeNativeMethod("pushBoolean", WritableNativeArray::pushBoolean),
|
||||
makeNativeMethod("pushDouble", WritableNativeArray::pushDouble),
|
||||
makeNativeMethod("pushInt", WritableNativeArray::pushInt),
|
||||
makeNativeMethod("pushString", WritableNativeArray::pushString),
|
||||
makeNativeMethod("pushNativeArray", WritableNativeArray::pushNativeArray),
|
||||
makeNativeMethod("pushNativeMap", WritableNativeArray::pushNativeMap),
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fb/fbjni.h>
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
|
||||
#include "ReadableNativeArray.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
struct WritableNativeMap;
|
||||
|
||||
struct WritableNativeArray
|
||||
: public jni::HybridClass<WritableNativeArray, ReadableNativeArray> {
|
||||
static constexpr const char* kJavaDescriptor = "Lcom/facebook/react/bridge/WritableNativeArray;";
|
||||
|
||||
WritableNativeArray();
|
||||
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
|
||||
|
||||
void pushNull();
|
||||
void pushBoolean(jboolean value);
|
||||
void pushDouble(jdouble value);
|
||||
void pushInt(jint value);
|
||||
void pushString(jstring value);
|
||||
void pushNativeArray(WritableNativeArray* otherArray);
|
||||
void pushNativeMap(WritableNativeMap* map);
|
||||
|
||||
static void registerNatives();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include "WritableNativeMap.h"
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
WritableNativeMap::WritableNativeMap()
|
||||
: HybridBase(folly::dynamic::object()) {}
|
||||
|
||||
WritableNativeMap::WritableNativeMap(folly::dynamic&& val)
|
||||
: HybridBase(std::move(val)) {
|
||||
if (!map_.isObject()) {
|
||||
throw std::runtime_error("WritableNativeMap value must be an object.");
|
||||
}
|
||||
}
|
||||
|
||||
local_ref<WritableNativeMap::jhybriddata> WritableNativeMap::initHybrid(alias_ref<jclass>) {
|
||||
return makeCxxInstance();
|
||||
}
|
||||
|
||||
folly::dynamic WritableNativeMap::consume() {
|
||||
throwIfConsumed();
|
||||
isConsumed = true;
|
||||
return std::move(map_);
|
||||
}
|
||||
|
||||
void WritableNativeMap::putNull(std::string key) {
|
||||
throwIfConsumed();
|
||||
map_.insert(std::move(key), nullptr);
|
||||
}
|
||||
|
||||
void WritableNativeMap::putBoolean(std::string key, bool val) {
|
||||
throwIfConsumed();
|
||||
map_.insert(std::move(key), val);
|
||||
}
|
||||
|
||||
void WritableNativeMap::putDouble(std::string key, double val) {
|
||||
throwIfConsumed();
|
||||
map_.insert(std::move(key), val);
|
||||
}
|
||||
|
||||
void WritableNativeMap::putInt(std::string key, int val) {
|
||||
throwIfConsumed();
|
||||
map_.insert(std::move(key), val);
|
||||
}
|
||||
|
||||
void WritableNativeMap::putString(std::string key, alias_ref<jstring> val) {
|
||||
if (!val) {
|
||||
putNull(std::move(key));
|
||||
return;
|
||||
}
|
||||
throwIfConsumed();
|
||||
map_.insert(std::move(key), val->toString());
|
||||
}
|
||||
|
||||
void WritableNativeMap::putNativeArray(std::string key, alias_ref<WritableNativeArray::jhybridobject> val) {
|
||||
if (!val) {
|
||||
putNull(std::move(key));
|
||||
return;
|
||||
}
|
||||
throwIfConsumed();
|
||||
auto array = val->cthis();
|
||||
exceptions::throwIfObjectAlreadyConsumed(array, "Array to put already consumed");
|
||||
map_.insert(key, std::move(array->array));
|
||||
array->isConsumed = true;
|
||||
}
|
||||
|
||||
void WritableNativeMap::putNativeMap(std::string key, alias_ref<jhybridobject> val) {
|
||||
if (!val) {
|
||||
putNull(std::move(key));
|
||||
return;
|
||||
}
|
||||
throwIfConsumed();
|
||||
auto other = val->cthis();
|
||||
map_.insert(std::move(key), other->consume());
|
||||
}
|
||||
|
||||
void WritableNativeMap::mergeNativeMap(ReadableNativeMap* other) {
|
||||
throwIfConsumed();
|
||||
other->throwIfConsumed();
|
||||
|
||||
for (auto sourceIt : other->map_.items()) {
|
||||
map_[sourceIt.first] = sourceIt.second;
|
||||
}
|
||||
}
|
||||
|
||||
void WritableNativeMap::registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod("putNull", WritableNativeMap::putNull),
|
||||
makeNativeMethod("putBoolean", WritableNativeMap::putBoolean),
|
||||
makeNativeMethod("putDouble", WritableNativeMap::putDouble),
|
||||
makeNativeMethod("putInt", WritableNativeMap::putInt),
|
||||
makeNativeMethod("putString", WritableNativeMap::putString),
|
||||
makeNativeMethod("putNativeArray", WritableNativeMap::putNativeArray),
|
||||
makeNativeMethod("putNativeMap", WritableNativeMap::putNativeMap),
|
||||
makeNativeMethod("mergeNativeMap", WritableNativeMap::mergeNativeMap),
|
||||
makeNativeMethod("initHybrid", WritableNativeMap::initHybrid),
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fb/fbjni.h>
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
|
||||
#include "ReadableNativeMap.h"
|
||||
#include "WritableNativeArray.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
struct WritableNativeMap : jni::HybridClass<WritableNativeMap, ReadableNativeMap> {
|
||||
static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/WritableNativeMap;";
|
||||
|
||||
WritableNativeMap();
|
||||
WritableNativeMap(folly::dynamic&& val);
|
||||
|
||||
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
|
||||
|
||||
folly::dynamic consume();
|
||||
|
||||
void putNull(std::string key);
|
||||
void putBoolean(std::string key, bool val);
|
||||
void putDouble(std::string key, double val);
|
||||
void putInt(std::string key, int val);
|
||||
void putString(std::string key, jni::alias_ref<jstring> val);
|
||||
void putNativeArray(std::string key, jni::alias_ref<WritableNativeArray::jhybridobject> val);
|
||||
void putNativeMap(std::string key, jni::alias_ref<jhybridobject> val);
|
||||
void mergeNativeMap(ReadableNativeMap* other);
|
||||
|
||||
static void registerNatives();
|
||||
|
||||
friend HybridBase;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -144,7 +144,7 @@ jvalue extract(std::weak_ptr<Instance>& instance, ExecutorToken token, char type
|
|||
break;
|
||||
case 'M':
|
||||
// HACK: Workaround for constructing ReadableNativeMap
|
||||
value.l = ExposedReadableNativeArray(folly::dynamic::array(arg)).getMap(0);
|
||||
value.l = ExposedReadableNativeArray(folly::dynamic::array(arg)).getMap(0).release();
|
||||
break;
|
||||
case 'X':
|
||||
value.l = extractCallback(instance, token, arg).release();
|
||||
|
|
Loading…
Reference in New Issue