Skip to content

Commit a1a0675

Browse files
christophstroblmp911de
authored andcommitted
Fix CustomConverter conversion lookup.
This commit makes sure to fall back to the configured custom converter if no more type specific converter has been registered. Closes #3580 Original pull request: #3581.
1 parent a88748d commit a1a0675

File tree

2 files changed

+83
-3
lines changed

2 files changed

+83
-3
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ protected <S extends Object> S readDocument(ConversionContext context, Bson bson
292292
Class<? extends S> rawType = typeToRead.getType();
293293

294294
if (conversions.hasCustomReadTarget(bson.getClass(), rawType)) {
295-
return doConvert(bson, rawType);
295+
return doConvert(bson, rawType, typeHint.getType());
296296
}
297297

298298
if (Document.class.isAssignableFrom(rawType)) {
@@ -1532,9 +1532,17 @@ public MappingMongoConverter with(MongoDatabaseFactory dbFactory) {
15321532
return target;
15331533
}
15341534

1535+
private <T extends Object> T doConvert(Object value, Class<? extends T> target) {
1536+
return doConvert(value, target, null);
1537+
}
1538+
15351539
@SuppressWarnings("ConstantConditions")
1536-
private <T> T doConvert(Object value, Class<T> target) {
1537-
return conversionService.convert(value, target);
1540+
private <T extends Object> T doConvert(Object value, Class<? extends T> target, @Nullable Class<? extends T> fallback) {
1541+
1542+
if(conversionService.canConvert(value.getClass(), target) || fallback == null) {
1543+
return conversionService.convert(value, target);
1544+
}
1545+
return conversionService.convert(value, fallback);
15381546
}
15391547

15401548
/**

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,6 +2383,51 @@ void writeEmbeddedTypeWithComplexValue() {
23832383
.doesNotContainKey("address.city");
23842384
}
23852385

2386+
@Test // GH-3580
2387+
void shouldFallbackToConfiguredCustomConversionTargetOnRead() {
2388+
2389+
GenericTypeConverter genericTypeConverter = spy(new GenericTypeConverter());
2390+
2391+
converter = new MappingMongoConverter(resolver, mappingContext);
2392+
converter.setCustomConversions(MongoCustomConversions.create(it -> {
2393+
it.registerConverter(genericTypeConverter);
2394+
}));
2395+
converter.afterPropertiesSet();
2396+
2397+
org.bson.Document source = new org.bson.Document("_class", SubTypeOfGenericType.class.getName()).append("value",
2398+
"v1");
2399+
GenericType target = converter.read(GenericType.class, source);
2400+
2401+
assertThat(target).isInstanceOf(GenericType.class);
2402+
assertThat(target.content).isEqualTo("v1");
2403+
2404+
verify(genericTypeConverter).convert(eq(source));
2405+
}
2406+
2407+
@Test // GH-3580
2408+
void shouldUseMostConcreteCustomConversionTargetOnRead() {
2409+
2410+
GenericTypeConverter genericTypeConverter = spy(new GenericTypeConverter());
2411+
SubTypeOfGenericTypeConverter subTypeOfGenericTypeConverter = spy(new SubTypeOfGenericTypeConverter());
2412+
2413+
converter = new MappingMongoConverter(resolver, mappingContext);
2414+
converter.setCustomConversions(MongoCustomConversions.create(it -> {
2415+
it.registerConverter(genericTypeConverter);
2416+
it.registerConverter(subTypeOfGenericTypeConverter);
2417+
}));
2418+
converter.afterPropertiesSet();
2419+
2420+
org.bson.Document source = new org.bson.Document("_class", SubTypeOfGenericType.class.getName()).append("value",
2421+
"v1");
2422+
GenericType target = converter.read(GenericType.class, source);
2423+
2424+
assertThat(target).isInstanceOf(SubTypeOfGenericType.class);
2425+
assertThat(target.content).isEqualTo("v1_s");
2426+
2427+
verify(genericTypeConverter, never()).convert(any());
2428+
verify(subTypeOfGenericTypeConverter).convert(eq(source));
2429+
}
2430+
23862431
static class GenericType<T> {
23872432
T content;
23882433
}
@@ -2899,4 +2944,31 @@ public Person onAfterConvert(Person entity, org.bson.Document document, String c
28992944
}
29002945
}
29012946

2947+
static class SubTypeOfGenericType extends GenericType<String> {
2948+
2949+
}
2950+
2951+
@ReadingConverter
2952+
static class GenericTypeConverter implements Converter<org.bson.Document, GenericType<?>> {
2953+
2954+
@Override
2955+
public GenericType<?> convert(org.bson.Document source) {
2956+
2957+
GenericType<Object> target = new GenericType<>();
2958+
target.content = source.get("value");
2959+
return target;
2960+
}
2961+
}
2962+
2963+
@ReadingConverter
2964+
static class SubTypeOfGenericTypeConverter implements Converter<org.bson.Document, SubTypeOfGenericType> {
2965+
2966+
@Override
2967+
public SubTypeOfGenericType convert(org.bson.Document source) {
2968+
2969+
SubTypeOfGenericType target = new SubTypeOfGenericType();
2970+
target.content = source.getString("value") + "_s";
2971+
return target;
2972+
}
2973+
}
29022974
}

0 commit comments

Comments
 (0)