Reputation: 863
I'm having the following error when using Mongo's aggregate with a Java 8 LocalDateTime criteria.
Caused by: org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.time.LocalDateTime.
with the following piece of code
@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);
}
}
You'll find few tests here, LocalDateTime works fine with a Spring repository, a classical query with the Criteria API using a MongoTemplate, but throws this error when creating an Aggregate query. https://github.com/Farael49/spring-mongo-aggregate-localdatetime
I also did a little test replacing the LocalDateTime with the java util Date to show it's not throwing a codec error.
Is there something I can do, or is it a Mongo Driver/Spring issue ?
Thanks
Upvotes: 1
Views: 3538
Reputation: 785
If you want to use LocalDateTime
directly you should provide a codec like this:
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;
}
}
You can register it this way:
@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);
}
where host
and dbName
might be autowired fields of some configuration class.
Upvotes: 2
Reputation: 5652
I think your problem is due to the mongodb java driver not knowing how to serialise the LocalDateTime object. There is a good solution to this problem here: Cannot serialize LocalDate in Mongodb
in your code amending it like this might work:
@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);
}
Upvotes: 2