无法在Mongodb中序列化LocalDate

时间:2015-01-06 13:44:43

标签: java json mongodb scala

我使用java 8 java.time.LocalDate来解析日期。

但是尝试将一个LocalDate对象插入到mongodb中。我在java驱动程序中遇到错误:

private def writeData(measure: DBCollection, installation: Int, date: String, dates: ListBuffer[LocalDate],
                    values: ListBuffer[BigDecimal], validated: Boolean, overwrite: Boolean) {
  val timeValues: BasicDBList = new BasicDBList
  var i = 0
  while ( i < dates.size )  {
    val obj: BasicDBObject = new BasicDBObject("time", dates(i))
    obj.put("value", values(i).toString())
    timeValues.add(obj)
    i += 1
  }
  if ( debug ) System.out.println("Storedata: " + timeValues.toString) <-- error here

错误日志:

  

java.lang.RuntimeException:json无法序列化类型:class java.time.LocalDate       at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:77)       在com.mongodb.util.JSONSerializers $ MapSerializer.serialize(JSONSerializers.java:317)       at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:79)       在com.mongodb.util.JSONSerializers $ IterableSerializer.serialize(JSONSerializers.java:290)       at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:79)       在com.mongodb.util.JSON.serialize(JSON.java:54)       在com.mongodb.util.JSON.serialize(JSON.java:40)       在com.mongodb.BasicDBList.toString(BasicDBList.java:38)       在web.MeasureAccess.writeData(MeasureAccess.scala:203)       在web.MeasureAccess.firstTime(MeasureAccess.scala:52)       在web.MeasureAccess $ .main(MeasureAccess.scala:262)       在web.MeasureAccess.main(MeasureAccess.scala)       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)       在java.lang.reflect.Method.invoke(Method.java:483)       在com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

我使用的是mongo-java-driver-2.13.0-rc1.jar 斯卡拉2.11.4 和java 1.8.0_25

完整性。

3 个答案:

答案 0 :(得分:9)

不幸的是,MongoDB驱动程序使用java.util.Date类型,请参阅文档here

因此,您必须先将LocalDate转换为Date实例,例如:

MongoClient mongoClient = new MongoClient("localhost", 27017);
DB db = mongoClient.getDB("test");
DBCollection coll = db.getCollection("testcol");

LocalDate ld = LocalDate.now();
Instant instant = ld.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
Date date = Date.from(instant);

BasicDBObject doc = new BasicDBObject("localdate", date);
coll.insert(doc);

我建议使用类似MorphiaJongo的东西来包装MongoDB驱动程序,因为您可以注册全局映射器以隐式执行这些转换,以便您可以使用LocalDate等,在您的域模型中

答案 1 :(得分:4)

对于遇到此问题的任何人,以下转换器都会让某人开始朝着正确的方向前进。这个TypeConverterDateLocalDateTime之间进行转换(因为OP专门询问了LocalDate,所以区别对待。)

将以下转换器添加到Morphia,如下所示:

morphia.getMapper().getConverters().addConverter(new LocalDateTimeConverter());

这是转换器类:

public class LocalDateTimeConverter extends TypeConverter implements SimpleValueConverter {

    public LocalDateTimeConverter() {
        // TODO: Add other date/time supported classes here
        // Other java.time classes: LocalDate.class, LocalTime.class
        // Arrays: LocalDateTime[].class, etc
        super(LocalDateTime.class);
    }

    @Override
    public Object decode(Class<?> targetClass, Object fromDBObject, MappedField optionalExtraInfo) {
        if (fromDBObject == null) {
            return null;
        }

        if (fromDBObject instanceof Date) {
            return ((Date) fromDBObject).toInstant().atZone(ZoneOffset.systemDefault()).toLocalDateTime();
        }

        if (fromDBObject instanceof LocalDateTime) {
            return fromDBObject;
        }

        // TODO: decode other types

        throw new IllegalArgumentException(String.format("Cannot decode object of class: %s", fromDBObject.getClass().getName()));
    }

    @Override
    public Object encode(Object value, MappedField optionalExtraInfo) {
        if (value == null) {
            return null;
        }

        if (value instanceof Date) {
            return value;
        }

        if (value instanceof LocalDateTime) {
            ZonedDateTime zoned = ((LocalDateTime) value).atZone(ZoneOffset.systemDefault());
            return Date.from(zoned.toInstant());
        }

        // TODO: encode other types

        throw new IllegalArgumentException(String.format("Cannot encode object of class: %s", value.getClass().getName()));
    }
}

答案 2 :(得分:1)

As Oliver Gierke mentions here

目前尚不支持此数据类型。我希望很快就能推出。