Andrei
Andrei

Reputation: 1447

How globally configure conversion of `MongoTemplate.getCollection().aggregate()`'s result to POJO?

I know two separate APIs in MongoTemplate, if you want to perform an .aggregate:

If I run a query and try to map (decode/deserialize/convert) its result to my POJO:

CodecRegistry pojoCodecRegistry = CodecRegistries.fromRegistries(
    MongoClientSettings.getDefaultCodecRegistry(), 
    CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build())
);
mongoTemplate
    .getCollection("myCollectionName")
    .withCodecRegistry(pojoCodecRegistry)
    .aggregate(myAggregation, MyPojo.class)
    .into(new ArrayList<>());

If I don't use the withCodecRegistry and I need to map result to my type (e.g. MyPojo.class) instead of Document.class, then I get an error saying codec for the class cannot be found or similar.
Example:

org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for CodecCacheKey{clazz=class com.example.MyPojo, types=null}.

I need to use MongoTemplate.getCollection().aggregate(), because it exposes a different set of APIs.
How can I make this work on the general case (so for any POJO I might supply) without specifying withCodecRegistry every time (so a global config somewhere)?

I'm using this together with SpringBoot.

Upvotes: 1

Views: 86

Answers (1)

Geba
Geba

Reputation: 1372

If you do not want to create pojoCodecRegistry and register it .withCodecRegistry(pojoCodecRegistry) each time you call MongoTemplate.getCollection().aggregate(),
then you can define the following bean:

@Configuration
public class MongoConfig {

    @Bean
    public MongoClientSettingsBuilderCustomizer mongoClientCustomizer() {
        var pojoCodecRegistry = CodecRegistries.fromRegistries(
            MongoClientSettings.getDefaultCodecRegistry(),
            CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build())
        );

        return builder -> builder.codecRegistry(pojoCodecRegistry);
    }
}

After this your code to call aggregate will look like this:

mongoTemplate
    .getCollection("myCollectionName")
    .aggregate(pipeline, MyPojo.class)
    .into(new ArrayList<>());

The solution is inspired by https://github.com/spring-projects/spring-boot/issues/20195

Upvotes: 1

Related Questions