Most of these answers are ancient. The Mongo driver is much newer and has changed dramatically. Here is an answer as of March 6, 2019 - using the most recent version of the Mongo Java driver - version 3.10.1, using most recent version of Joda time - 2.10.1. I intentionally use fully qualified class names so there is no confusion on the libraries in use. As such, there is no need for any import statements.
**
Edit 2019-03-09:
Feedback from user @OleV.V. (see comments below) indicate perhaps Joda Time is less favorable over the Java 8 java.time libraries. Upon investigation I find the current MongoDB Java driver supports the java.time.Instant.now() method properly and saves an ISODate without the need of a codec. The information provided here illustrates how to add a custom codec to the driver. For this reason alone I believe there is value in this answer.
**
My answer is derived from work from SquarePegSys BigDecimalCodec.java found at https://gist.github.com/squarepegsys/9a97f7c70337e7c5e006a436acd8a729, the difference is their solution is geared towards supporting big decimal values, my solution is geared toward Joda DateTime compatibility.
I like to provide the output of the program first, before showing source code. This way you can evaluate if the output is providing the solution you are seeking before investing time digesting and understanding the code. Again, the point is to save a date value as an ISODate datatype in mongoDB using Joda time, i.e., so the saved DateTime is not saved as a string.
I am using Maven to build. I am running Ubuntu 18.04LTS.
$ mvn -version
Apache Maven 3.5.2
Maven home: /usr/share/maven
Java version: 10.0.2, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "4.15.0-43-generic", arch: "amd64", family: "unix"
Build the program:
cd <directory holding pom.xml file>
mvn package
Run the program:
$ java -jar Test.jar
Mar 06, 2019 5:12:02 PM com.mongodb.diagnostics.logging.JULLogger log
INFO: Cluster created with settings {hosts=[127.0.0.1:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
Mar 06, 2019 5:12:03 PM com.mongodb.diagnostics.logging.JULLogger log
INFO: Opened connection [connectionId{localValue:1, serverValue:9}] to 127.0.0.1:27017
Mar 06, 2019 5:12:03 PM com.mongodb.diagnostics.logging.JULLogger log
INFO: Monitor thread successfully connected to server with description ServerDescription{address=127.0.0.1:27017, type=STANDALONE, state=CONNECTED, ok=true, version=ServerVersion{versionList=[4, 0, 6]}, minWireVersion=0, maxWireVersion=7, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=3220919}
Mar 06, 2019 5:12:03 PM com.mongodb.diagnostics.logging.JULLogger log
INFO: Opened connection [connectionId{localValue:2, serverValue:10}] to 127.0.0.1:27017
Query results using mongo shell:
MongoDB > db.testcollection.find().pretty()
{
"_id" : ObjectId("5c806e6272b3f469d9969157"),
"name" : "barry",
"status" : "cool",
"number" : 1,
"date" : ISODate("2019-03-07T01:05:38.381Z")
}
Source Code
There are a total of 4 classes implemented (the pom.xml file is just a build tool file)...
- Main
- Transformer
- Provider
- Codec
pom.xml
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test.barry</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>test</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<outputDirectory>${basedir}</outputDirectory>
<finalName>Test</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>test.barry.Main</mainClass>
</transformer>
</transformers>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.10.1</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
</project>
Main.java
package test.barry;
public class Main {
public static void main(String[] args) {
java.util.ArrayList<com.mongodb.ServerAddress> hosts = new java.util.ArrayList<com.mongodb.ServerAddress>();
hosts.add(new com.mongodb.ServerAddress("127.0.0.1", 27017));
com.mongodb.MongoCredential mongoCredential = com.mongodb.MongoCredential.createScramSha1Credential("testuser", "admin", "mysecret".toCharArray());
org.bson.BSON.addEncodingHook(org.joda.time.DateTime.class, new test.barry.DateTimeTransformer());
org.bson.codecs.configuration.CodecRegistry codecRegistry = org.bson.codecs.configuration.CodecRegistries.fromRegistries(
org.bson.codecs.configuration.CodecRegistries.fromProviders(
new test.barry.DateTimeCodecProvider()
), com.mongodb.MongoClient.getDefaultCodecRegistry()
);
com.mongodb.MongoClientSettings mongoClientSettings = com.mongodb.MongoClientSettings.builder()
.applyToClusterSettings(clusterSettingsBuilder -> clusterSettingsBuilder.hosts(hosts))
.credential(mongoCredential)
.writeConcern(com.mongodb.WriteConcern.W1)
.readConcern(com.mongodb.ReadConcern.MAJORITY)
.readPreference(com.mongodb.ReadPreference.nearest())
.retryWrites(true)
.codecRegistry(codecRegistry)
.build();
com.mongodb.client.MongoClient client = com.mongodb.client.MongoClients.create(mongoClientSettings);
com.mongodb.client.MongoDatabase db = client.getDatabase("testdb");
com.mongodb.client.MongoCollection<org.bson.Document> collection = db.getCollection("testcollection");
// BUILD UP A DOCUMENT
org.bson.Document document = new org.bson.Document("name", "barry")
.append("status", "cool")
.append("number", 1)
.append("date", new org.joda.time.DateTime());
collection.insertOne(document);
}
}
DateTimeCodec.java
package test.barry;
public class DateTimeCodec implements org.bson.codecs.Codec<org.joda.time.DateTime> {
@Override
public void encode(final org.bson.BsonWriter writer, final org.joda.time.DateTime value, final org.bson.codecs.EncoderContext encoderContext) {
writer.writeDateTime(value.getMillis());
}
@Override
public org.joda.time.DateTime decode(final org.bson.BsonReader reader, final org.bson.codecs.DecoderContext decoderContext) {
return new org.joda.time.DateTime(reader.readDateTime());
}
@Override
public Class<org.joda.time.DateTime> getEncoderClass() {
return org.joda.time.DateTime.class;
}
}
DateTimeCodecProvider.java
package test.barry;
public class DateTimeCodecProvider implements org.bson.codecs.configuration.CodecProvider {
@Override
public <T> org.bson.codecs.Codec<T> get(final Class<T> classToVerify, final org.bson.codecs.configuration.CodecRegistry registry) {
if (classToVerify == org.joda.time.DateTime.class) {
return (org.bson.codecs.Codec<T>) new DateTimeCodec();
}
return null;
}
}
DateTimeTransformer.java
package test.barry;
public class DateTimeTransformer implements org.bson.Transformer {
@Override
public Object transform(Object objectToTransform) {
org.joda.time.DateTime value = (org.joda.time.DateTime) objectToTransform;
return value;
}
}
Conclusion
The java world seems to be gravitating towards Joda time. Its a nice library and provides relief for common date/time needs. My guess is Mongo will natively support this library but for now we must help it along.
Quick note: I attempted to use the most modern mongoDB classes, but in class Main.java, I refer to an older library method - com.mongodb.MongoClient.getDefaultCodecRegistry() as I could not find it in com.mongodb.client.MongoClient. If you identify how to use com.mongodb.client.MongoClient instead please add a comment...