spring-data-mongodb
spring-data-mongodb copied to clipboard
MappingMongoConverter does not work while convert a field which declared with Map<String ,Object >
In java , version 11..17.RELEASE :
A JSONObject would be recognised as a Map<String,Object> .
It happen to that JSONObject have a BigDecimal field, so i register a couple of converts :
- BigDecimalToDecimal128Converter for WritingConverter
- Decimal128ToBigDecimalConverter for ReadingConverter
however , BigDecimalToDecimal128Converter for WritingConverter works, but Decimal128ToBigDecimalConverter for ReadingConverter does not work .
it is cased by
org.springframework.data.mongodb.core.convert.MappingMongoConverter.getPotentiallyConvertedSimpleRead:
if (value == null || target == null || target.isAssignableFrom(value.getClass())) {
return value;
}
and I also found that i cannot use a customer MappingMongoConverter, because argument ObjectPath in method readMap cannot not be accessed from outside package:
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mappingContext) {
@Override
protected Map<Object, Object> readMap(TypeInformation<?> type, DBObject dbObject, ObjectPath path) {
return null;
}
};
That's a flaw we need to investigate since the Map value type is object and custom converter is registered no type info is written, so on read we cannot determine the desired target type. Maybe there's a way to tell from the type used by the driver itself. We need to investigate options here. If you have a solution in mind (and the time to code it) please feel free to open a PR.
Hi @christophstrobl , I tried to reproduce this with a UnitTest, can you validate this is the correct issue?
@Test
void shouldConvertBigDecimalToDecimal128AndBack() {
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(MongoCustomConversions.create(it ->
it.registerConverters(Arrays.asList(new BigDecimalToDecimal128Converter(), new Decimal128ToBigDecimalConverter()))));
converter.afterPropertiesSet();
BigDecimal originalValue = BigDecimal.valueOf(10712389.1234d);
GenericType<Object> source = new GenericType<>();
source.content = originalValue;
org.bson.Document writeDocument = new org.bson.Document();
converter.write(source, writeDocument);
Decimal128 decimal128Value = new Decimal128(originalValue);
assertThat(decimal128Value).isEqualTo(writeDocument.get("content"));
GenericType<Object> observedValue = converter.read(GenericType.class, writeDocument);
assertThat(observedValue.content).isEqualTo(originalValue); // ---> This Assertion Failed
assertThat(observedValue.content).isInstanceOf(BigDecimal.class);
}
Failed Message:
// assertThat(observedValue.content).isEqualTo(originalValue);
org.opentest4j.AssertionFailedError:
expected: "10712389.1234 (BigDecimal@4893b344)"
but was: "10712389.1234 (Decimal128@53a665ad)"
Expected :10712389.1234
Actual :10712389.1234
Converters:
@WritingConverter
private static class BigDecimalToDecimal128Converter implements Converter<BigDecimal, Decimal128> {
@Override
public Decimal128 convert(BigDecimal bigDecimal) {
return new Decimal128(bigDecimal);
}
}
@ReadingConverter
private static class Decimal128ToBigDecimalConverter implements Converter<Decimal128, BigDecimal> {
@Override
public BigDecimal convert(Decimal128 decimal128) {
return decimal128.bigDecimalValue();
}
}
@christophstrobl @mp911de is this still relevent? if so, can you please validate my understanding above?
@christophstrobl Hello, can you please let me know if my understanding of the issue is correct and if it's still relevant to work on it?
Thanks for providing the test and sorry for long silence. We've been revisiting the issue and the mapping behaves as expected within its boundaries for resolving generic signatures. Since we do not have any data point for resolving the generic type of content
in the given example we cannot determine which value to map it to. The writing Converter
in turn must not know about the context it is called in.
There's actually a couple of ways how to address the issue ranging from a more strongly typed model over, a custom Converter
that would add type information, to a property specific ValueConverter
.
这是来自QQ邮箱的自动回复邮件。 您好,我尽快给您回复。