Reputation: 1296
I have a main class:
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class ContentModel implements Serializable {
@JsonProperty("serviceData")
private ServiceData serviceData;
}
And nested-class:
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class ServiceData implements Serializable {
@JsonProperty ("dateTimeMessageSend")
private LocalDateTime dateTimeMessageSend;
}
I'm trying to deserialize this by using custom deserialiser:
public class LocalDateTimeDeserializer extends StdDeserializer<LocalDateTime> {
private static final long serialVersionUID = 1L;
protected LocalDateTimeDeserializer() {
super(LocalDateTime.class);
}
@Override
public LocalDateTime deserialize(final JsonParser jp, final DeserializationContext ctxt)
throws IOException {
return LocalDateTime.parse(jp.readValueAs(String.class));
}
}
This is, how I configure my objectMapper:
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
this.objectMapper.registerModule(javaTimeModule);
this.objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
this.objectMapper.registerModule(new Jdk8Module());
this.objectMapper.findAndRegisterModules();
Application receive outside the following json:
{
"serviceData": {
"dateTimeMessageSend": {
"month": "APRIL",
"dayOfYear": 109,
"dayOfWeek": "MONDAY",
"nano": 183251000,
"year": 2021,
"monthValue": 4,
"dayOfMonth": 19,
"hour": 14,
"minute": 52,
"second": 44,
"chronology": {
"calendarType": "iso8601",
"id": "ISO"
}
},
}
}
At the time of LocalDateTime-deserialization, I receive exception:
MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
I suppose, that jackson recognise "dateTimeMessageSend" as an object and unable parse it as a string.
What the way to solve the problem?
Upvotes: 0
Views: 1136
Reputation: 10127
There seems to be some misunderstanding about what you actually receive
in the deserialize
method when Jackson calls your LocalDateTimeSerializer
.
You do not just get a single long string like
{ "month": "APRIL", "dayOfYear": 109, ... }
.
Therefore you cannot just simply call
jp.readValueAs(String.class);
You got a MismatchedInputExcpetion
here, because the parser
encountered a {
instead of a string "something"
.
Actually you get a stream of tokens (beginning with {
)
which you are supposed to consume up to the closing }
token,
extract the relevant parts from this,
and build a LocalDateTime
object from these parts.
See for example Baeldung - Getting started with deserialization in Jackson,
especially the custom deserializer example given there.
Following this tuturial you can implement the deserialize
method like this:
@Override
public LocalDateTime deserialize(final JsonParser jp, final DeserializationContext ctxt)
throws IOException {
JsonNode node = jp.getCodec().readTree(jp);
int year = ((NumericNode) node.get("year")).asInt();
int monthValue = ((NumericNode) node.get("monthValue")).asInt();
int dayOfMonth = ((NumericNode) node.get("dayOfMonth")).asInt();
int hour = ((NumericNode) node.get("hour")).asInt();
int minute = ((NumericNode) node.get("minute")).asInt();
int second = ((NumericNode) node.get("second")).asInt();
return LocalDateTime.of(year, monthValue, dayOfMonth, hour, minute, second);
}
Note that there is quite a bit of redundancy in the received JSON tree representing
the LoclDateTime
. For example: it contains "month": "APRIL"
and
"monthValue": 4
. Therefore you don't need to extract all the
values from the tree, but only some them.
Upvotes: 1