Spring Mongo Aggregate& LocalDateTime问题

时间:2017-10-18 12:51:05

标签: java spring mongodb java-8

将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问题?

由于

2 个答案:

答案 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);
}

其中hostdbName可能是某个配置类的自动连接字段。

答案 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);
}