KeTr
KeTr

Reputation: 67

MongoDB POJO custom Codecs for nested Classes

mongodb-driver-sync version 3.8.2

I'm trying to write a Class Parent into the MongoDB database.

class Parent {

  private Child child;

}

class Child {

  private int a;
  private String b;

}

I want to have custom codecs for both Classes and register them in a central location:


 ConnectionString connString = new ConnectionString(connectionString);

 MongoClientSettings settings = MongoClientSettings.builder()
        .applyConnectionString(connString)
        .codecRegistry(
            CodecRegistries.fromRegistries(
                MongoClientSettings.getDefaultCodecRegistry(),
                CodecRegistries.fromCodecs(
                        ////////////////////
                        //// HERE///////////
                        ////////////////////
                     new ParentCodec(), new ChildCodec()
                ))
        ).build();

MongoClient client = MongoClients.create(settings);
........

However I'm unable to find out how to implement ParentCodec correctly. Any examples I find are newing a DocumentCodec inside their custom Codec, which they then use to encode the document they generate, like so:

public class ParentCodec implements Codec<Parent> {

  private Codec<Document> documentCodec = new DocumentCodec();

  @Override
  public void encode(BsonWriter bsonWriter,
                     Parent parent,
                     EncoderContext encoderContext)
  {
    Document doc = new Document();

    doc.put("child", parent.getChild());

    documentCodec.encode(bsonWriter, doc, encoderContext);
  }
}

This fails, because the newed DocumentCodec only knows the codecs in the DefaultCodecRegistry:

org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class package.Child.
    at org.bson.codecs.configuration.CodecCache.getOrThrow(CodecCache.java:46)
    at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:63)
    at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:37)
    at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:184)
    at org.bson.codecs.DocumentCodec.writeIterable(DocumentCodec.java:207)
    at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:180)
    at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:199)
    at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:141)
    at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:45)

Is there any way around this? I mean, I could obviously do something like this:

public class ParentCodec implements Codec<Parent> {

  private Codec<Document> documentCodec = new DocumentCodec(
      CodecRegistries.fromRegistries(
          MongoClientSettings.getDefaultCodecRegistry(),
          CodecRegistries.fromCodecs(
              new ChildCodec()
          )));

But this is ugly and I lose out on being able to register all my codecs in one central location. Anything else, that I missed?

Upvotes: 2

Views: 3089

Answers (1)

Collin Krawll
Collin Krawll

Reputation: 2520

Pass the CodecRegistry to your codecs. Then in the codecs, get the DocumentCodec from the registry (using registry.get(Document.class)) instead of calling new.

The DocumentCodec will then be aware of all of the other Codecs in the registry.

ParentCodec

public class ParentCodec implements Codec<Parent> {
    private final CodecRegistry registry;
    private final Codec<Document> documentCodec;

    /**
     * Registry constructor.
     *
     * @param registry The CodecRegistry to use.
     */
    public ParentCodec(CodecRegistry registry) {
        this.registry = registry;
        this.documentCodec = this.registry.get(Document.class);
    }
    // ...
}

Main

public class Main {
    public static void main(String[] args) {
        // ...
        CodecRegistry codecRegistry = MongoClient.getDefaultCodecRegistry();
        codecRegistry = CodecRegistries.fromRegistries(
            CodecRegistries.fromCodecs(new ParentCodec(codecRegistry), new ChildCodec(codecRegistry)),
            codecRegistry
        );
        // ...
    }
}

Upvotes: 1

Related Questions