Skip to content

Commit 289dbfa

Browse files
committed
feat: Instant support
feat: Instant support
1 parent 829ae48 commit 289dbfa

File tree

3 files changed

+43
-4
lines changed

3 files changed

+43
-4
lines changed

google-cloud-firestore/src/main/java/com/google/cloud/firestore/CustomClassMapper.java

+25-4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.lang.reflect.TypeVariable;
3737
import java.lang.reflect.WildcardType;
3838
import java.math.BigDecimal;
39+
import java.time.Instant;
3940
import java.util.ArrayList;
4041
import java.util.Collection;
4142
import java.util.Collections;
@@ -175,6 +176,9 @@ private static <T> Object serialize(T o, ErrorPath path) {
175176
|| o instanceof FieldValue
176177
|| o instanceof Value) {
177178
return o;
179+
} else if (o instanceof Instant) {
180+
Instant instant = (Instant) o;
181+
return Timestamp.ofTimeSecondsAndNanos(instant.getEpochSecond(), instant.getNano());
178182
} else {
179183
Class<T> clazz = (Class<T>) o.getClass();
180184
BeanMapper<T> mapper = loadOrCreateBeanMapperForClass(clazz);
@@ -233,6 +237,8 @@ private static <T> T deserializeToClass(Object o, Class<T> clazz, DeserializeCon
233237
return (T) convertDate(o, context);
234238
} else if (Timestamp.class.isAssignableFrom(clazz)) {
235239
return (T) convertTimestamp(o, context);
240+
} else if (Instant.class.isAssignableFrom(clazz)) {
241+
return (T) convertInstant(o, context);
236242
} else if (Blob.class.isAssignableFrom(clazz)) {
237243
return (T) convertBlob(o, context);
238244
} else if (GeoPoint.class.isAssignableFrom(clazz)) {
@@ -557,6 +563,19 @@ private static Timestamp convertTimestamp(Object o, DeserializeContext context)
557563
}
558564
}
559565

