Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add support to deserialize to custom Lists and Maps #337

Merged
merged 3 commits into from Aug 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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