将Mongo的聚合与Java 8 LocalDateTime标准一起使用时,我遇到以下错误。
引起:org.bson.codecs.configuration.CodecConfigurationException: 找不到类java.time.LocalDateTime的编解码器。
使用以下代码
@SpringBootApplication
public class MongojavatimeApplication implements CommandLineRunner {
@Autowired
private MongoTemplate template;
public static void main(String[] args) {
SpringApplication.run(MongojavatimeApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
Criteria c = Criteria.where("createdDate").gt(LocalDateTime.now().minusDays(30));
template.aggregate(Aggregation.newAggregation(Aggregation.match(c)), "TestJavaTime", TestJavaTime.class);
}
}
你会在这里找到一些测试,LocalDateTime可以正常使用Spring存储库,使用MongoTemplate使用Criteria API进行经典查询,但在创建聚合查询时会抛出此错误。 https://github.com/Farael49/spring-mongo-aggregate-localdatetime
我还做了一点测试,用java util Date替换LocalDateTime,以显示它没有抛出编解码器错误。
我能做些什么,还是Mongo Driver / Spring问题?
由于
答案 0 :(得分:1)
如果你想直接使用LocalDateTime
,你应该提供这样的编解码器:
public enum LocalDateTimeCodec
implements Codec<LocalDateTime> {
INSTANCE;
@Override
public void encode(
BsonWriter writer,
LocalDateTime value,
EncoderContext encoderContext) {
writer.writeDateTime(
value.toInstant(ZoneOffset.UTC)
.toEpochMilli()
);
}
@Override
public LocalDateTime decode(
BsonReader reader,
DecoderContext decoderContext) {
return Instant.ofEpochMilli(reader.readDateTime())
.atOffset(ZoneOffset.UTC)
.toLocalDateTime();
}
@Override
public Class<LocalDateTime> getEncoderClass() {
return LocalDateTime.class;
}
}
您可以这样注册:
@Bean
public MongoDbFactory mongoDbFactory() throws Exception {
CodecRegistry registry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(LocalDateTimeCodec.INSTANCE),
MongoClient.getDefaultCodecRegistry()
);
MongoClientOptions options = MongoClientOptions
.builder()
.codecRegistry(registry)
.build();
return new SimpleMongoDbFactory(new MongoClient(host, options), dbName);
}
其中host
和dbName
可能是某个配置类的自动连接字段。
答案 1 :(得分:0)
我认为你的问题是由于mongodb java驱动程序不知道如何序列化LocalDateTime对象。这里有一个很好的解决方案:Cannot serialize LocalDate in Mongodb
在您的代码中修改它可能会起作用:
@Override
public void run(String... args) throws Exception {
LocalDateTime startDateTime = LocalDateTime.now().minusDays(30);
Instant startInstant = startDateTime.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
Criteria c = Criteria.where("createdDate").gt(Date.from(startInstant));
template.aggregate(Aggregation.newAggregation(Aggregation.match(c)), "TestJavaTime", TestJavaTime.class);
}