18
18
import static com .google .firebase .firestore .util .ApiUtil .newInstance ;
19
19
20
20
import android .net .Uri ;
21
+ import android .os .Build ;
22
+ import androidx .annotation .RequiresApi ;
21
23
import com .google .firebase .Timestamp ;
22
24
import com .google .firebase .firestore .Blob ;
23
25
import com .google .firebase .firestore .DocumentId ;
42
44
import java .lang .reflect .WildcardType ;
43
45
import java .net .URI ;
44
46
import java .net .URL ;
47
+ import java .time .Instant ;
45
48
import java .util .ArrayList ;
46
49
import java .util .Collection ;
47
50
import java .util .Collections ;
@@ -177,6 +180,9 @@ private static <T> Object serialize(T o, ErrorPath path) {
177
180
|| o instanceof FieldValue
178
181
|| o instanceof VectorValue ) {
179
182
return o ;
183
+ } else if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O && o instanceof Instant ) {
184
+ Instant instant = (Instant ) o ;
185
+ return new Timestamp (instant .getEpochSecond (), instant .getNano ());
180
186
} else if (o instanceof Uri || o instanceof URI || o instanceof URL ) {
181
187
return o .toString ();
182
188
} else {
@@ -237,6 +243,9 @@ private static <T> T deserializeToClass(Object o, Class<T> clazz, DeserializeCon
237
243
return (T ) convertDate (o , context );
238
244
} else if (Timestamp .class .isAssignableFrom (clazz )) {
239
245
return (T ) convertTimestamp (o , context );
246
+ } else if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O
247
+ && Instant .class .isAssignableFrom (clazz )) {
248
+ return (T ) convertInstant (o , context );
240
249
} else if (Blob .class .isAssignableFrom (clazz )) {
241
250
return (T ) convertBlob (o , context );
242
251
} else if (GeoPoint .class .isAssignableFrom (clazz )) {
@@ -512,6 +521,20 @@ private static Timestamp convertTimestamp(Object o, DeserializeContext context)
512
521
}
513
522
}
514
523
524
+ @ RequiresApi (api = Build .VERSION_CODES .O )
525
+ private static Instant convertInstant (Object o , DeserializeContext context ) {
526
+ if (o instanceof Timestamp ) {
527
+ Timestamp timestamp = (Timestamp ) o ;
528
+ return Instant .ofEpochSecond (timestamp .getSeconds (), timestamp .getNanoseconds ());
529
+ } else if (o instanceof Date ) {
530
+ return Instant .ofEpochMilli (((Date ) o ).getTime ());
531
+ } else {
532
+ throw deserializeError (
533
+ context .errorPath ,
534
+ "Failed to convert value of type " + o .getClass ().getName () + " to Instant" );
535
+ }
536
+ }
537
+
515
538
private static Blob convertBlob (Object o , DeserializeContext context ) {
516
539
if (o instanceof Blob ) {
517
540
return (Blob ) o ;
@@ -933,13 +956,15 @@ Map<String, Object> serialize(T object, ErrorPath path) {
933
956
private void applyFieldAnnotations (Field field ) {
934
957
if (field .isAnnotationPresent (ServerTimestamp .class )) {
935
958
Class <?> fieldType = field .getType ();
936
- if (fieldType != Date .class && fieldType != Timestamp .class ) {
959
+ if (fieldType != Date .class
960
+ && fieldType != Timestamp .class
961
+ && !(Build .VERSION .SDK_INT >= Build .VERSION_CODES .O && fieldType == Instant .class )) {
937
962
throw new IllegalArgumentException (
938
963
"Field "
939
964
+ field .getName ()
940
965
+ " is annotated with @ServerTimestamp but is "
941
966
+ fieldType
942
- + " instead of Date or Timestamp ." );
967
+ + " instead of Date, Timestamp, or Instant ." );
943
968
}
944
969
serverTimestamps .add (propertyName (field ));
945
970
}
@@ -954,13 +979,15 @@ private void applyFieldAnnotations(Field field) {
954
979
private void applyGetterAnnotations (Method method ) {
955
980
if (method .isAnnotationPresent (ServerTimestamp .class )) {
956
981
Class <?> returnType = method .getReturnType ();
957
- if (returnType != Date .class && returnType != Timestamp .class ) {
982
+ if (returnType != Date .class
983
+ && returnType != Timestamp .class
984
+ && !(Build .VERSION .SDK_INT >= Build .VERSION_CODES .O && returnType == Instant .class )) {
958
985
throw new IllegalArgumentException (
959
986
"Method "
960
987
+ method .getName ()
961
988
+ " is annotated with @ServerTimestamp but returns "
962
989
+ returnType
963
- + " instead of Date or Timestamp ." );
990
+ + " instead of Date, Timestamp, or Instant ." );
964
991
}
965
992
serverTimestamps .add (propertyName (method ));
966
993
}
0 commit comments