Reputation: 2907
I'm using Spring Cloud Brixton.SR4
with Spring Data MongoDB.
I have a very simple entity:
@Document
public class Foo{
private Period period;
//getter & setter
}
Because java.time.Period
is not supported by jsr310
I'm creating custom converters:
class Converters {
@Component
@WritingConverter
static class PeriodToStringConverter implements Converter<Period, String> {
@Override
public String convert(Period period) {
return period.toString();
}
}
@ReadingConverter
@Component
static class StringToPeriodConverter implements Converter<String, Period> {
@Override
public Period convert(String s) {
return Period.parse(s);
}
}
Now I register them in my configuration class extending AbstractMongoConfiguration
:
@Bean
@Override
public MappingMongoConverter mappingMongoConverter() throws Exception {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
final CustomConversions conversions = customConversions();
log.info("hasCustomWriteTarget(Period.class): " + conversions.hasCustomWriteTarget(Period.class));
log.info("hasCustomWriteTarget(Period.class, String.class): " + conversions.hasCustomWriteTarget(Period.class, String.class));
log.info("hasCustomReadTarget(String.class, Period.class): " + conversions.hasCustomReadTarget(String.class, Period.class));
converter.setCustomConversions(conversions);
converter.afterPropertiesSet(); //probably not needed, trying out of despair
return converter;
}
@Bean
@Override
public CustomConversions customConversions() {
List<Converter> converters = new ArrayList<>();
converters.add(new Converters.PeriodToStringConverter());
converters.add(new Converters.StringToPeriodConverter());
return new CustomConversions(converters);
}
When I start my app I see in the logs:
hasCustomWriteTarget(Period.class): true
hasCustomWriteTarget(Period.class, String.class): true
hasCustomReadTarget(String.class, Period.class): true
Now I create a new Foo
and save it to my repository:
Foo foo = new Foo();
foo.setPeriod(Period.of(2, 0, 1));
fooRepository.save(foo);
Now the weirdness happens:
In Mongodb I see:
{
"_id": ObjectId("xxxx"),
"period": {
"years" : 0,
"months" : 2,
"days" : 1
}
}
So already that's something wrong. It should be saved as a String
When I try to read the object in Java I get:
org.springframework.data.mapping.model.MappingException: No property null found on entity class java.time.Period to bind constructor parameter to!
I debugged the code in MappingMongoConverter
:
if (conversions.hasCustomReadTarget(dbo.getClass(), rawType)) {
return conversionService.convert(dbo, rawType);
}
because my object was not store as a String the dbo
variable is actually a BasicDbObject
and therefore I don't have converter for this.
Any idea why my write converter is not being used to persist the Period
?
I have jackson-datatype-jdk8
on my classpath, could it be the issue? Would jackson be involved at all for persisting in Mongodb?
EDIT
It seems to be a registration issue. When I debug the code, the CustomConversion
object used in MappingMongoConverter
is different than the one I create. And it doesn't have the custom converters which I create
Upvotes: 1
Views: 2587
Reputation: 2907
OK it was extremely stupid...
I was also creating my own MongoTemplate
:
@Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
Which basically ignores my custom converter. To fix it:
@Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory(), mappingMongoConverter());
}
Upvotes: 1