1818import static com .google .firebase .firestore .util .ApiUtil .newInstance ;
1919
2020import android .net .Uri ;
21+ import android .os .Build ;
22+ import androidx .annotation .RequiresApi ;
2123import com .google .firebase .Timestamp ;
2224import com .google .firebase .firestore .Blob ;
2325import com .google .firebase .firestore .DocumentId ;
4143import java .lang .reflect .WildcardType ;
4244import java .net .URI ;
4345import java .net .URL ;
46+ import java .time .Instant ;
4447import java .util .ArrayList ;
4548import java .util .Collection ;
4649import java .util .Collections ;
@@ -175,6 +178,9 @@ private static <T> Object serialize(T o, ErrorPath path) {
175178 || o instanceof DocumentReference
176179 || o instanceof FieldValue ) {
177180 return o ;
181+ } else if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O && o instanceof Instant ) {
182+ Instant instant = (Instant ) o ;
183+ return new Timestamp (instant .getEpochSecond (), instant .getNano ());
178184 } else if (o instanceof Uri || o instanceof URI || o instanceof URL ) {
179185 return o .toString ();
180186 } else {
@@ -235,6 +241,8 @@ private static <T> T deserializeToClass(Object o, Class<T> clazz, DeserializeCon
235241 return (T ) convertDate (o , context );
236242 } else if (Timestamp .class .isAssignableFrom (clazz )) {
237243 return (T ) convertTimestamp (o , context );
244+ } else if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O && Instant .class .isAssignableFrom (clazz )) {
245+ return (T ) convertInstant (o , context );
238246 } else if (Blob .class .isAssignableFrom (clazz )) {
239247 return (T ) convertBlob (o , context );
240248 } else if (GeoPoint .class .isAssignableFrom (clazz )) {
@@ -508,6 +516,20 @@ private static Timestamp convertTimestamp(Object o, DeserializeContext context)
508516 }
509517 }
510518
519+ @ RequiresApi (api = Build .VERSION_CODES .O )
520+ private static Instant convertInstant (Object o , DeserializeContext context ) {
521+ if (o instanceof Timestamp ) {
522+ Timestamp timestamp = (Timestamp ) o ;
523+ return Instant .ofEpochSecond (timestamp .getSeconds (), timestamp .getNanoseconds ());
524+ } else if (o instanceof Date ) {
525+ return Instant .ofEpochMilli (((Date ) o ).getTime ());
526+ } else {
527+ throw deserializeError (
528+ context .errorPath ,
529+ "Failed to convert value of type " + o .getClass ().getName () + " to Instant" );
530+ }
531+ }
532+
511533 private static Blob convertBlob (Object o , DeserializeContext context ) {
512534 if (o instanceof Blob ) {
513535 return (Blob ) o ;
@@ -919,13 +941,14 @@ Map<String, Object> serialize(T object, ErrorPath path) {
919941 private void applyFieldAnnotations (Field field ) {
920942 if (field .isAnnotationPresent (ServerTimestamp .class )) {
921943 Class <?> fieldType = field .getType ();
922- if (fieldType != Date .class && fieldType != Timestamp .class ) {
944+ if (fieldType != Date .class && fieldType != Timestamp .class
945+ && ! (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O && fieldType == Instant .class )) {
923946 throw new IllegalArgumentException (
924947 "Field "
925948 + field .getName ()
926949 + " is annotated with @ServerTimestamp but is "
927950 + fieldType
928- + " instead of Date or Timestamp ." );
951+ + " instead of Date, Timestamp, or Instant ." );
929952 }
930953 serverTimestamps .add (propertyName (field ));
931954 }
@@ -940,13 +963,14 @@ private void applyFieldAnnotations(Field field) {
940963 private void applyGetterAnnotations (Method method ) {
941964 if (method .isAnnotationPresent (ServerTimestamp .class )) {
942965 Class <?> returnType = method .getReturnType ();
943- if (returnType != Date .class && returnType != Timestamp .class ) {
966+ if (returnType != Date .class && returnType != Timestamp .class
967+ && ! (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O && returnType == Instant .class )) {
944968 throw new IllegalArgumentException (
945969 "Method "
946970 + method .getName ()
947971 + " is annotated with @ServerTimestamp but returns "
948972 + returnType
949- + " instead of Date or Timestamp ." );
973+ + " instead of Date, Timestamp, or Instant ." );
950974 }
951975 serverTimestamps .add (propertyName (method ));
952976 }
0 commit comments