15

We are trying to setup our own Converters for Spring Data Mongo and having problems with it.

Seems like Spring never calls for registerConvertersIn on CustomConversions and thus our custom converters added through overriden AbstractMongoConfiguration#customConversions never become part of conversion.

We are using Spring Data Mongo 1.6.3, but it seems it could be a problem for 1.8.0 too (I've checked calls to CustomConversions#registerConvertersIn and found none.)

I was able to fix this problem by calling CustomConversions#registerConvertersIn in custom MappingMongoConverter like this:

class MongoConfig extends AbstractMongoConfiguration {
    @Bean
    @Override
    public MappingMongoConverter mappingMongoConverter() throws Exception {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
        MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext()) {
            @Override
            public void setCustomConversions(CustomConversions conversions) {
                super.setCustomConversions(conversions);
                conversions.registerConvertersIn(conversionService);
            }

        };
        converter.setCustomConversions(customConversions());
        return converter;
    }
}

Is that a bug or we are doing something wrong?

Found another work around: https://stackoverflow.com/a/14369998/4567261

Community
  • 1
  • 1
Konstantin Fedorov
  • 153
  • 1
  • 1
  • 7
  • Seems like better way to call afterPropertiesSet on MappingMongoConverter. https://stackoverflow.com/questions/13780692/set-mongodb-converter-programatically Still unclear why it could not be done automatically by Spring Data Mongo itself. – Konstantin Fedorov Dec 10 '15 at 22:10

4 Answers4

26

In Spring Boot 2.x it's as simple as creating a registration bean that registers all of your converters:

@Configuration
public class Converters {

  @Bean
  public MongoCustomConversions mongoCustomConversions() {

    return new MongoCustomConversions(
        Arrays.asList(
            new MyClassToBytesConverter(),
            new BytesToMyClassConverter()));
  }
}

Then create your converter classes:

@WritingConverter
public class MyClassToBytesConverter implements Converter<MyClass, Binary> {

  @Override
  public Binary convert(MyClasssource) {
  // your code
  }
}
@ReadingConverter
public class BytesToMyClassConverter implements Converter<Binary, MyClass> {

  @Override
  public MyClass convert(Binary source) {
  /// your code
  }
}
Andy Brown
  • 11,766
  • 2
  • 42
  • 61
  • 2
    there are 5 different converter classes (bson, jackson-databing, spring-core etc..), Could you mention which one have you used in your your converter classes please? – user11908262 Mar 03 '23 at 06:56
12

Nothing worked for me but this.

While setting up mongoTemplate we need to tell to mongo db use the custom conversion:

@Bean
public MongoTemplate mongoTemplate() throws Exception {
    MongoTemplate mongoTemplate = new MongoTemplate(mongo(), mongoDatabase);
    MappingMongoConverter conv = (MappingMongoConverter) mongoTemplate.getConverter();
    // tell mongodb to use the custom converters
    conv.setCustomConversions(customConversions()); 
    conv.afterPropertiesSet();
    return mongoTemplate;
}

Follow this link for more details:

ℛɑƒæĿᴿᴹᴿ
  • 4,983
  • 4
  • 38
  • 58
tushar rohilla
  • 121
  • 1
  • 2
10

It took me one hour to figure out in the LATEST VERSION of spring data mongo, org.bson.Document should be used instead of com.mongodb.BasicDBObject. Here is an example:

@Component
@WritingConverter
public class UserModelConverter implements Converter<UserModel, Document> {

    @Override
    public Document convert(UserModel s) {
        Document obj = new Document();
        obj.put("firstName", "FirstName");
        obj.put("lastName", "LastName");

        obj.remove("_class");

        return obj;
    }
}
iamcrypticcoder
  • 2,609
  • 4
  • 27
  • 50
  • 5
    i spent more than an hour before finding your post. thanks for this. i don't understand why this isn't published more widely and why BasicDBObject is not backwards-compatible with a deprecated warning. Very poor upgrade experience. – ystan- Aug 05 '20 at 15:41
  • Agreed. Wasted so much time until I found this answer, every guide I found uses BasicDBObject. – caprica Sep 04 '21 at 15:44
  • I love you so much right now! Wasted a couple of hours of pointless trying before finding your solution. Annoyingly, the spring-data.mogodb docs actually use String, instead of Document!? :mindblown: – RekaB Feb 04 '23 at 00:27
3

Did you annotate your MongoConfig class with @Configuration ?

Your class MongoConfig need to be managed by the Spring BeanFactory to get callback afterPropertiesSet()( where conversions.registerConvertersIn(conversionService) is originally called ) automatically called

If you don't annotate you configuration bean you need to call afterPropertiesSet() yourself

Gut
  • 331
  • 1
  • 10