/** * Copyright (c) Facebook, Inc. and its affiliates. * *
This source code is licensed under the MIT license found in the LICENSE file in the root * directory of this source tree. */ package com.facebook.react.bridge; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * Java {@link HashMap} backed implementation of {@link ReadableMap} and {@link WritableMap} * Instances of this class SHOULD NOT be used for communication between java and JS, use instances * of {@link WritableNativeMap} created via {@link Arguments#createMap} or just {@link ReadableMap} * interface if you want your "native" module method to take a map from JS as an argument. * *
Main purpose for this class is to be used in java-only unit tests, but could also be used
* outside of tests in the code that operates only in java and needs to communicate with RN modules
* via their JS-exposed API.
*/
public class JavaOnlyMap implements ReadableMap, WritableMap {
private final Map mBackingMap;
public static JavaOnlyMap of(Object... keysAndValues) {
return new JavaOnlyMap(keysAndValues);
}
public static JavaOnlyMap deepClone(ReadableMap map) {
JavaOnlyMap res = new JavaOnlyMap();
ReadableMapKeySetIterator iter = map.keySetIterator();
while (iter.hasNextKey()) {
String propKey = iter.nextKey();
ReadableType type = map.getType(propKey);
switch (type) {
case Null:
res.putNull(propKey);
break;
case Boolean:
res.putBoolean(propKey, map.getBoolean(propKey));
break;
case Number:
res.putDouble(propKey, map.getDouble(propKey));
break;
case String:
res.putString(propKey, map.getString(propKey));
break;
case Map:
res.putMap(propKey, deepClone(map.getMap(propKey)));
break;
case Array:
res.putArray(propKey, JavaOnlyArray.deepClone(map.getArray(propKey)));
break;
}
}
return res;
}
/** @param keysAndValues keys and values, interleaved */
private JavaOnlyMap(Object... keysAndValues) {
if (keysAndValues.length % 2 != 0) {
throw new IllegalArgumentException("You must provide the same number of keys and values");
}
mBackingMap = new HashMap();
for (int i = 0; i < keysAndValues.length; i += 2) {
Object val = keysAndValues[i + 1];
if (val instanceof Number) {
// all values from JS are doubles, so emulate that here for tests.
val = ((Number)val).doubleValue();
}
mBackingMap.put(keysAndValues[i], val);
}
}
public JavaOnlyMap() {
mBackingMap = new HashMap();
}
@Override
public boolean hasKey(@Nonnull String name) {
return mBackingMap.containsKey(name);
}
@Override
public boolean isNull(@Nonnull String name) {
return mBackingMap.get(name) == null;
}
@Override
public boolean getBoolean(@Nonnull String name) {
return (Boolean) mBackingMap.get(name);
}
@Override
public double getDouble(@Nonnull String name) {
return ((Number) mBackingMap.get(name)).doubleValue();
}
@Override
public int getInt(@Nonnull String name) {
return ((Number) mBackingMap.get(name)).intValue();
}
@Override
public String getString(@Nonnull String name) {
return (String) mBackingMap.get(name);
}
@Override
public ReadableMap getMap(@Nonnull String name) {
return (ReadableMap) mBackingMap.get(name);
}
@Override
public JavaOnlyArray getArray(@Nonnull String name) {
return (JavaOnlyArray) mBackingMap.get(name);
}
@Override
public @Nonnull Dynamic getDynamic(@Nonnull String name) {
return DynamicFromMap.create(this, name);
}
@Override
public @Nonnull ReadableType getType(@Nonnull String name) {
Object value = mBackingMap.get(name);
if (value == null) {
return ReadableType.Null;
} else if (value instanceof Number) {
return ReadableType.Number;
} else if (value instanceof String) {
return ReadableType.String;
} else if (value instanceof Boolean) {
return ReadableType.Boolean;
} else if (value instanceof ReadableMap) {
return ReadableType.Map;
} else if (value instanceof ReadableArray) {
return ReadableType.Array;
} else if (value instanceof Dynamic) {
return ((Dynamic) value).getType();
} else {
throw new IllegalArgumentException(
"Invalid value " + value.toString() + " for key " + name + "contained in JavaOnlyMap");
}
}
@Override
public @Nonnull Iterator