[JAVA-1741] 3.x: How to save java.sql.Timestamp or java.sql.Date? Created: 02/Apr/15  Updated: 18/Jul/16  Resolved: 05/Jan/16

Status: Closed
Project: Java Driver
Component/s: Codecs
Affects Version/s: 3.0.0
Fix Version/s: 3.2.1

Type: Improvement Priority: Major - P3
Reporter: Ngoc Assignee: Jeffrey Yemin
Resolution: Done Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
is duplicated by DRIVERS-277 mongo-java driver 3.0 version throws ... Closed
is duplicated by JAVA-2103 No codec for java.sql.Timestamp Closed
Related
is related to JAVA-2064 Document change in behaviour of Java ... Closed

 Description   

I've followed the tutorial Getting Started with the 3.0 Java Driver:
http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-3.0-java-driver/

But when I save a doc with a java.sql.Timestamp value, there's error about codec.

I'm used to 2.x driver, but new to 3.x driver. Can you update the tutorial to instruct how to save java.sql.Timestamp?



 Comments   
Comment by Jeffrey Yemin [ 13/Jan/16 ]

Closing for 3.2.1 release.

Comment by Githook User [ 05/Jan/16 ]

Author:

{u'username': u'jyemin', u'name': u'Jeff Yemin', u'email': u'jeff.yemin@10gen.com'}

Message: JAVA-1741: In order to preserve backwards compatibility with the 2.x driver, encode instances of java.util.Date subclasses (in particular java.sql.Date and java.sql.Timestamp) as BSON dates.

Note: for java.sql.Timestamp in particular, this can result in information loss, as the nanos field is silently ignored
(it's acknowledged in the javadoc for Timestamp that the inheritance relationship between the two classes is a mistake).

Note: As this is only for backwards compatibility, support for encoding Date subclasses has only been added for DBObject, and not other containers like Document.
Branch: 3.2.x
https://github.com/mongodb/mongo-java-driver/commit/ac638b225bc997cf121913741589182fee039999

Comment by Githook User [ 04/Jan/16 ]

Author:

{u'username': u'jyemin', u'name': u'Jeff Yemin', u'email': u'jeff.yemin@10gen.com'}

Message: JAVA-1741: In order to preserve backwards compatibility with the 2.x driver, encode instances of java.util.Date subclasses (in particular java.sql.Date and java.sql.Timestamp) as BSON dates.

Note: for java.sql.Timestamp in particular, this can result in information loss, as the nanos field is silently ignored
(it's acknowledged in the javadoc for Timestamp that the inheritance relationship between the two classes is a mistake).

Note: As this is only for backwards compatibility, support for encoding Date subclasses has only been added for DBObject, and not other containers like Document.
Branch: master
https://github.com/mongodb/mongo-java-driver/commit/6a2ea9d2665387c589b98311fc453b33c1697ac8

Comment by Alexander Komyagin [ 22/Oct/15 ]

Here's one workaround to get a MongoTemplate in Spring with the converter in place:

MongoClient client = new MongoClient(addr, creds);
MongoDbFactory mongodbFactory = new SimpleMongoDbFactory(client, db);
MongoMappingContext context = new MongoMappingContext();
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongodbFactory);
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, context);
converter.setCustomConversions(new CustomConversions(Collections.singletonList(TimestampToDateConverter.INSTANCE)));
converter.afterPropertiesSet();
 
return new MongoTemplate(mongodbFactory, converter);

and

public enum TimestampToDateConverter implements Converter<java.sql.Timestamp, Date> {
  INSTANCE;
 
  public Date convert(java.sql.Timestamp source) {
      return source == null ? null : new Date(source.getTime());
  }
}

Comment by Jeffrey Yemin [ 02/Sep/15 ]

Yes, you're right, if you're using the DBCollection API. Sorry for the confusion.

Comment by Gui Forget [ 02/Sep/15 ]

Thanks Jeff. I don't believe we can register custom Codec for the DBObjectCodec though, that codec solely use the DefaultCodecRegistry

Comment by Jeffrey Yemin [ 02/Sep/15 ]

It's a mistake that the 2.x driver encodes instances of java.sql.Timestamp, as it silently drops the nanosecond field that's present in that class. We plan to document this backward compatibility break, and suggest that users prepare for this by converting Timestamp to Date, e.g. new Date(timestamp.getTime()).

If that's not possible, then an application can always register a custom Codec, as Ross described in an earlier comment.

Comment by Gui Forget [ 01/Sep/15 ]

Adding it to the Default registry is key so it works also for the DBObjectCodec. After I upgraded to 3.0 I'm getting this error and as far as I know I have no way to fix it other than converting before encoding the DBObject:

org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.sql.Timestamp.
        at org.bson.codecs.configuration.CodecCache.getOrThrow(CodecCache.java:46) ~[mongo-java-driver-3.0.3.jar:?]
        at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:63) ~[mongo-java-driver-3.0.3.jar:?]
        at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:37) ~[mongo-java-driver-3.0.3.jar:?]
        at com.mongodb.DBObjectCodec.writeValue(DBObjectCodec.java:210) ~[mongo-java-driver-3.0.3.jar:?]
        at com.mongodb.DBObjectCodec.encodeMap(DBObjectCodec.java:220) ~[mongo-java-driver-3.0.3.jar:?]
        at com.mongodb.DBObjectCodec.writeValue(DBObjectCodec.java:196) ~[mongo-java-driver-3.0.3.jar:?]
        at com.mongodb.DBObjectCodec.encodeIterable(DBObjectCodec.java:269) ~[mongo-java-driver-3.0.3.jar:?]
        at com.mongodb.DBObjectCodec.writeValue(DBObjectCodec.java:198) ~[mongo-java-driver-3.0.3.jar:?]
        at com.mongodb.DBObjectCodec.encode(DBObjectCodec.java:128) ~[mongo-java-driver-3.0.3.jar:?]
        at com.mongodb.DBObjectCodec.encode(DBObjectCodec.java:61) ~[mongo-java-driver-3.0.3.jar:?]
        at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:63) ~[mongo-java-driver-3.0.3.jar:?]
        at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:29) ~[mongo-java-driver-3.0.3.jar:?]

Comment by Ross Lawley [ 23/Jun/15 ]

Good question - I've reopened and will get back shortly.

Comment by Ngoc [ 23/Jun/15 ]

Thanks for the info.
Why don't you add/provide the codec for java.sql.Timestamp "by default", so that it just works like in the previous version of the driver?

Comment by Ross Lawley [ 23/Jun/15 ]

Hi,

Apologies for the delay, we have added a section on the documentation site regarding Codecs and Codec Registries - http://mongodb.github.io/mongo-java-driver/3.0/bson/codecs/

If you follow that you will be able to create a codec for a java.sql.Timestamp.

The steps are:

1. Create a Codec for the Timestamp
2. Create a BsonTypeClassMap mapping the Bson type to the Timestamp.class
3. Create a new DocumentCodecProvider with the new BsonTypeClassMap
4. Use the CodecRegistries helpers to combine and create a new CodecRegsitry comprised of:

  • The TimestampCodec (using the fromCodecs helper)
  • The new DocumentCodecProvider (using the fromProviders helper)
  • The default registry MongoClient.getDefaultCodecRegistry()

5. Pass the new CodecRegistry to the MongoClientOptions.builder and use when creating a new MongoClient OR pass the CodecRegistry and use the MongoDatabase.withCodecRegistry.

Hope that clarifies the process.

Generated at Thu Feb 08 08:55:22 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.