Navigation Menu

Skip to content

Commit

Permalink
fix: add support to deserialize to custom Lists and Maps (#337)
Browse files Browse the repository at this point in the history
  • Loading branch information
suraj-qlogic committed Aug 27, 2020
1 parent 44c806c commit dc897e0
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 2 deletions.
Expand Up @@ -266,7 +266,21 @@ private static <T> T deserializeToParameterizedType(
Type genericType = type.getActualTypeArguments()[0];
if (o instanceof List) {
List<Object> list = (List<Object>) o;
List<Object> result = new ArrayList<>(list.size());
List<Object> result;
try {
result =
(rawType == List.class)
? new ArrayList<>(list.size())
: (List<Object>) rawType.getDeclaredConstructor().newInstance();
} catch (InstantiationException
| IllegalAccessException
| NoSuchMethodException
| InvocationTargetException e) {
throw deserializeError(
context.errorPath,
String.format(
"Unable to deserialize to %s: %s", rawType.getSimpleName(), e.toString()));
}
for (int i = 0; i < list.size(); i++) {
result.add(
deserializeToType(
Expand All @@ -287,7 +301,21 @@ private static <T> T deserializeToParameterizedType(
"Only Maps with string keys are supported, but found Map with key type " + keyType);
}
Map<String, Object> map = expectMap(o, context);
HashMap<String, Object> result = new HashMap<>();
HashMap<String, Object> result;
try {
result =
(rawType == Map.class)
? new HashMap<String, Object>()
: (HashMap<String, Object>) rawType.getDeclaredConstructor().newInstance();
} catch (InstantiationException
| IllegalAccessException
| NoSuchMethodException
| InvocationTargetException e) {
throw deserializeError(
context.errorPath,
String.format(
"Unable to deserialize to %s: %s", rawType.getSimpleName(), e.toString()));
}
for (Map.Entry<String, Object> entry : map.entrySet()) {
result.put(
entry.getKey(),
Expand Down
Expand Up @@ -24,6 +24,8 @@
import static com.google.cloud.firestore.LocalFirestoreHelper.DOCUMENT_NAME;
import static com.google.cloud.firestore.LocalFirestoreHelper.DOCUMENT_PATH;
import static com.google.cloud.firestore.LocalFirestoreHelper.FIELD_TRANSFORM_COMMIT_RESPONSE;
import static com.google.cloud.firestore.LocalFirestoreHelper.FOO_LIST;
import static com.google.cloud.firestore.LocalFirestoreHelper.FOO_MAP;
import static com.google.cloud.firestore.LocalFirestoreHelper.GEO_POINT;
import static com.google.cloud.firestore.LocalFirestoreHelper.NESTED_CLASS_OBJECT;
import static com.google.cloud.firestore.LocalFirestoreHelper.SERVER_TIMESTAMP_PROTO;
Expand Down Expand Up @@ -69,10 +71,13 @@
import com.google.cloud.firestore.LocalFirestoreHelper.InvalidPOJO;
import com.google.cloud.firestore.spi.v1.FirestoreRpc;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.firestore.v1.ArrayValue;
import com.google.firestore.v1.BatchGetDocumentsRequest;
import com.google.firestore.v1.BatchGetDocumentsResponse;
import com.google.firestore.v1.CommitRequest;
import com.google.firestore.v1.CommitResponse;
import com.google.firestore.v1.MapValue;
import com.google.firestore.v1.Value;
import java.math.BigInteger;
import java.util.ArrayList;
Expand Down Expand Up @@ -1073,4 +1078,66 @@ public void deleteNestedFieldUsingFieldPath() throws Exception {
Collections.<String, Value>emptyMap(), Collections.singletonList("`a.b`.`c.d`")));
assertEquals(expectedCommit, commitCapture.getValue());
}

@Test
public void deserializeCustomList() throws ExecutionException, InterruptedException {
ImmutableMap CUSTOM_LIST_PROTO =
ImmutableMap.<String, Value>builder()
.put(
"fooList",
Value.newBuilder()
.setArrayValue(
ArrayValue.newBuilder()
.addValues(
Value.newBuilder()
.setMapValue(
MapValue.newBuilder().putAllFields(SINGLE_FIELD_PROTO))
.build()))
.build())
.build();
doAnswer(getAllResponse(CUSTOM_LIST_PROTO))
.when(firestoreMock)
.streamRequest(
getAllCapture.capture(),
streamObserverCapture.capture(),
Matchers.<ServerStreamingCallable>any());
DocumentSnapshot snapshot = documentReference.get().get();
LocalFirestoreHelper.CustomList customList =
snapshot.toObject(LocalFirestoreHelper.CustomList.class);

assertEquals(FOO_LIST, customList.fooList);
assertEquals(SINGLE_FIELD_OBJECT, customList.fooList.get(0));
}

@Test
public void deserializeCustomMap() throws ExecutionException, InterruptedException {
ImmutableMap CUSTOM_MAP_PROTO =
ImmutableMap.<String, Value>builder()
.put(
"fooMap",
Value.newBuilder()
.setMapValue(
MapValue.newBuilder()
.putFields(
"customMap",
Value.newBuilder()
.setMapValue(
MapValue.newBuilder().putAllFields(SINGLE_FIELD_PROTO))
.build())
.build())
.build())
.build();
doAnswer(getAllResponse(CUSTOM_MAP_PROTO))
.when(firestoreMock)
.streamRequest(
getAllCapture.capture(),
streamObserverCapture.capture(),
Matchers.<ServerStreamingCallable>any());
DocumentSnapshot snapshot = documentReference.get().get();
LocalFirestoreHelper.CustomMap customMap =
snapshot.toObject(LocalFirestoreHelper.CustomMap.class);

assertEquals(FOO_MAP, customMap.fooMap);
assertEquals(SINGLE_FIELD_OBJECT, customMap.fooMap.get("customMap"));
}
}
Expand Up @@ -143,6 +143,8 @@ public final class LocalFirestoreHelper {
public static final Timestamp TIMESTAMP;
public static final GeoPoint GEO_POINT;
public static final Blob BLOB;
public static final FooList<SingleField> FOO_LIST = new FooList<>();
public static final FooMap<String, SingleField> FOO_MAP = new FooMap<>();

public static final Precondition UPDATE_PRECONDITION;

Expand All @@ -165,6 +167,30 @@ public boolean equals(Object o) {
}
}

public static class FooList<E> extends ArrayList<SingleField> {
public FooList() {
super();
}
}

public static class CustomList {
public CustomList() {}

public FooList<SingleField> fooList;
}

public static class FooMap<K, V> extends HashMap<K, V> {
public FooMap() {
super();
}
}

public static class CustomMap {
public CustomMap() {}

public FooMap<String, SingleField> fooMap;
}

public static class NestedClass {
public SingleField first = new SingleField();
public AllSupportedTypes second = new AllSupportedTypes();
Expand Down Expand Up @@ -773,6 +799,8 @@ public boolean equals(Object o) {
SINGLE_FIELD_MAP = map("foo", (Object) "bar");
SINGLE_FILED_MAP_WITH_DOT = map("c.d", (Object) "bar");
SINGLE_FIELD_OBJECT = new SingleField();
FOO_LIST.add(SINGLE_FIELD_OBJECT);
FOO_MAP.put("customMap", SINGLE_FIELD_OBJECT);
SINGLE_FIELD_PROTO = map("foo", Value.newBuilder().setStringValue("bar").build());
UPDATED_POJO_PROTO =
map(
Expand Down
Expand Up @@ -16,6 +16,8 @@

package com.google.cloud.firestore.it;

import static com.google.cloud.firestore.LocalFirestoreHelper.FOO_LIST;
import static com.google.cloud.firestore.LocalFirestoreHelper.FOO_MAP;
import static com.google.cloud.firestore.LocalFirestoreHelper.UPDATE_SINGLE_FIELD_OBJECT;
import static com.google.cloud.firestore.LocalFirestoreHelper.map;
import static com.google.common.truth.Truth.assertThat;
Expand Down Expand Up @@ -1402,6 +1404,34 @@ public Void updateCallback(Transaction transaction) throws Exception {
}
}

@Test
public void deserializeCustomList() throws Exception {
LocalFirestoreHelper.CustomList customList = new LocalFirestoreHelper.CustomList();
customList.fooList = FOO_LIST;
DocumentReference documentReference = randomColl.document("doc1");
documentReference.set(customList).get();
DocumentSnapshot documentSnapshots = documentReference.get().get();
LocalFirestoreHelper.CustomList targetCustomList =
documentSnapshots.toObject(LocalFirestoreHelper.CustomList.class);

assertEquals(FOO_LIST, targetCustomList.fooList);
assertEquals(SINGLE_FIELD_OBJECT, targetCustomList.fooList.get(0));
}

@Test
public void deserializeCustomMap() throws Exception {
LocalFirestoreHelper.CustomMap customMap = new LocalFirestoreHelper.CustomMap();
customMap.fooMap = FOO_MAP;
DocumentReference documentReference = randomColl.document("doc1");
documentReference.set(customMap).get();
DocumentSnapshot documentSnapshots = documentReference.get().get();
LocalFirestoreHelper.CustomMap targetCustomMap =
documentSnapshots.toObject(LocalFirestoreHelper.CustomMap.class);

assertEquals(FOO_MAP, targetCustomMap.fooMap);
assertEquals(SINGLE_FIELD_OBJECT, targetCustomMap.fooMap.get("customMap"));
}

/** Wrapper around ApiStreamObserver that returns the results in a list. */
private static class StreamConsumer<T> implements ApiStreamObserver<T> {
SettableApiFuture<List<T>> done = SettableApiFuture.create();
Expand Down

0 comments on commit dc897e0

Please sign in to comment.