566+
private static Instant convertInstant(Object o, DeserializeContext context) {
567+
if (o instanceof Timestamp) {
568+
Timestamp timestamp = (Timestamp) o;
569+
return Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos());
570+
} else if (o instanceof Date) {
571+
return Instant.ofEpochMilli(((Date) o).getTime());
572+
} else {
573+
throw deserializeError(
574+
context.errorPath,
575+
"Failed to convert value of type " + o.getClass().getName() + " to Instant");
576+
}
577+
}
578+
560579
private static Blob convertBlob(Object o, DeserializeContext context) {
561580
if (o instanceof Blob) {
562581
return (Blob) o;
@@ -976,13 +995,13 @@ Map<String, Object> serialize(T object, ErrorPath path) {
976995
private void applyFieldAnnotations(Field field) {
977996
if (field.isAnnotationPresent(ServerTimestamp.class)) {
978997
Class<?> fieldType = field.getType();
979-
if (fieldType != Date.class && fieldType != Timestamp.class) {
998+
if (fieldType != Date.class && fieldType != Timestamp.class && fieldType != Instant.class) {
980999
throw new IllegalArgumentException(
9811000
"Field "
9821001
+ field.getName()
9831002
+ " is annotated with @ServerTimestamp but is "
9841003
+ fieldType
985-
+ " instead of Date or Timestamp.");
1004+
+ " instead of Date, Timestamp, or Instant.");
9861005
}
9871006
serverTimestamps.add(propertyName(field));
9881007
}
@@ -997,13 +1016,15 @@ private void applyFieldAnnotations(Field field) {
9971016
private void applyGetterAnnotations(Method method) {
9981017
if (method.isAnnotationPresent(ServerTimestamp.class)) {
9991018
Class<?> returnType = method.getReturnType();
1000-
if (returnType != Date.class && returnType != Timestamp.class) {
1019+
if (returnType != Date.class
1020+
&& returnType != Timestamp.class
1021+
&& returnType != Instant.class) {
10011022
throw new IllegalArgumentException(
10021023
"Method "
10031024
+ method.getName()
10041025
+ " is annotated with @ServerTimestamp but returns "
10051026
+ returnType
1006-
+ " instead of Date or Timestamp.");
1027+
+ " instead of Date, Timestamp, or Instant.");
10071028
}
10081029
serverTimestamps.add(propertyName(method));
10091030
}

google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java

+1
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,7 @@ public void extractFieldMaskFromMerge() throws Exception {
872872
"second.foo",
873873
"second.geoPointValue",
874874
"second.infValue",
875+
"second.instantValue",
875876
"second.longValue",
876877
"second.nanValue",
877878
"second.negInfValue",

google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java

+17
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
import java.nio.charset.StandardCharsets;
7676
import java.text.ParseException;
7777
import java.text.SimpleDateFormat;
78+
import java.time.Instant;
7879
import java.util.ArrayList;
7980
import java.util.Arrays;
8081
import java.util.Collections;
@@ -148,6 +149,7 @@ public final class LocalFirestoreHelper {
148149

149150
public static final Date DATE;
150151
public static final Timestamp TIMESTAMP;
152+
public static final Instant INSTANT;
151153
public static final GeoPoint GEO_POINT;
152154
public static final Blob BLOB;
153155
public static final FooList<SingleField> FOO_LIST = new FooList<>();
@@ -942,6 +944,7 @@ public static class AllSupportedTypes {
942944
public SingleField objectValue = new SingleField();
943945
public Date dateValue = DATE;
944946
public Timestamp timestampValue = TIMESTAMP;
947+
public Instant instantValue = INSTANT;
945948
public List<String> arrayValue = ImmutableList.of("foo");
946949
public String nullValue = null;
947950
public Blob bytesValue = BLOB;
@@ -968,6 +971,7 @@ public boolean equals(Object o) {
968971
&& Objects.equals(objectValue, that.objectValue)
969972
&& Objects.equals(dateValue, that.dateValue)
970973
&& Objects.equals(timestampValue, that.timestampValue)
974+
&& Objects.equals(instantValue, that.instantValue)
971975
&& Objects.equals(arrayValue, that.arrayValue)
972976
&& Objects.equals(nullValue, that.nullValue)
973977
&& Objects.equals(bytesValue, that.bytesValue)
@@ -989,6 +993,10 @@ public boolean equals(Object o) {
989993
Timestamp.ofTimeSecondsAndNanos(
990994
TimeUnit.MILLISECONDS.toSeconds(DATE.getTime()),
991995
123000); // Firestore truncates to microsecond precision.
996+
INSTANT =
997+
Instant.ofEpochSecond(
998+
TimeUnit.MILLISECONDS.toSeconds(DATE.getTime()),
999+
123000); // Firestore truncates to microsecond precision.
9921000
GEO_POINT = new GeoPoint(50.1430847, -122.9477780);
9931001
BLOB = Blob.fromBytes(new byte[] {1, 2, 3});
9941002
SINGLE_FLOAT_MAP = map("float", 0.1F);
@@ -1083,6 +1091,7 @@ public boolean equals(Object o) {
10831091
ALL_SUPPORTED_TYPES_MAP.put("objectValue", map("foo", (Object) "bar"));
10841092
ALL_SUPPORTED_TYPES_MAP.put("dateValue", Timestamp.of(DATE));
10851093
ALL_SUPPORTED_TYPES_MAP.put("timestampValue", TIMESTAMP);
1094+
ALL_SUPPORTED_TYPES_MAP.put("instantValue", TIMESTAMP);
10861095
ALL_SUPPORTED_TYPES_MAP.put("arrayValue", ImmutableList.of("foo"));
10871096
ALL_SUPPORTED_TYPES_MAP.put("nullValue", null);
10881097
ALL_SUPPORTED_TYPES_MAP.put("bytesValue", BLOB);
@@ -1119,6 +1128,14 @@ public boolean equals(Object o) {
11191128
.setSeconds(479978400)
11201129
.setNanos(123000)) // Timestamps supports microsecond precision.
11211130
.build())
1131+
.put(
1132+
"instantValue",
1133+
Value.newBuilder()
1134+
.setTimestampValue(
1135+
com.google.protobuf.Timestamp.newBuilder()
1136+
.setSeconds(479978400)
1137+
.setNanos(123000)) // Instants supports microsecond precision.
1138+
.build())
11221139
.put(
11231140
"arrayValue",
11241141
Value.newBuilder()

0 commit comments

Comments
 (0)