无法在 Mongodb 中序列化 LocalDate
Cannot serialize LocalDate in Mongodb
我正在使用 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 can't serialize type : class java.time.LocalDate
at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:77)
at com.mongodb.util.JSONSerializers$MapSerializer.serialize(JSONSerializers.java:317)
at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:79)
at com.mongodb.util.JSONSerializers$IterableSerializer.serialize(JSONSerializers.java:290)
at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:79)
at com.mongodb.util.JSON.serialize(JSON.java:54)
at com.mongodb.util.JSON.serialize(JSON.java:40)
at com.mongodb.BasicDBList.toString(BasicDBList.java:38)
at web.MeasureAccess.writeData(MeasureAccess.scala:203)
at web.MeasureAccess.firstTime(MeasureAccess.scala:52)
at web.MeasureAccess$.main(MeasureAccess.scala:262)
at 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)
at java.lang.reflect.Method.invoke(Method.java:483)
at 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
为了完整性。
As Oliver Gierke mentions here
尚不支持此数据类型。我希望这将很快可用。
不幸的是,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);
我建议使用 Morphia or Jongo 之类的东西来包装 MongoDB 驱动程序,因为您可以注册全局映射器以隐式地即时执行这些转换,以便您可以使用 LocalDate 等, 在您的域模型中
对于遇到此问题的任何人,以下转换器将帮助他们朝着正确的方向开始。这个 TypeConverter
在 Date
和 LocalDateTime
之间转换(做出这种区分是因为 OP 特别询问了 LocalDate)。
将以下转换器添加到 Morphia,如下所示:
morphia.getMapper().getConverters().addConverter(new LocalDateTimeConverter());
这是转换器class:
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()));
}
}
我正在使用 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 can't serialize type : class java.time.LocalDate at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:77) at com.mongodb.util.JSONSerializers$MapSerializer.serialize(JSONSerializers.java:317) at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:79) at com.mongodb.util.JSONSerializers$IterableSerializer.serialize(JSONSerializers.java:290) at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:79) at com.mongodb.util.JSON.serialize(JSON.java:54) at com.mongodb.util.JSON.serialize(JSON.java:40) at com.mongodb.BasicDBList.toString(BasicDBList.java:38) at web.MeasureAccess.writeData(MeasureAccess.scala:203) at web.MeasureAccess.firstTime(MeasureAccess.scala:52) at web.MeasureAccess$.main(MeasureAccess.scala:262) at 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) at java.lang.reflect.Method.invoke(Method.java:483) at 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
为了完整性。
As Oliver Gierke mentions here
尚不支持此数据类型。我希望这将很快可用。
不幸的是,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);
我建议使用 Morphia or Jongo 之类的东西来包装 MongoDB 驱动程序,因为您可以注册全局映射器以隐式地即时执行这些转换,以便您可以使用 LocalDate 等, 在您的域模型中
对于遇到此问题的任何人,以下转换器将帮助他们朝着正确的方向开始。这个 TypeConverter
在 Date
和 LocalDateTime
之间转换(做出这种区分是因为 OP 特别询问了 LocalDate)。
将以下转换器添加到 Morphia,如下所示:
morphia.getMapper().getConverters().addConverter(new LocalDateTimeConverter());
这是转换器class:
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()));
}
}