spring-data-mongodb icon indicating copy to clipboard operation
spring-data-mongodb copied to clipboard

CodecConfigurationException when saving ZonedDateTime to MongoDB with Spring Boot >= 2.0.1.RELEASE [DATAMONGO-2106]

Open spring-projects-issues opened this issue 6 years ago • 9 comments

thokrae opened DATAMONGO-2106 and commented

I was able to reproduce this bug with a minimal modification of the official Spring Boot guide for Accessing Data with MongoDB, see https://github.com/thokrae/spring-data-mongo-zoneddatetime.

After adding a java.time.ZonedDateTime field to the Customer class, running the example code from the guide fails with a CodecConfigurationException:

Customer.java:

        public String lastName;
        public ZonedDateTime created;

        public Customer() {

output:

...
Caused by: org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.time.ZonedDateTime.
	at org.bson.codecs.configuration.CodecCache.getOrThrow(CodecCache.java:46) ~[bson-3.6.3.jar:na]
	at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:63) ~[bson-3.6.3.jar:na]
	at org.bson.codecs.configuration.ChildCodecRegistry.get(ChildCodecRegistry.java:51) ~[bson-3.6.3.jar:na]
	at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:184) ~[bson-3.6.3.jar:na]
	at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:199) ~[bson-3.6.3.jar:na]
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:141) ~[bson-3.6.3.jar:na]
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:45) ~[bson-3.6.3.jar:na]
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:63) ~[bson-3.6.3.jar:na]
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:29) ~[bson-3.6.3.jar:na]
	at com.mongodb.operation.BulkWriteBatch$WriteRequestEncoder.encode(BulkWriteBatch.java:381) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.operation.BulkWriteBatch$WriteRequestEncoder.encode(BulkWriteBatch.java:371) ~[mongodb-driver-core-3.6.3.jar:na]
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:63) ~[bson-3.6.3.jar:na]
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:29) ~[bson-3.6.3.jar:na]
	at com.mongodb.connection.BsonWriterHelper.writeDocument(BsonWriterHelper.java:74) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.connection.BsonWriterHelper.writePayload(BsonWriterHelper.java:58) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.connection.CommandMessage.encodeMessageBodyWithMetadata(CommandMessage.java:133) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.connection.RequestMessage.encode(RequestMessage.java:147) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:245) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:98) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:441) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:80) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:189) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:264) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.connection.DefaultServerConnection.command(DefaultServerConnection.java:126) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.operation.MixedBulkWriteOperation.executeCommand(MixedBulkWriteOperation.java:372) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.operation.MixedBulkWriteOperation.executeBulkWriteBatch(MixedBulkWriteOperation.java:254) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.operation.MixedBulkWriteOperation.access$700(MixedBulkWriteOperation.java:65) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.operation.MixedBulkWriteOperation$1.call(MixedBulkWriteOperation.java:198) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.operation.MixedBulkWriteOperation$1.call(MixedBulkWriteOperation.java:189) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.operation.OperationHelper.withReleasableConnection(OperationHelper.java:433) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.operation.MixedBulkWriteOperation.execute(MixedBulkWriteOperation.java:189) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.operation.MixedBulkWriteOperation.execute(MixedBulkWriteOperation.java:65) ~[mongodb-driver-core-3.6.3.jar:na]
	at com.mongodb.Mongo$3.execute(Mongo.java:837) ~[mongodb-driver-3.6.3.jar:na]
	at com.mongodb.MongoCollectionImpl.executeSingleWriteRequest(MongoCollectionImpl.java:1025) ~[mongodb-driver-3.6.3.jar:na]
	at com.mongodb.MongoCollectionImpl.executeInsertOne(MongoCollectionImpl.java:513) ~[mongodb-driver-3.6.3.jar:na]
	at com.mongodb.MongoCollectionImpl.insertOne(MongoCollectionImpl.java:493) ~[mongodb-driver-3.6.3.jar:na]
	at com.mongodb.MongoCollectionImpl.insertOne(MongoCollectionImpl.java:487) ~[mongodb-driver-3.6.3.jar:na]
	at org.springframework.data.mongodb.core.MongoTemplate$8.doInCollection(MongoTemplate.java:1276) ~[spring-data-mongodb-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:524) ~[spring-data-mongodb-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.data.mongodb.core.MongoTemplate.insertDocument(MongoTemplate.java:1270) ~[spring-data-mongodb-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.data.mongodb.core.MongoTemplate.doInsert(MongoTemplate.java:1051) ~[spring-data-mongodb-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.data.mongodb.core.MongoTemplate.insert(MongoTemplate.java:988) ~[spring-data-mongodb-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:80) ~[spring-data-mongodb-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
	at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:377) ~[spring-data-commons-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) ~[spring-data-commons-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:629) ~[spring-data-commons-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:593) ~[spring-data-commons-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:578) ~[spring-data-commons-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
	at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.0.7.RELEASE.jar:2.0.7.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
	at com.sun.proxy.$Proxy48.save(Unknown Source) ~[na:na]
	at com.enbw.App.run(App.java:23) [classes/:na]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:797) [spring-boot-2.0.2.RELEASE.jar:2.0.2.RELEASE]
	... 5 common frames omitted

This can be solved by changing the Spring Boot version from 2.0.5.RELEASE to 2.0.1.RELEASE in the pom.xml (the version of spring-mongo-db changes from 2.0.10.RELEASE to 2.0.6.RELEASE):

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
</parent>

Now the exception is gone and the Customer objects including the ZonedDateTime fields are written to MongoDB.

Would you agree this is a breaking change in a point release and therefore a bug?


Affects: 2.0.10 (Kay SR10)

1 votes, 3 watchers

spring-projects-issues avatar Oct 08 '18 07:10 spring-projects-issues

Oliver Drotbohm commented

ZonedDateTime is not a type MongoDB understands. Spring Data in turn only supports date-time-types without time zone information out of the box as only those types guarantee orderability of the values in the database. See the reference documentation for details.

If you want to persist types that carry time zone information you need to map them yourself, i.e. register custom converters for them

spring-projects-issues avatar Oct 08 '18 07:10 spring-projects-issues

Oliver Drotbohm commented

I just checked your code sample and also can't get this to work on 2.0.1 as the app fails to bootstrap with a different error coming from Spring Data

spring-projects-issues avatar Oct 08 '18 07:10 spring-projects-issues

thokrae commented

Thank you for the reponse.

The example code runs with 2.0.1.RELEASE if I provide the connection details of a MongoDB cluster in the application.properties.

spring.data.mongodb.host=***
spring.data.mongodb.port=***
spring.data.mongodb.database=***
spring.data.mongodb.user=
spring.data.mongodb.pw=***

Screenshot of the result in MongoBooster

I also had another exception when trying to connect to a local MongoDB instance on a Ubuntu 18.04 system, but assumed this was a configuration issue

spring-projects-issues avatar Oct 08 '18 08:10 spring-projects-issues

Oliver Drotbohm commented

I am running into an exception that a parameter name cannot be determined on 2.0.1. In general, as documented, date time types with time zones are not supported

spring-projects-issues avatar Oct 08 '18 08:10 spring-projects-issues

MongoDB Java driver has support for ZonedDateTime for version >= 3.7, Implementation details

dineshbhagat avatar Feb 19 '21 09:02 dineshbhagat

@dineshbhagat thanks for the heads up. We'll look into this.

christophstrobl avatar Feb 19 '21 09:02 christophstrobl

MongoDB Java driver has support for ZonedDateTime for version >= 3.7, Implementation details

My bad 😞, there is only the following codec as of now in version 4.2

InstantCodec
LocalDateCodec
LocalDateTimeCodec
LocalTimeCodec

dineshbhagat avatar Feb 19 '21 10:02 dineshbhagat

MongoDB Java driver has support for ZonedDateTime for version >= 3.7, Implementation details

No, for ZonedDateTime we still need to add bson-codecs-jsr310 dependency and then register the codec.

<dependency>
    <groupId>io.github.cbartosiak</groupId>
    <artifactId>bson-codecs-jsr310</artifactId>
    <version>3.5.4</version>
</dependency>

singh-abhijeet avatar Sep 22 '21 10:09 singh-abhijeet

I am really facing issue with LocalDate and LocalDateTime. When i saved or retrive or delete by date everything seems to work with default setting. I did not do anythig special for jsr310. Except changing date before saving like below - .date( LocalDate.of( v.getDate().getYear(), v.getDate().getMonth(), v.getDate().getDayOfMonth()) .atStartOfDay(ZoneOffset.UTC) .toInstant() .atZone(ZoneOffset.UTC) .toLocalDate())

but the only problem i see when i look at db .. in database date is one day less and time is 1 hr less to actual. i was expecting it should save exact same value but its not. Even for Insant its same.

rahulcse1 avatar Jan 11 '24 20:01 rahulcse1