Uploaded image for project: 'Java Driver'
  1. Java Driver
  2. JAVA-3665

Polymorphic POJO mapping does not work with package registration only

    • Type: Icon: Bug Bug
    • Resolution: Works as Designed
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: 3.12.2
    • Component/s: POJO
    • None
    • Environment:
      Java 8, Mongodb server 3.6, mongodb-driver-sync 3.12.2

      When polymorphic classes are used with @BsonDiscriminator, attempts to read/deserialize POJOs that return polymorhpic results (any of the derived classes may be returned) will fail, unless you do one of two things:

      • Register every class explicitly (not just the package)
      • Use a concrete instead of every derived class before attempting to read it.

      The suggestion initially given by mongodb support (reading from Collection<DerivedClass> instead of Collection<BaseClass> is not workable, because you cannot read a list of mixed types e.g.
      MongoCursor<MessageBase> cursor = msgs.find().iterator();
      while (cursor.hasNext()) { ... }
      {{}}

      The issue seems to be that simply registering the package as prescribed
      CodecProvider pojoCodecProvider = PojoCodecProvider.builder().register(myPackage).build();
      CodecRegistry pojoCodecRegistry = CodecRegistries.fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), CodecRegistries.fromProviders(pojoCodecProvider));
      mongoClient = MongoClients.create(MongoClientSettings.builder()
      .applyConnectionString(new ConnectionString(mongodbURI))
      .codecRegistry(pojoCodecRegistry).build());
      collection = mongoClient.getDatabase(mongodbDatabase).getCollection(mongodbCollection, entityClass);
      {{}}

      is not enough. Attempting to read from the database results in the following error:
      ERROR: An exception occurred when decoding using the AutomaticPojoCodec.
      Decoding into a 'Derived1' failed with the following exception:
      Failed to decode 'Derived1'. Decoding errored with: A class could not be found for the discriminator: 'derived1'.
      A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type. 
      Polymorphism does work if concrete classes are first utilized before an attempt is made to read polymorphically. Please see the attached "scratch.zip" example which is built using maven. It is a CLI with three commands:

      • clear: clear the table
      • write: write two objects to table, then read them back polymorphically
      • read: read objects polymorphically

      When you run this, you'll see that the write command works as expected, returning a polymorphic list, but the read command fails if that is the first command run in a process. The only difference is that the write command first inserts  Derived1 and Dervied2 before reading them back. Clearly, it must somehow convince the POJO codec to believe that the derived classes all exist before it can read them. 

      Changing the codec registration to 

      CodecProvider pojoCodecProvider = PojoCodecProvider.builder().register(Base.class, Derived1.class, Derived2.class).build(); CodecProvider pojoCodecProvider = PojoCodecProvider.builder().register(Base.class, Derived1.class, Derived2.class).build();

      Works as expected.

            Assignee:
            ross@mongodb.com Ross Lawley
            Reporter:
            john.lilley@redpointglobal.com John Lilley
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: