Cannot deserialize localdatetime using mongo and mongojack

1.4k Views Asked by At

I have a simple pojo

import lombok.Data;

@Data
public class DataPojo {
   private LocalDateTime myDate;           
}

When I try to read the pojo from mongo + mongojack

MongoCredential credential = MongoCredential.createCredential(userName, "aDb", password.toCharArray());
MongoClient mongoClient = new MongoClient(new ServerAddress(mongoServer), Arrays.asList(credential));
DB db = mongoClient.getDB("aDb");
DBCollection aCollection = db.getCollection("aCollection");

JacksonDBCollection<DataPojo, String> jDbCol = JacksonDBCollection.wrap(aCollection, DataPojo.class, String.class);
DataPojo d = jDbCol.findOne();

I get the following error

java.lang.RuntimeException: IOException encountered while reading from a byte array input stream
at org.mongojack.internal.stream.JacksonDBDecoder.decode(JacksonDBDecoder.java:67)
...
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Problem deserializing property 'myDate' (expected type: [simple type, class java.time.LocalDateTime]; actual type: java.util.Date), problem: argument type mismatch (through reference chain: DataPojo["myDate"])

I have read things about @JsonDeserialize(using = LocalDateTimeDeserializer.class) and that just leads to other errors.

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (VALUE_EMBEDDED_OBJECT), expected START_ARRAY: Expected array or string.

I am using mongo-java-driver version 3.1.0-rc0, mongojack version 2.5.1. The mongodb that I am running against is 2.6.9. The field that I am trying to read is an ISODate.

It seems like my problem is at the driver level. Is there a way to tell mongo driver to represent dates as java.time.LocalDateTime instead of java.util.Date?

1

There are 1 best solutions below

0
On

Your problem is not at the driver level; MongoDB has no knowledge at all of java.util.Date. But the BSON Date type is nearly identical to java.util.Date in internal representation. Thankfully in the MongoDB shell it's always printed using timezone Z, so it's not too confusing to just ignore the timezone and treat it as a java.time.LocalDateTime instead, but there's no built-in way to make that explicit at the BSON level.

At the mapper level, there are several different ways you can specify the mapping you want here. From your question it's not clear which LocalDateTimeDeserializer you tried using; but you want to make sure first of all that you're using one that targets java.time.LocalDateTime, not org.joda.time.LocalDateTime. If you've checked that and still are having trouble, then you might consider writing your own Converter instead of a Deserializer, which you'd invoke with a nearly identical annotation:

@JsonDeserialize(converter = LocalDateTimeConverter.class)

The difference being that you'd just need to implement a convert method from a java.util.Date to a org.joda.time.LocalDateTime, rather than dealing with JSON streams at all.