[JAVA-2829] Handling OffsetTimeStamp Created: 17/Apr/18  Updated: 27/Oct/23  Resolved: 18/Apr/18

Status: Closed
Project: Java Driver
Component/s: Codecs
Affects Version/s: 3.6.3
Fix Version/s: None

Type: Task Priority: Major - P3
Reporter: Gintautas Sulskus Assignee: Unassigned
Resolution: Works as Designed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Spring Boot 2.0.1.RELEASE



 Description   
Context

I followed the insructions in mongo.github (related to JAVA-1741) to serialise a field of type OffsetDateTime to Bson String.

Neither the codec not the codecProvider are used during the write operations. The field is then stored in the database as Object:

updatedOn Object:
    dateTime "2018-04-16 17:11:09.315Z" Date
    offset "+01:00" String  

On read operations, the codec is invoked for dateTime and offset fields to deserialise them to an object of type OffsetDateTime. Of course it fails because the codec does not know how to process the offset field.

I have not tested this in Spring Boot 1.x as of yet.

Can't really tell whether this is a configuration problem or a bug. Hence the question "what may be wrong here" instead of a suggestion.

Implementation and configuration details

MongoConfig extends AbstractMongoConfiguration

    @Override
    public MongoClient mongoClient() {
        CodecRegistry defaultCodecRegistry = MongoClient.getDefaultCodecRegistry();
 
        Map<BsonType, Class<?>> replacements = new HashMap<BsonType, Class<?>>();
        replacements.put(BsonType.DATE_TIME, OffsetDateTime.class);
        BsonTypeClassMap bsonTypeClassMap = new BsonTypeClassMap(replacements);
        DocumentCodecProvider documentCodecProvider = new DocumentCodecProvider(bsonTypeClassMap);
 
        Codec<OffsetDateTime> offsetDateTimeCodec = new OffsetDateTimeCodec();
 
        CodecRegistry codecRegistry = CodecRegistries.
                fromRegistries(CodecRegistries.fromCodecs(offsetDateTimeCodec),
                        CodecRegistries.fromProviders(documentCodecProvider),
                        defaultCodecRegistry);
 
        MongoClientOptions mcs = MongoClientOptions.builder()
                .codecRegistry(codecRegistry)
                .build();
 
        return new MongoClient(new ServerAddress(), mcs);
    }

DocumentCodecProvider.java

public class DocumentCodecProvider implements CodecProvider {
    private final BsonTypeClassMap bsonTypeClassMap;
 
    public DocumentCodecProvider(final BsonTypeClassMap bsonTypeClassMap) {
        this.bsonTypeClassMap = bsonTypeClassMap;
    }
 
    @Override
    public <T> Codec<T> get(final Class<T> clazz, final CodecRegistry registry) {
        if (clazz == Document.class) {
            // construct DocumentCodec with a CodecRegistry and a BsonTypeClassMap
            return (Codec<T>) new DocumentCodec(registry, bsonTypeClassMap);
        }
 
        return null;
    }
}

OffsetDateTimeCodec.java

public class OffsetDateTimeCodec implements Codec<OffsetDateTime> {
 
    @Override
    public void encode(final BsonWriter writer, final OffsetDateTime value, final EncoderContext encoderContext) {
        writer.writeString(value.toString());
    }
 
    @Override
    public OffsetDateTime decode(final BsonReader reader, final DecoderContext decoderContext) {
        return OffsetDateTime.parse(reader.readString());
    }
 
    @Override
    public Class<OffsetDateTime> getEncoderClass() {
        return OffsetDateTime.class;
    }
}

DocRepository.java

public interface DocRepository extends MongoRepository<DocEntity, String> {
    public List<DocEntity> findAll();
    public SchemaDocumentEntity insert(DocEntity formSchemaDocumentEntity);
}

DocEntity.java

@Document
public class DocEntity {
    
    @Id
    private ObjectId documentId;
    private OffsetDateTime updatedOn;
}



 Comments   
Comment by Gintautas Sulskus [ 17/Apr/18 ]

Ok, I found the problem. I was importing org.bson.codecs.DocumentCodecProvider instead of my own DocumentCodecProvider. I I think it would be better to use something like CustomDocumentCodecProvider in the example.

In the end, I have decided to drop the idea to store OffsetDateTime and just use the Instant type that gets serialised to Date.

Comment by Gintautas Sulskus [ 17/Apr/18 ]

Added a git repo that demonstrates the issue that I am experiencing.

Just run the OffsetDateTimeBsonTest and it will fail attempting to deserialise a String to OffsetDateTime. If you check the embedded database, you will find that updatedOn is stored as an Object rather than a String. Hence, no codec is used.
The test uses embedded MongoDB.

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