Skip to content

Commit e264d60

Browse files
authored
Implement POJO field reads. (#83)
* Added `T get(..., Class<T>, ...)` overloads for extracting fields as a custom class (POJO) type.
1 parent be03a71 commit e264d60

File tree

4 files changed

+110
-0
lines changed

4 files changed

+110
-0
lines changed

firebase-firestore/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
- [feature] Custom objects (POJOs) can now be passed as a field value in
33
update(), within `Map<>` objects passed to set(), in array transform
44
operations, and in query filters.
5+
- [feature] DocumentSnapshot.get() now supports retrieving fields as
6+
custom objects (POJOs) by passing a Class<T> instance, e.g.
7+
`snapshot.get("field", CustomType.class)`.
58

69
# 17.1.2
710
- [changed] Changed the internal handling for locally updated documents that

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/POJOTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,28 @@ public void testAPIsAcceptPOJOsForFields() {
222222
waitFor(Tasks.whenAll(tasks));
223223
}
224224

225+
@Test
226+
public void testDocumentSnapshotGetWithPOJOs() {
227+
DocumentReference ref = testDocument();
228+
229+
// Go offline so that we can verify server timestamp behavior overload.
230+
ref.getFirestore().disableNetwork();
231+
232+
POJO pojo = new POJO(1.0, "a", ref);
233+
ref.set(map("field", pojo));
234+
235+
DocumentSnapshot snap = waitFor(ref.get());
236+
237+
assertEquals(pojo, snap.get("field", POJO.class));
238+
assertEquals(pojo, snap.get(FieldPath.of("field"), POJO.class));
239+
assertEquals(
240+
pojo, snap.get("field", POJO.class, DocumentSnapshot.ServerTimestampBehavior.DEFAULT));
241+
assertEquals(
242+
pojo,
243+
snap.get(
244+
FieldPath.of("field"), POJO.class, DocumentSnapshot.ServerTimestampBehavior.DEFAULT));
245+
}
246+
225247
@Test
226248
public void setFieldMaskMustHaveCorrespondingValue() {
227249
CollectionReference collection = testCollection();

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/ServerTimestampTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,28 @@ public void testServerTimestampsUsesPreviousValueFromLocalMutation() {
248248
assertThat(remoteSnapshot.get("a")).isInstanceOf(Timestamp.class);
249249
}
250250

251+
@Test
252+
public void testServerTimestampBehaviorOverloadsOfDocumentSnapshotGet() {
253+
writeInitialData();
254+
waitFor(docRef.update(updateData));
255+
DocumentSnapshot snap = accumulator.awaitLocalEvent();
256+
257+
// Default behavior should return null timestamp (via any overload).
258+
assertNull(snap.get("when"));
259+
assertNull(snap.get(FieldPath.of("when")));
260+
assertNull(snap.get("when", Timestamp.class));
261+
assertNull(snap.get(FieldPath.of("when"), Timestamp.class));
262+
263+
// Estimate should return a Timestamp object (via any overload).
264+
assertThat(snap.get("when", ServerTimestampBehavior.ESTIMATE)).isInstanceOf(Timestamp.class);
265+
assertThat(snap.get(FieldPath.of("when"), ServerTimestampBehavior.ESTIMATE))
266+
.isInstanceOf(Timestamp.class);
267+
assertThat(snap.get("when", Timestamp.class, ServerTimestampBehavior.ESTIMATE))
268+
.isInstanceOf(Timestamp.class);
269+
assertThat(snap.get(FieldPath.of("when"), Timestamp.class, ServerTimestampBehavior.ESTIMATE))
270+
.isInstanceOf(Timestamp.class);
271+
}
272+
251273
@Test
252274
public void testServerTimestampsWorkViaTransactionSet() {
253275
waitFor(

firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentSnapshot.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,69 @@ public Object get(
289289
firestore.getFirestoreSettings().areTimestampsInSnapshotsEnabled()));
290290
}
291291

292+
/**
293+
* Returns the value at the field, converted to a POJO, or null if the field or document doesn't
294+
* exist.
295+
*
296+
* @param field The path to the field
297+
* @param valueType The Java class to convert the field value to.
298+
* @return The value at the given field or null.
299+
*/
300+
@Nullable
301+
public <T> T get(@NonNull String field, @NonNull Class<T> valueType) {
302+
return get(FieldPath.fromDotSeparatedPath(field), valueType, ServerTimestampBehavior.DEFAULT);
303+
}
304+
305+
/**
306+
* Returns the value at the field, converted to a POJO, or null if the field or document doesn't
307+
* exist.
308+
*
309+
* @param field The path to the field
310+
* @param valueType The Java class to convert the field value to.
311+
* @param serverTimestampBehavior Configures the behavior for server timestamps that have not yet
312+
* been set to their final value.
313+
* @return The value at the given field or null.
314+
*/
315+
@Nullable
316+
public <T> T get(
317+
@NonNull String field,
318+
@NonNull Class<T> valueType,
319+
@NonNull ServerTimestampBehavior serverTimestampBehavior) {
320+
return get(FieldPath.fromDotSeparatedPath(field), valueType, serverTimestampBehavior);
321+
}
322+
323+
/**
324+
* Returns the value at the field, converted to a POJO, or null if the field or document doesn't
325+
* exist.
326+
*
327+
* @param fieldPath The path to the field
328+
* @param valueType The Java class to convert the field value to.
329+
* @return The value at the given field or null.
330+
*/
331+
@Nullable
332+
public <T> T get(@NonNull FieldPath fieldPath, @NonNull Class<T> valueType) {
333+
return get(fieldPath, valueType, ServerTimestampBehavior.DEFAULT);
334+
}
335+
336+
/**
337+
* Returns the value at the field, converted to a POJO, or null if the field or document doesn't
338+
* exist.
339+
*
340+
* @param fieldPath The path to the field
341+
* @param valueType The Java class to convert the field value to.
342+
* @param serverTimestampBehavior Configures the behavior for server timestamps that have not yet
343+
* been set to their final value.
344+
* @return The value at the given field or null.
345+
*/
346+
@Nullable
347+
public <T> T get(
348+
@NonNull FieldPath fieldPath,
349+
@NonNull Class<T> valueType,
350+
@NonNull ServerTimestampBehavior serverTimestampBehavior) {
351+
Object data = get(fieldPath, serverTimestampBehavior);
352+
return data == null ? null : CustomClassMapper.convertToCustomClass(data, valueType);
353+
}
354+
292355
/**
293356
* Returns the value of the field as a boolean. If the value is not a boolean this will throw a
294357
* runtime exception.

0 commit comments

Comments
 (0)