diff --git a/firebase-firestore/CHANGELOG.md b/firebase-firestore/CHANGELOG.md index cecc22c7581..2e11f63e0c5 100644 --- a/firebase-firestore/CHANGELOG.md +++ b/firebase-firestore/CHANGELOG.md @@ -3,6 +3,9 @@ if it fails to load SSL Ciphers. To avoid these crashes, you must bundle Conscrypt to support non-GMSCore devices on Android KitKat or JellyBean (see https://github.com/grpc/grpc-java/blob/master/SECURITY.md#tls-on-android). +- [feature] Added a `@DocumentId` annotation which can be used on a + `DocumentReference` or `String` property in a POJO to indicate that the SDK + should automatically populate it with the document's ID. # 20.1.0 - [changed] SSL and gRPC initialization now happens on a separate thread, which diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/POJOTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/POJOTest.java index 0253d829c9e..8cceddb7188 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/POJOTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/POJOTest.java @@ -201,6 +201,34 @@ public void setShortValue(@Nullable Short shortValue) { } } + public static final class POJOWithDocumentIdAnnotation { + String str; + @DocumentId public DocumentReference autoPopulatedReference; + @DocumentId String docReferenceId; + + static class NestedPOJO { + @DocumentId public DocumentReference autoPopulatedReference; + } + + public NestedPOJO nested = new NestedPOJO(); + + public String getDocReferenceId() { + return docReferenceId; + } + + public void setDocReferenceId(String id) { + this.docReferenceId = id; + } + + public String getStr() { + return str; + } + + public void setStr(String str) { + this.str = str; + } + } + @After public void tearDown() { IntegrationTestUtil.tearDown(); @@ -216,6 +244,20 @@ public void testWriteAndRead() { assertEquals(data, otherData); } + @Test + public void testDocumentIdAnnotation() { + CollectionReference collection = testCollection(); + POJOWithDocumentIdAnnotation data = new POJOWithDocumentIdAnnotation(); + data.setStr("name"); + DocumentReference reference = waitFor(collection.add(data)); + DocumentSnapshot doc = waitFor(reference.get()); + POJOWithDocumentIdAnnotation readFromStore = doc.toObject(POJOWithDocumentIdAnnotation.class); + assertEquals("name", readFromStore.getStr()); + assertEquals(reference, readFromStore.autoPopulatedReference); + assertEquals(reference, readFromStore.nested.autoPopulatedReference); + assertEquals(reference.getId(), readFromStore.getDocReferenceId()); + } + @Test public void testSetMerge() { CollectionReference collection = testCollection(); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentId.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentId.java new file mode 100644 index 00000000000..eb096e426ff --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentId.java @@ -0,0 +1,49 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.firestore; + +import com.google.firebase.annotations.PublicApi; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation used to mark a POJO property to be automatically populated with the document's ID when + * the POJO is created from a Cloud Firestore document (for example, via {@link + * DocumentSnapshot#toObject}). + * + *
When using a POJO to write to a document (via {@link DocumentReference#set} or @{@link + * WriteBatch#set}), the property annotated by @DocumentId is ignored, which allows writing the POJO + * back to any document, even if it's not the origin of the POJO. + */ +@PublicApi +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +public @interface DocumentId {} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/CustomClassMapper.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/CustomClassMapper.java index f3230a6b1e3..6c4388419d6 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/CustomClassMapper.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/CustomClassMapper.java @@ -19,6 +19,7 @@ import com.google.firebase.Timestamp; import com.google.firebase.firestore.Blob; +import com.google.firebase.firestore.DocumentId; import com.google.firebase.firestore.DocumentReference; import com.google.firebase.firestore.Exclude; import com.google.firebase.firestore.FieldValue; diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/DocumentId.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/DocumentId.java deleted file mode 100644 index 7eab6674889..00000000000 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/DocumentId.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.firebase.firestore.util; - -import com.google.firebase.annotations.PublicApi; -import com.google.firebase.firestore.DocumentReference; -import com.google.firebase.firestore.DocumentSnapshot; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation used to mark a POJO property to be automatically populated with the document's ID when - * the POJO is created from a Firestore document (e.g. via {@link DocumentSnapshot#toObject}). - * - *
This annotation can only be applied to properties of String or {@link DocumentReference}, - * otherwise a runtime exception will be thrown. - * - *
A run time exception will be thrown if this annotation is applied to a property that is not - * writeable (eg, a Java Bean getter without a backing field.). - * - *
If there are conflicts between this annotation and property name matches, a runtime exception - * will be thrown. For example: If a POJO has a field `firstName` annotated by @DocumentId, and - * there is a property from the document named `firstName` as well, an exception will be thrown when - * you try to read document into the POJO via {@link DocumentSnapshot#toObject} or {@link - * DocumentReference#get}. - * - *
When writing a POJO to Firestore, the @DocumentId-annotated property will be ignored, to allow - * writing to any documents that are not the origin of the POJO. - */ -@PublicApi -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.FIELD, ElementType.METHOD}) -@interface DocumentId {} diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/util/MapperTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/util/MapperTest.java index 3cd91f34684..a1175456389 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/util/MapperTest.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/util/MapperTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; +import com.google.firebase.firestore.DocumentId; import com.google.firebase.firestore.DocumentReference; import com.google.firebase.firestore.Exclude; import com.google.firebase.firestore.PropertyName;