Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider null value settings for types with custom conversion. #4728

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.4.0-SNAPSHOT</version>
<version>4.4.x-GH-4710-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data MongoDB</name>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-benchmarks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.4.0-SNAPSHOT</version>
<version>4.4.x-GH-4710-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.4.0-SNAPSHOT</version>
<version>4.4.x-GH-4710-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.4.0-SNAPSHOT</version>
<version>4.4.x-GH-4710-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,21 @@ private static Document getOrCreateNestedDocument(String key, Bson source) {

return nested;
}

DocumentAccessor withCheckFieldMapping(boolean checkFieldMapping) {

if(!checkFieldMapping) {
return this;
}

return new DocumentAccessor(this.document) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to handle field write checks here, how about creating a named subclass that we would use across MappingMongoConverter in the write paths?

@Override
public void put(MongoPersistentProperty prop, @Nullable Object value) {
if(value != null || prop.writeNullValues()) {
super.put(prop, value);
}
}
};

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,11 @@ public <T> T getPropertyValue(MongoPersistentProperty property) {
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);
Expand Down Expand Up @@ -1284,7 +1289,8 @@ private void writeSimpleInternal(@Nullable Object value, Bson bson, String key)

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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
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;
Expand Down Expand Up @@ -2693,9 +2694,85 @@ void shouldWriteNullPropertyCorrectly() {
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() {

Expand Down Expand Up @@ -4102,13 +4179,19 @@ static class WithFieldWrite {
@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;

}

Expand Down
Loading