Browse Source

Consider null value settings for types with custom conversion.

This commit fixes an issue where settings regarding storage of null values had been ignored if a custom converter took care of the conversion.

Original pull request: #4728
Closes #4710
issue/4755
Christoph Strobl 2 years ago committed by Mark Paluch
parent
commit
8077b184b9
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 17
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DocumentAccessor.java
  2. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  3. 87
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java

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

@ -172,4 +172,21 @@ class DocumentAccessor { @@ -172,4 +172,21 @@ class DocumentAccessor {
return nested;
}
DocumentAccessor withCheckFieldMapping(boolean checkFieldMapping) {
if(!checkFieldMapping) {
return this;
}
return new DocumentAccessor(this.document) {
@Override
public void put(MongoPersistentProperty prop, @Nullable Object value) {
if(value != null || prop.writeNullValues()) {
super.put(prop, value);
}
}
};
}
}

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

@ -964,6 +964,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -964,6 +964,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
dbRefObj = proxy.toDBRef();
}
if(obj !=null && conversions.hasCustomWriteTarget(obj.getClass())) {
accessor.withCheckFieldMapping(true).put(prop, doConvert(obj, conversions.getCustomWriteTarget(obj.getClass()).get()));
return;
}
dbRefObj = dbRefObj != null ? dbRefObj : createDBRef(obj, prop);
accessor.put(prop, dbRefObj);
@ -1261,7 +1266,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -1261,7 +1266,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
private void writeSimpleInternal(@Nullable Object value, Bson bson, MongoPersistentProperty property,
PersistentPropertyAccessor<?> persistentPropertyAccessor) {
DocumentAccessor accessor = new DocumentAccessor(bson);
DocumentAccessor accessor = new DocumentAccessor(bson).withCheckFieldMapping(true);
if (conversions.hasValueConverter(property)) {
accessor.put(property, conversions.getPropertyValueConversions().getValueConverter(property).write(value,

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

@ -63,6 +63,7 @@ import org.springframework.data.annotation.Id; @@ -63,6 +63,7 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.annotation.Transient;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.convert.ConverterBuilder;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.convert.PropertyValueConverter;
import org.springframework.data.convert.PropertyValueConverterFactory;
@ -2693,9 +2694,85 @@ class MappingMongoConverterUnitTests { @@ -2693,9 +2694,85 @@ class MappingMongoConverterUnitTests {
converter.write(fieldWrite, document);
assertThat(document).containsEntry("writeAlways", null).doesNotContainKey("writeNonNull");
assertThat(document).containsEntry("writeAlwaysPersonDBRef", null).doesNotContainKey("writeNonNullPersonDBRef");
}
@Test // GH-4710
void shouldWriteSimplePropertyCorrectlyAfterConversionReturnsNull() {
MongoCustomConversions conversions = new MongoCustomConversions(ConverterBuilder.writing(Integer.class, String.class, it -> null).andReading(it -> null).getConverters().stream().toList());
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(conversions);
converter.afterPropertiesSet();
WithFieldWrite fieldWrite = new WithFieldWrite();
fieldWrite.writeAlways = 10;
fieldWrite.writeNonNull = 20;
org.bson.Document document = new org.bson.Document();
converter.write(fieldWrite, document);
assertThat(document).containsEntry("writeAlways", null).doesNotContainKey("writeNonNull");
}
@Test // GH-4710
void shouldWriteComplexPropertyCorrectlyAfterConversionReturnsNull() {
MongoCustomConversions conversions = new MongoCustomConversions(ConverterBuilder.writing(Person.class, String.class, it -> null).andReading(it -> null).getConverters().stream().toList());
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(conversions);
converter.afterPropertiesSet();
WithFieldWrite fieldWrite = new WithFieldWrite();
fieldWrite.writeAlwaysPerson = new Person();
fieldWrite.writeNonNullPerson = new Person();
org.bson.Document document = new org.bson.Document();
converter.write(fieldWrite, document);
assertThat(document).containsEntry("writeAlwaysPerson", null).doesNotContainKey("writeNonNullPerson");
}
@Test // GH-4710
void shouldDelegateWriteOfDBRefToCustomConversionIfConfigured() {
MongoCustomConversions conversions = new MongoCustomConversions(ConverterBuilder.writing(Person.class, DBRef.class, it -> new DBRef("persons", "n/a")).andReading(it -> null).getConverters().stream().toList());
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(conversions);
converter.afterPropertiesSet();
WithFieldWrite fieldWrite = new WithFieldWrite();
fieldWrite.writeAlwaysPersonDBRef = new Person();
fieldWrite.writeNonNullPersonDBRef = new Person();
org.bson.Document document = new org.bson.Document();
converter.write(fieldWrite, document);
assertThat(document).containsEntry("writeAlwaysPersonDBRef", new DBRef("persons", "n/a"));//.doesNotContainKey("writeNonNullPersonDBRef");
}
@Test // GH-4710
void shouldDelegateWriteOfDBRefToCustomConversionIfConfiguredAndCheckNulls() {
MongoCustomConversions conversions = new MongoCustomConversions(ConverterBuilder.writing(Person.class, DBRef.class, it -> null).andReading(it -> null).getConverters().stream().toList());
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(conversions);
converter.afterPropertiesSet();
WithFieldWrite fieldWrite = new WithFieldWrite();
fieldWrite.writeAlwaysPersonDBRef = new Person();
fieldWrite.writeNonNullPersonDBRef = new Person();
org.bson.Document document = new org.bson.Document();
converter.write(fieldWrite, document);
assertThat(document).containsEntry("writeAlwaysPersonDBRef", null).doesNotContainKey("writeNonNullPersonDBRef");
}
@Test // GH-3686
void readsCollectionContainingNullValue() {
@ -4102,13 +4179,19 @@ class MappingMongoConverterUnitTests { @@ -4102,13 +4179,19 @@ class MappingMongoConverterUnitTests {
@org.springframework.data.mongodb.core.mapping.Field(
write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Integer writeAlways;
@org.springframework.data.mongodb.core.mapping.Field(
write = org.springframework.data.mongodb.core.mapping.Field.Write.NON_NULL) Person writeNonNullPerson;
@org.springframework.data.mongodb.core.mapping.Field(
write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Person writeAlwaysPerson;
@org.springframework.data.mongodb.core.mapping.DBRef
@org.springframework.data.mongodb.core.mapping.Field(
write = org.springframework.data.mongodb.core.mapping.Field.Write.NON_NULL) Person writeNonNullPerson;
write = org.springframework.data.mongodb.core.mapping.Field.Write.NON_NULL) Person writeNonNullPersonDBRef;
@org.springframework.data.mongodb.core.mapping.DBRef
@org.springframework.data.mongodb.core.mapping.Field(
write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Person writeAlwaysPerson;
write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Person writeAlwaysPersonDBRef;
}

Loading…
Cancel
Save