Files
react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyArray.java
T
Moti Zilberman 1a2937151b Make writable arrays and maps only shallowly writable
Summary:
@public

The `WritableArray` and `WritableMap` interfaces currently require that nested arrays and maps also be writable. Nothing in our code actually relies on this, so we can relax this restriction and get useful properties.

For instance, it is now possible to construct a `JavaOnlyMap` (or array) that reuses `ReadableMap` and `ReadableArray` values by reference ( = structural sharing) instead of forcing a deep copy.

Reviewed By: kathryngray

Differential Revision: D16132580

fbshipit-source-id: 9f41189ebea2a82e775a7a4da8c357a5ce9c5b9d
2019-07-08 13:25:02 -07:00

206 lines
5.0 KiB
Java

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>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.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Java {@link ArrayList} backed implementation of {@link ReadableArray} and {@link WritableArray}
* Instances of this class SHOULD NOT be used for communication between java and JS, use instances
* of {@link WritableNativeArray} created via {@link Arguments#createArray} or just {@link
* ReadableArray} interface if you want your "native" module method to take an array from JS as an
* argument.
*
* <p>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 JavaOnlyArray implements ReadableArray, WritableArray {
private final List mBackingList;
public static JavaOnlyArray from(List list) {
return new JavaOnlyArray(list);
}
public static JavaOnlyArray of(Object... values) {
return new JavaOnlyArray(values);
}
public static JavaOnlyArray deepClone(ReadableArray ary) {
JavaOnlyArray res = new JavaOnlyArray();
for (int i = 0, size = ary.size(); i < size; i++) {
ReadableType type = ary.getType(i);
switch (type) {
case Null:
res.pushNull();
break;
case Boolean:
res.pushBoolean(ary.getBoolean(i));
break;
case Number:
res.pushDouble(ary.getDouble(i));
break;
case String:
res.pushString(ary.getString(i));
break;
case Map:
res.pushMap(JavaOnlyMap.deepClone(ary.getMap(i)));
break;
case Array:
res.pushArray(deepClone(ary.getArray(i)));
break;
}
}
return res;
}
private JavaOnlyArray(Object... values) {
mBackingList = Arrays.asList(values);
}
private JavaOnlyArray(List list) {
mBackingList = new ArrayList(list);
}
public JavaOnlyArray() {
mBackingList = new ArrayList();
}
@Override
public int size() {
return mBackingList.size();
}
@Override
public boolean isNull(int index) {
return mBackingList.get(index) == null;
}
@Override
public double getDouble(int index) {
return ((Number) mBackingList.get(index)).doubleValue();
}
@Override
public int getInt(int index) {
return ((Number) mBackingList.get(index)).intValue();
}
@Override
public @Nullable String getString(int index) {
return (String) mBackingList.get(index);
}
@Override
public ReadableArray getArray(int index) {
return (ReadableArray) mBackingList.get(index);
}
@Override
public boolean getBoolean(int index) {
return (Boolean) mBackingList.get(index);
}
@Override
public ReadableMap getMap(int index) {
return (ReadableMap) mBackingList.get(index);
}
@Override
public @Nonnull Dynamic getDynamic(int index) {
return DynamicFromArray.create(this, index);
}
@Override
public @Nonnull ReadableType getType(int index) {
Object object = mBackingList.get(index);
if (object == null) {
return ReadableType.Null;
} else if (object instanceof Boolean) {
return ReadableType.Boolean;
} else if (object instanceof Double || object instanceof Float || object instanceof Integer) {
return ReadableType.Number;
} else if (object instanceof String) {
return ReadableType.String;
} else if (object instanceof ReadableArray) {
return ReadableType.Array;
} else if (object instanceof ReadableMap) {
return ReadableType.Map;
}
return null;
}
@Override
public void pushBoolean(boolean value) {
mBackingList.add(value);
}
@Override
public void pushDouble(double value) {
mBackingList.add(value);
}
@Override
public void pushInt(int value) {
mBackingList.add(new Double(value));
}
@Override
public void pushString(@Nullable String value) {
mBackingList.add(value);
}
@Override
public void pushArray(@Nullable ReadableArray array) {
mBackingList.add(array);
}
@Override
public void pushMap(@Nullable ReadableMap map) {
mBackingList.add(map);
}
@Override
public void pushNull() {
mBackingList.add(null);
}
@Override
public @Nonnull ArrayList<Object> toArrayList() {
return new ArrayList<Object>(mBackingList);
}
@Override
public String toString() {
return mBackingList.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
JavaOnlyArray that = (JavaOnlyArray) o;
if (mBackingList != null ? !mBackingList.equals(that.mBackingList) : that.mBackingList != null)
return false;
return true;
}
@Override
public int hashCode() {
return mBackingList != null ? mBackingList.hashCode() : 0;
}
}