javaspring-bootrestepochjava.time.instant

Instant incorrectly parsing epoch string with rest api


I have a rest API with an input value which is an epoch. However, storing as an Instant ignores the nanos, thus storing it as some date in the future (I think). I could be storing them in the wrong type also as had thought about storing them as a long either.

Example: From the input of 683124845000 I am expecting a date and time in 1991. It is converted to +23617-05-13T13:23:20Z.

public class Booking {
    private Instant epoch;
    private String email;
}

The JSON input is:

{
  "epoch": "683124845000", 
  "email": "email@email.com"
}

Currently, I just have a controller that returns OK regardless of input as I am modeling the input.

@PostMapping("/booking")
    public ResponseEntity createBooking(@RequestBody Booking booking) {
        return ResponseEntity.ok().build();
    }

Solution

  • The default Instant serializer is expecting the epoch to be in seconds. Here are the following solutions:

    1. Use long or Long to store the epoch.
    2. Change your API to expect seconds.
    3. Create custom serializer / deserializer.

    Custom serializer / deserializer implementation:
    (Assuming you want to use milliseconds for your API since the epoch in the question seemed to be in milliseconds)

    Serializer

    public class CustomInstantSerializer extends JsonSerializer<Instant> {
    
        @Override
        public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            long epoch = value.toEpochMilli();
            gen.writeNumber(epoch);
        }
    
    }
    

    Deserializer

    public class CustomInstantDeserializer extends JsonDeserializer<Instant> {
    
        @Override
        public Instant deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
            long epoch = jp.getLongValue();
            return Instant.ofEpochMilli(epoch);
        }
    
    }
    

    Then wiring the serializer / deserializer to the field:

    public class Booking {
    
        @JsonSerialize(using = CustomInstantSerializer.class)
        @JsonDeserialize(using = CustomInstantDeserializer.class)
        private Instant epoch;
    
        private String email;
    
    }