Issue
I have this class:
public class MyLocalApplicationClass {
private String name
private LocalDateTime creationDate;
private String createdBy;
}
And in a response that I receive from a rest service I get this object (as a json):
public class MyRemoteApplicationClass {
private String name
private Date creationDate;
private String createdBy;
}
So when I send the request I get the value (json) of creationDate from MyRemoteApplicationClass like this:
{
“name”:”anything”,
"creation_date": 1666190973000,
"created_by": “anyone”
}
So I was wondering if it is possible to receive this as a LocalDateTime or I should receive it as a Date and then cast it to LocalDateTime (think this is my best option)?
Because I am trying to receive it as a LocalDateTime but it throws this error:
"raw timestamp (1656015404000) not allowed for `java.time.LocalDateTime`: need additional information such as an offset or time-zone (see class Javadocs)"
Also I tried to receive it as LocalDate
only, but it throws this error (which I already added the dependency of jsr310 and also added the serializer and deserializer with this annotations @JsonSerialize(using = LocalDateSerializer.class) @JsonDeserialize(using = LocalDateDeserializer.class)
so I think the real problem is the warning) and warning:
Java 8 date/time type `java.time.DateTimeException` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.fasterxml.jackson.databind.JsonMappingException["cause"])
WARN -- com.fasterxml.jackson.databind.JsonMappingException: Invalid value for EpochDay (valid values -365243219162 - 365241780471): 1656015404000
Solution
There are several possible solutions:
- You can declare all-args constructor in your
MyLocalApplicationClass
and annotate each argument with@JsonProperty
. The and the contranctior parametercreationDate
should be received aslong
. It would be parsed from epoch millisecond toLocalDateTime
manually.
Here's it might look like:
public class MyLocalApplicationClass {
private String name;
private LocalDateTime creationDate;
private String createdBy;
public MyLocalApplicationClass(@JsonProperty("name") String name,
@JsonProperty("creationDate") long creationDate,
@JsonProperty("createdBy") String createdBy) {
this.name = name;
this.createdBy = createdBy;
this.creationDate = Instant
.ofEpochMilli(creationDate)
.atZone(ZoneOffset.UTC)
.toLocalDateTime();
}
}
- Another option would be to change the type of
creationDate
property toInstant
. To make working we would need to configureObjectMapper
by registeringJavaTimeModule
module and instructing mapper about the precision of the timestamp, namely setting deserialization propertyDeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS
to false. For that we need to placeJackson2ObjectMapperBuilder
andObjectMapper
as Beans into the Spring's Context.
@Configuration
public class JsonConfig {
@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
return new Jackson2ObjectMapperBuilder();
}
@Bean
public ObjectMapper objectMapper() {
return jackson2ObjectMapperBuilder()
.build()
.registerModule(new JavaTimeModule())
.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
}
}
That would allow deserializing MyLocalApplicationClass
without making use of data-binding annotations (but only if creationDate
would be declared as of type Instant
):
public class MyLocalApplicationClass {
private String name;
private Instant creationDate;
private String createdBy;
// getter, setters, etc.
}
- Lastly, we can implement a custom
Deserializer
and apply it by annotatingcreationDate
field with@JsonDeserialize
annotation.
Answered By - Alexander Ivanchenko
Answer Checked By - Willingham (JavaFixing Volunteer)