deserializing error with date - JSON decoding error - java

I am getting a response from an api and it is failing to deserialize a date which looks like this "2021-09-10T21:48:35.352+0000". I have set up attribute in my class like below
#JsonProperty("processedAt")
private LocalDateTime processedAt;
org.springframework.core.codec.DecodingException: JSON decoding error: Cannot deserialize value of type java.time.LocalDateTime from String "2021-09-10T21:48:35.352+0000": Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text '2021-09-10T21:48:35.352+0000' could not be parsed, unparsed text found at index 23;
what format of date should I be using in class to get the date out and not fail on deserializing. thanks in advance

By default Jackson does not support this date time format pattern. Therefore you need to explicitly mention that using #JsonFormat annotation. Like this,
#JsonProperty("processedAt")
#JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private LocalDateTime processedAt;
Looking at your datetime format, you should probably use OffsetDateTime instead of LocalDateTime. Otherwise your timezone will be ignored (If you local timezone is +0000, then LocalDateTime should be fine).
#JsonProperty("processedAt")
#JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private OffsetDateTime processedAt;
Update
If you use OffsetDateTime, then you don't need to explicitly mention the pattern using #JsonFormat annotation. Something like this sufficient.
#JsonProperty("processedAt")
private OffsetDateTime processedAt;

I did not check but you are using LocalDateTime and are trying to deserialize a ZonedDateTime. Maybe change the type?
That is also in agreement with the error message that states that the error is at position 23. Exactly where the unexpected zone information starts.

Related

Java LocalDate format from reading from JSON and saving to Database

In as Spring Boot app, I am reading LocalDate from a JSON in dd/MM/yyyy format e.g. 15/03/2009 and while reading, I created them to a request. The format in the request is dd/MM/yyyy.
*ProductRequest:
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")
private LocalDate buyingDate;
And then I save the date fields to database via my Entity. It also has the same format as shown below:
*ProductEntity:
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")
private LocalDate buyingDate;
But the data in the database is shown in yyyy-MM-dd format. I think it is default format for LocalDate, but I need to be clarified about these points: Could you helps me please?
1. Does LocalDate always kept in yyyy-MM-dd format in the database independently from it had in JSON file and in Request?
2. As far as I see, the format while reading the data to ProductRequest is related to the usage when displaying data using this class (ProductRequest). IS that true?
3. Is there any need to use #JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy") for the date field in ProductEntity? As far as I see, it does not make any sense for the format when saving to database. So, if we do not display or use date field from this entity, then there is no need to use format annotation. Is that true?
Does LocalDate always kept in yyyy-MM-dd format in the database independently from it had in JSON file and in Request?
The JSON representation you use has nothing to do with how data is stored in the database[*]. Each database vendor (Oracle, MySQL, Postgres, SQLServer, etc) has its own way of storing date and date+time values. It's the job of your application or framework (eg, Hibernate) to translate from Java types such as LocalDate into the appropriate format for SQL statements. So the answer is "yes," the format of a date in the application is independent from how it's stored in a database.
As far as I see, the format while reading the data to ProductRequest is related to the usage when displaying data using this class (ProductRequest). IS that true?
Only if you serialize ProductRequest back out to JSON. #JsonFormat applies to both reading (deserializing) and writing (serializing) from/to JSON.
Is there any need to use #JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy") for the date field in ProductEntity? As far as I see, it does not make any sense for the format when saving to database. So, if we do not display or use date field from this entity, then there is no need to use format annotation. Is that true?
That is correct. In fact, it's very misleading to see that annotation in an entity[*]
[1] Unless you are using a database that natively understands JSON and/or stores data internally as JSON.

Parse string date to OffsetDateTime when time zone information is missing

