diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CustomClassMapper.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CustomClassMapper.java index 6c685767e..f50852c2b 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CustomClassMapper.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CustomClassMapper.java @@ -266,7 +266,18 @@ private static T deserializeToParameterizedType( Type genericType = type.getActualTypeArguments()[0]; if (o instanceof List) { List list = (List) o; - List result = new ArrayList<>(list.size()); + List result = null; + try { + result = + (rawType == List.class) + ? new ArrayList<>(list.size()) + : (List) rawType.getDeclaredConstructor().newInstance(); + } catch (InstantiationException + | IllegalAccessException + | NoSuchMethodException + | InvocationTargetException e) { + throw new RuntimeException(e); + } for (int i = 0; i < list.size(); i++) { result.add( deserializeToType( diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java index 9464c4c22..6196499eb 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java @@ -24,6 +24,7 @@ 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.GEO_POINT; import static com.google.cloud.firestore.LocalFirestoreHelper.NESTED_CLASS_OBJECT; import static com.google.cloud.firestore.LocalFirestoreHelper.SERVER_TIMESTAMP_PROTO; @@ -69,10 +70,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; @@ -1073,4 +1077,33 @@ public void deleteNestedFieldUsingFieldPath() throws Exception { Collections.emptyMap(), Collections.singletonList("`a.b`.`c.d`"))); assertEquals(expectedCommit, commitCapture.getValue()); } + + @Test + public void deserializeCustomList() throws ExecutionException, InterruptedException { + ImmutableMap CUSTOM_LIST_PROTO = + ImmutableMap.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.any()); + DocumentSnapshot snapshot = documentReference.get().get(); + LocalFirestoreHelper.CustomList customList = + snapshot.toObject(LocalFirestoreHelper.CustomList.class); + + assertEquals(FOO_LIST, customList.fooList); + } } diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java index db022ba95..7048f4c7e 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java @@ -143,6 +143,7 @@ public final class LocalFirestoreHelper { public static final Timestamp TIMESTAMP; public static final GeoPoint GEO_POINT; public static final Blob BLOB; + public static final FooList FOO_LIST = new FooList<>(); public static final Precondition UPDATE_PRECONDITION; @@ -165,6 +166,18 @@ public boolean equals(Object o) { } } + public static class FooList extends ArrayList { + public FooList() { + super(); + } + } + + public static class CustomList { + public CustomList() {} + + public FooList fooList; + } + public static class NestedClass { public SingleField first = new SingleField(); public AllSupportedTypes second = new AllSupportedTypes(); @@ -773,6 +786,7 @@ 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); SINGLE_FIELD_PROTO = map("foo", Value.newBuilder().setStringValue("bar").build()); UPDATED_POJO_PROTO = map( diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java index 512e88464..2da7cd218 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java @@ -16,6 +16,7 @@ package com.google.cloud.firestore.it; +import static com.google.cloud.firestore.LocalFirestoreHelper.FOO_LIST; 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; @@ -1402,6 +1403,18 @@ 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); + } + /** Wrapper around ApiStreamObserver that returns the results in a list. */ private static class StreamConsumer implements ApiStreamObserver { SettableApiFuture> done = SettableApiFuture.create();