I\'m trying to use a custom converter with spring-data-mongodb. I want to create it programmatically, but I get the following error:
org.springframework.core
Since org.springframework.data:spring-data-commons:1.13.3.RELEASE
, here's how to programmatically create a MongoTemplate
with custom converters
public MongoTemplate mongoTemplate(String mongoUri) throws Exception {
MongoDbFactory factory = new SimpleMongoDbFactory(new MongoClientURI(mongoUri));
CustomConversions conversions = new CustomConversions(
Arrays.asList(new FooWriteConverter(), new FooReadConverter()));
MongoMappingContext mappingContext = new MongoMappingContext();
DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mappingContext);
mongoConverter.setCustomConversions(conversions);
mongoConverter.afterPropertiesSet();
return new MongoTemplate(factory, mongoConverter);
}
The converters (implementation omitted)
class FooWriteConverter implements Converter<Foo, DBObject> { ... }
class FooReadConverter implements Converter<DBObject, Foo> { ... }
How to customize mongo with custom converters is decribed here in detail:
http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mapping-configuration
I injected the default configuration values so i can benefit from the application.properties configuration settings.
@Configuration
public class MongoConfiguration extends AbstractMongoConfiguration {
@Value("${spring.data.mongodb.database:test}")
String database;
@Value("${spring.data.mongodb.host:localhost}:${spring.data.mongodb.port:27017}")
String host;
@Override
protected String getDatabaseName() {
return database;
}
@Override
public Mongo mongo() throws Exception {
return new MongoClient(host);
}
@Bean
@Override
public CustomConversions customConversions() {
List<Converter<?, ?>> converterList = new ArrayList<Converter<?, ?>>();
converterList.add(new MongoColorWriter());
converterList.add(new MongoColorReader());
return new CustomConversions(converterList);
}
}
For me it was registering my converter as a reader instead of a writer. To fix that you need to add the @WritingConverter annotation to your converter class
@Component
@WritingConverter
public class NoteWriterConverter implements Converter<Note, DBObject> {
@Override
public DBObject convert(Note source) {
DBObject obj = new BasicDBObject();
obj.put("title", source.getTitle());
obj.put("reviewDate", source.getReviewDate());
obj.removeField("_class");
return obj;
}
}
This answer may be a little late for the OP, but I just ran into the same problem today and found a solution...
To set it up programmatically, you need to call MongoMappingConverter.afterPropertiesSet()
before you use it. I realized this from reading the code for MongoTemplate.getDefaultMongoConverter(MongoDbFactory)
.
Here's an example:
MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory, context);
converter.setTypeMapper(mapper);
converter.setCustomConversions(new CustomConversions(
Arrays.asList(
new TimeZoneReadConverter(),
new TimeZoneWriteConverter()
)
));
converter.afterPropertiesSet();
MongoTemplate template = new MongoTemplate(mongoDbFactory, converter);
Just a heads up. I was struggling with that problem on spring-data-mongodb 1.5.1.RELEASE
using Java Configuration. As some classes have changed, I'm posting my solution.
Add the following definition in your configuration class annotated with @Configuration
:
@Bean
public Mongo mongo() throws Exception {
MongoPropertiesResolver resolver = mongoResolver();
return new MongoClient(resolver.getUrl());
}
@Bean
public MongoDbFactory mongoDbFactory() throws Exception {
return new SimpleMongoDbFactory(mongo(), "database");
}
@Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory(), mongoConverter());
}
@Bean
public CustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<Converter<?, ?>>();
converters.add(new TimeZoneReadConverter());
converters.add(new TimeZoneReadConverter());
return new CustomConversions(converters);
}
@Bean
public MappingMongoConverter mongoConverter() throws Exception {
MongoMappingContext mappingContext = new MongoMappingContext();
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mappingContext);
mongoConverter.setCustomConversions(customConversions());
return mongoConverter;
}
With the introduction of the java.time package in java 8 I ran into a similar issue using the new LocalDate and LocalDateTime classes in the new package. This is how I solved it:
I wrote a converter for all 4 of these conversion options:
Here is an example
public class DateToLocalDateTimeConverter implements Converter<Date, LocalDateTime> {
@Override
public LocalDateTime convert(Date source) {
return source == null ? null : LocalDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
Then by including this in the xml configuration for the mongodb connection I was able to work in java 8 dates with mongodb (remember to add all the converters):
<mongo:mapping-converter>
<mongo:custom-converters>
<mongo:converter>
<bean class="package.DateToLocalDateTimeConverter" />
</mongo:converter>
</mongo:custom-converters>
</mongo:mapping-converter>