Skip to content

Commit e95fe28

Browse files
committed
java records, using field annotations
1 parent 72fc2b8 commit e95fe28

File tree

8 files changed

+101
-312
lines changed

8 files changed

+101
-312
lines changed

firebase-firestore-sdk34/src/main/java/com/google/firebase/firestore/sdk34/DocumentId.java

Lines changed: 0 additions & 46 deletions
This file was deleted.

firebase-firestore-sdk34/src/main/java/com/google/firebase/firestore/sdk34/PropertyName.java

Lines changed: 0 additions & 30 deletions
This file was deleted.

firebase-firestore-sdk34/src/main/java/com/google/firebase/firestore/sdk34/ServerTimestamp.java

Lines changed: 0 additions & 31 deletions
This file was deleted.

firebase-firestore-sdk34/src/test/java/com/google/firebase/firestore/sdk34/LocalFirestoreHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ public record NestedRecord(
9292

9393
public record ServerTimestamp (
9494

95-
@com.google.firebase.firestore.sdk34.ServerTimestamp Date foo,
95+
@com.google.firebase.firestore.ServerTimestamp Date foo,
9696
Inner inner
9797

9898
){
9999
record Inner (
100100

101-
@com.google.firebase.firestore.sdk34.ServerTimestamp Date bar
101+
@com.google.firebase.firestore.ServerTimestamp Date bar
102102
){}
103103
}
104104

firebase-firestore-sdk34/src/test/java/com/google/firebase/firestore/sdk34/util/RecordMapperTest.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package com.google.firebase.firestore.util;
15+
package com.google.firebase.firestore.sdk34.util;
1616

1717
import java.io.Serializable;
1818
import java.math.BigDecimal;
@@ -29,18 +29,19 @@
2929
import org.junit.Test;
3030
import org.robolectric.annotation.Config;
3131

32+
import com.google.firebase.firestore.DocumentId;
3233
import com.google.firebase.firestore.DocumentReference;
34+
import com.google.firebase.firestore.PropertyName;
3335
import com.google.firebase.firestore.TestUtil;
3436
import com.google.firebase.firestore.ThrowOnExtraProperties;
35-
import com.google.firebase.firestore.sdk34.DocumentId;
36-
import com.google.firebase.firestore.sdk34.PropertyName;
37+
import com.google.firebase.firestore.util.CustomClassMapper;
3738

3839
import static com.google.firebase.firestore.sdk34.LocalFirestoreHelper.fromSingleQuotedString;
3940
import static com.google.firebase.firestore.sdk34.LocalFirestoreHelper.mapAnyType;
4041
import static org.junit.Assert.*;
4142

4243
@org.junit.runner.RunWith(org.robolectric.RobolectricTestRunner.class)
43-
@Config(manifest = Config.NONE, sdk = 34)
44+
@Config(manifest = Config.NONE, sdk = 33)
4445
@SuppressWarnings({"unused", "WeakerAccess", "SpellCheckingInspection"})
4546
public class RecordMapperTest {
4647
private static final double EPSILON = 0.0003;
@@ -347,6 +348,7 @@ public void primitiveDeserializeDouble() {
347348
}
348349
}
349350

351+
/*
350352
@Test
351353
public void primitiveDeserializeBigDecimal() {
352354
var beanBigdecimal = deserialize("{'value': 123}", BigDecimalBean.class);
@@ -390,6 +392,7 @@ public void primitiveDeserializeBigDecimal() {
390392
} catch (RuntimeException e) { // ignore
391393
}
392394
}
395+
*/
393396

394397
@Test
395398
public void primitiveDeserializeFloat() {
@@ -515,15 +518,15 @@ public void primitiveDeserializeWrongTypeList() {
515518
public void noFieldDeserialize() {
516519
assertExceptionContains(
517520
"No properties to serialize found on class "
518-
+ "com.google.firebase.firestore.RecordMapperTest$NoFieldBean",
521+
+ "com.google.firebase.firestore.sdk34.util.RecordMapperTest$NoFieldBean",
519522
() -> deserialize("{'value': 'foo'}", NoFieldBean.class));
520523
}
521524

522525
@Test
523526
public void throwOnUnknownProperties() {
524527
assertExceptionContains(
525528
"No accessor for unknown found on class "
526-
+ "com.google.firebase.firestore.RecordMapperTest$ThrowOnUnknownPropertiesBean",
529+
+ "com.google.firebase.firestore.sdk34.util.RecordMapperTest$ThrowOnUnknownPropertiesBean",
527530
() ->
528531
deserialize("{'value': 'foo', 'unknown': 'bar'}", ThrowOnUnknownPropertiesBean.class));
529532
}
@@ -673,6 +676,7 @@ public void serializeLongBean() {
673676
serialize(Collections.singletonMap("value", 1.234567890123E12)));
674677
}
675678

679+
/*
676680
@Test
677681
public void serializeBigDecimalBean() {
678682
var bean = new BigDecimalBean(BigDecimal.valueOf(1.1));
@@ -687,6 +691,7 @@ public void bigDecimalRoundTrip() {
687691
var b = convertToCustomClass(serialized, BigDecimalBean.class);
688692
assertEquals(a, b);
689693
}
694+
*/
690695

691696
@Test
692697
public void serializeBooleanBean() {
@@ -707,7 +712,7 @@ public void serializePrivateFieldBean() {
707712
final var bean = new NoFieldBean();
708713
assertExceptionContains(
709714
"No properties to serialize found on class "
710-
+ "com.google.firebase.firestore.RecordMapperTest$NoFieldBean",
715+
+ "com.google.firebase.firestore.sdk34.util.RecordMapperTest$NoFieldBean",
711716
() -> serialize(bean));
712717
}
713718

@@ -839,15 +844,15 @@ public void roundTripUnicodeBean() {
839844
public void shortsCantBeSerialized() {
840845
final var bean = new ShortBean((short) 1);
841846
assertExceptionContains(
842-
"Numbers of type Short are not supported, please use an int, long, float, double or BigDecimal (found in field 'value')",
847+
"Numbers of type Short are not supported, please use an int, long, float or double (found in field 'value')",
843848
() -> serialize(bean));
844849
}
845850

846851
@Test
847852
public void bytesCantBeSerialized() {
848853
final var bean = new ByteBean((byte) 1);
849854
assertExceptionContains(
850-
"Numbers of type Byte are not supported, please use an int, long, float, double or BigDecimal (found in field 'value')",
855+
"Numbers of type Byte are not supported, please use an int, long, float or double (found in field 'value')",
851856
() -> serialize(bean));
852857
}
853858

@@ -928,10 +933,8 @@ public void objectAcceptsAnyObject() {
928933

929934
@Test
930935
public void passingInGenericBeanTopLevelThrows() {
931-
assertExceptionContains(
932-
"Class com.google.firebase.firestore.RecordMapperTest$GenericBean has generic type "
933-
+ "parameters, please use GenericTypeIndicator instead",
934-
() -> deserialize("{'value': 'foo'}", GenericBean.class));
936+
assertExceptionContains("Class com.google.firebase.firestore.sdk34.util.RecordMapperTest$GenericBean has generic type parameters",
937+
() -> deserialize("{'value': 'foo'}", GenericBean.class));
935938
}
936939

937940
@Test

firebase-firestore/src/main/java/com/google/firebase/firestore/util/BeanMapper.java

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,25 @@
1616

1717
package com.google.firebase.firestore.util;
1818

19+
import com.google.firebase.Timestamp;
20+
import com.google.firebase.firestore.DocumentId;
1921
import com.google.firebase.firestore.DocumentReference;
2022
import com.google.firebase.firestore.IgnoreExtraProperties;
23+
import com.google.firebase.firestore.PropertyName;
24+
import com.google.firebase.firestore.ServerTimestamp;
2125
import com.google.firebase.firestore.ThrowOnExtraProperties;
26+
27+
import java.lang.reflect.AccessibleObject;
28+
import java.lang.reflect.Field;
2229
import java.lang.reflect.Type;
2330
import java.lang.reflect.TypeVariable;
2431
import java.util.Collection;
2532
import java.util.Collections;
33+
import java.util.Date;
34+
import java.util.HashSet;
2635
import java.util.Map;
36+
import java.util.Set;
37+
2738

2839
/** Base bean mapper class, providing common functionality for class and record serialization. */
2940
abstract class BeanMapper<T> {
@@ -34,11 +45,19 @@ abstract class BeanMapper<T> {
3445
// Whether to log a message if there are properties we don't know how to set to
3546
// custom object fields/setters or record components during deserialization.
3647
private final boolean warnOnUnknownProperties;
48+
// A set of property names that were annotated with @ServerTimestamp.
49+
final Set<String> serverTimestamps;
50+
// A set of property names that were annotated with @DocumentId. These properties will be
51+
// populated with document ID values during deserialization, and be skipped during
52+
// serialization.
53+
final Set<String> documentIdPropertyNames;
3754

3855
BeanMapper(Class<T> clazz) {
3956
this.clazz = clazz;
4057
throwOnUnknownProperties = clazz.isAnnotationPresent(ThrowOnExtraProperties.class);
4158
warnOnUnknownProperties = !clazz.isAnnotationPresent(IgnoreExtraProperties.class);
59+
serverTimestamps = new HashSet<>();
60+
documentIdPropertyNames = new HashSet<>();
4261
}
4362

4463
Class<T> getClazz() {
@@ -75,7 +94,38 @@ abstract T deserialize(
7594
Map<TypeVariable<Class<T>>, Type> types,
7695
DeserializeContext context);
7796

78-
void ensureValidDocumentIdType(String fieldDescription, String operation, Type type) {
97+
void applyFieldAnnotations(Field field) {
98+
if (field.isAnnotationPresent(ServerTimestamp.class)) {
99+
Class<?> fieldType = field.getType();
100+
if (fieldType != Date.class && fieldType != Timestamp.class) {
101+
throw new IllegalArgumentException("Field " + field.getName() + " is annotated with @ServerTimestamp but is "
102+
+ fieldType + " instead of Date or Timestamp.");
103+
}
104+
serverTimestamps.add(propertyName(field));
105+
}
106+
107+
if (field.isAnnotationPresent(DocumentId.class)) {
108+
Class<?> fieldType = field.getType();
109+
ensureValidDocumentIdType("Field", "is", fieldType);
110+
documentIdPropertyNames.add(propertyName(field));
111+
}
112+
}
113+
114+
static String propertyName(Field field) {
115+
String annotatedName = annotatedName(field);
116+
return annotatedName != null? annotatedName : field.getName();
117+
}
118+
119+
static String annotatedName(AccessibleObject obj) {
120+
if (obj.isAnnotationPresent(PropertyName.class)) {
121+
PropertyName annotation = obj.getAnnotation(PropertyName.class);
122+
return annotation.value();
123+
}
124+
125+
return null;
126+
}
127+
128+
static void ensureValidDocumentIdType(String fieldDescription, String operation, Type type) {
79129
if (type != String.class && type != DocumentReference.class) {
80130
throw new IllegalArgumentException(
81131
fieldDescription

0 commit comments

Comments
 (0)