I'm receiving a string time object from a third party that looks like this: 12/12/2021 3:34:30 PM. The time zone information is missing but I know it is UTC.
I'm using Jackson to parse the csv and have been playing around with the annotations to try and get it to parse correctly. Here is what I currently have:
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "M/d/yyyy h:mm:ss a", timezone = "UTC", lenient = OptBoolean.TRUE)
protected OffsetDateTime shareDate
which gives me the error:
com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.time.OffsetDateTime` from String "12/12/2021 3:34:30 PM": Failed to deserialize java.time.OffsetDateTime: (java.time.DateTimeException) Unable to obtain OffsetDateTime from TemporalAccessor: {InstantSeconds=1639323270},ISO,UTC resolved to 2021-12-12T15:34:30 of type java.time.format.Parsed
I can change the OffsetDateTime to LocalDateTime and it works. I would rather save it as an OffsetDateTime since I do know it is always UTC. Anyone out there know how to set the annotation to get that to work? Or is it not possible that way?

Java Spring deserializing ISO Zulu time error

I am trying to parse dates with the format "yyyy-MM-dd'T'HH:mm:ssZ". I have a controller with a POST endpoint which takes an object. In that object is a date field of object type "Instant". it has the following annotations:
#JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssZ")
#JsonSerialize(using = InstantSerializer.class)
#JsonDeserialize(using = DefaultInstantDeserializer.class)
private Instant endTime;
I had to create the DefaultInstantDeserializer because using the provided one gave me an error because InstantDeserializer (from the jackson-datatype library) has no no-args constructor.
This is that class
public class DefaultInstantDeserializer extends InstantDeserializer<Instant> {
public DefaultInstantDeserializer() {
super(Instant.class, DateTimeFormatter.ISO_INSTANT,
Instant::from,
a -> Instant.ofEpochMilli(a.value),
a -> Instant.ofEpochSecond(a.integer, a.fraction),
null,
true // yes, replace zero offset with Z
);
}
}
using Postman, I sent the object, with that field being 2022-02-08T15:22:24+00:00
I get this error from in the logs from Spring:
Failed to deserialize java.time.Instant: (java.time.format.DateTimeParseException) Text '2022-02-08T15:14:28+00:00' could not be parsed at index 19\n
It looks like it cannot parse the time starting at +00:00. I thought the Z indicated Zulu time/ GMT/ UTC time, which is a 0 offset. Is "yyyy-MM-dd'T'HH:mm:ssZ" not a valid date format? My requirements say I must use that pattern. In Postman the pattern I am using to send the data is YYYY-MM-DDTHH:mm:ssZ. There is some disconnect between the 0 offset and the Z value, I thought the deserializer would take care of that, but I think not. Any suggestions?
Thanks

Jackson not de-serializing dates properly?

I have the following field in my Java class to record timestamps:
#JsonProperty
#JsonFormat(pattern = "YYYY-MM-dd hh:mm:ss", timezone = "GMT")
private Date timestamp;
This object is created and persisted in a database. This works fine, but when fetching the record from the DB which contains the correct date, Jackson de-serializes the JSON incorrectly by always setting the month and day to 12-30.
e.g. if I create a record with this timestamp:
2020-01-02 12:30:00
Jackson will deserialize it as:
2020-12-30 12:30:00
This happens every time and I don't know what's causing it. Can anyone help?
Your pattern is mixing up minutes vs. months among other things. See the doc for SimpleDateFormat
You probably want: #JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT")

Validate Date in the request body

I have a request body have date field and I want to validate the input of the date and return error code 400 BadRequest if the format is wrong.
If I use the JsonFormat then it throws error 500:
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd")
private Date dateAt;
So I changed the field to String and then parse and throw BadRequest format everywhere using the getDate()
I am not really satisfied with this approach. Is there any other elegant way to achieve this validation?
I think I will accept error 500 from JSON formatter and skip my custom exception.
Since Java 8, you should avoid using Date. Java 8 brought an entirely new date and time API.
According to your question, a suitable replacement for Date would be LocalDate, which is expected to be in the format yyyy-MM-dd.
Jackson has a module supporting the new date and time API and an exception will be thrown if the date is not in the correct format. When serializing, you want to make sure the WRITE_DATES_AS_TIMESTAMPS feature is disabled, so the values will be written according to the ISO 8601 format.

Categories