Skip to content

Serialization of Iterables and Maps is not using default codec #245

@hborchardt

Description

@hborchardt

Hi, thanks a lot for mongojack!

We recently upgraded mongojack from 4.2.1 to 4.8.2 and the following construct no longer works:

MongoCollection<Document> collection = mongoDB.getTemplateCollection(Document.class);
collection.aggregate(List.of(new Document("$match", List.of(Filters.and(Filters.eq("a", "b"), Filters.eq("b", "c"))))))
    .into(new ArrayList<>());

throws a

org.mongojack.MongoJsonMappingException: Error mapping BSON to POJOs
	at org.mongojack.internal.stream.JacksonEncoder.encode(JacksonEncoder.java:43)
	at org.mongojack.internal.stream.JacksonCodec.encode(JacksonCodec.java:61)
	at org.bson.codecs.EncoderContext.encodeWithChildContext(EncoderContext.java:91)
	at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:212)
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:170)
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:44)
	at org.bson.BsonDocumentWrapper.getUnwrapped(BsonDocumentWrapper.java:199)
	at org.bson.BsonDocumentWrapper.containsKey(BsonDocumentWrapper.java:124)
	at com.mongodb.client.internal.AggregateIterableImpl.getOutNamespace(AggregateIterableImpl.java:240)
...
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.mongodb.client.model.Filters$AndFilter and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ImmutableCollections$List12[0])
	at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
	at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1308)
	at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:414)
	at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:53)
	at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:30)
	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318)
	at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1572)
	at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1061)
	at org.mongojack.internal.stream.JacksonEncoder.encode(JacksonEncoder.java:41)
	... 84 more

After some investigation, the issue arises because previously, bson 4.3.x serialized Iterables and Maps directly, which was changed for bson 4.4.0 in this PR: mongodb/mongo-java-driver#811
Now, bson delegates serialization of Iterables and Maps to the codecRegistry, which for us is mongojack's JacksonCodecRegistry. But the JacksonCodecRegistry.java:isDefault(Class<T> clazz) function does not list Iterables and Maps as classes that the default registry should handle, so Jackson tries to serialize the List and therefore also the Filters$AndFilter, which results in the changed behavior.

A workaround for us is to override the isDefault function:

    pojoCodecRegistry = new JacksonCodecRegistry(mapper, MongoClientSettings.getDefaultCodecRegistry(), null,
        UuidRepresentation.STANDARD) {
      @Override
      protected <T> boolean isDefault(Class<T> clazz) {
        if (Iterable.class.isAssignableFrom(clazz) || 
            Map.class.isAssignableFrom(clazz)) {
          return true;
        }
        return super.isDefault(clazz);
      }
    };

but maybe you would like to include this in the standard isDefault function.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions