Add an option to @Field annotation to include/exclude null values on write.

Properties can be annotated with `@Field(write=…)` to control whether a property with a null value should be included or omitted (default) during conversion in the target Document.

Closes #3407
Original pull request: #3646.
This commit is contained in:
Divya Srivastava
2021-05-09 16:16:43 +05:30
committed by Mark Paluch
parent a481636429
commit b1020d19ba
6 changed files with 83 additions and 0 deletions

View File

@@ -744,6 +744,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
Object value = accessor.getProperty(prop);
if (value == null) {
if(!prop.isPropertyOmittableOnNull()) {
writeSimpleInternal(value, bson , prop);
}
continue;
}

View File

@@ -285,4 +285,18 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
public boolean isTextScoreProperty() {
return isAnnotationPresent(TextScore.class);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isPropertyOmittableOnNull()
*/
public boolean isPropertyOmittableOnNull() {
org.springframework.data.mongodb.core.mapping.Field annotation = findAnnotation(
org.springframework.data.mongodb.core.mapping.Field.class);
if ( annotation != null && annotation.write().equals(Field.Write.ALWAYS) ) {
return false;
}
return true;
}
}

View File

@@ -34,6 +34,21 @@ import org.springframework.core.annotation.AliasFor;
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
public @interface Field {
/**
* Enumeration of write strategies for a field with null value.It decides whether a field with null value has to be
* written to the resulting document to be saved to the database.
*/
enum Write{
/*
* The field will always be written to the database irrespective of null value.
*/
ALWAYS,
/*
* The field will only be written to the database if it has a non null value.
*/
NON_NULL
}
/**
* The key to be used to store the field inside the document. Alias for {@link #name()}.
*
@@ -65,4 +80,14 @@ public @interface Field {
* @since 2.2
*/
FieldType targetType() default FieldType.IMPLICIT;
/**
* If set to {@link Write#NON_NULL} {@literal null} values will be omitted.
* Setting the value to {@link Write#ALWAYS} explicitly adds an entry for the given field
* holding {@literal null} as a value {@code 'fieldName' : null }.
* <p />
* <strong>NOTE</strong> Setting the value to {@link Write#ALWAYS} may lead to increased document size.
* @return {@link Write#NON_NULL} by default.
*/
Write write() default Write.NON_NULL;
}

View File

@@ -104,6 +104,24 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
* @since 1.6
*/
boolean isTextScoreProperty();
/**
* Returns whether the property is to be written to the document if the value is null <br/>
* It's annotated with {@link Field.Write}.
*
* @return
* @since 1.6
*/
boolean isPropertyOmittableOnNull();
/**
* Returns whether the property is to be written to the document if the value is null <br/>
* It's annotated with {@link omitNull}.
*
* @return
* @since 1.6
*/
boolean isOmitNullProperty();
/**
* Returns the {@link DBRef} if the property is a reference.

View File

@@ -92,6 +92,11 @@ class UnwrappedMongoPersistentProperty implements MongoPersistentProperty {
public boolean isTextScoreProperty() {
return delegate.isTextScoreProperty();
}
@Override
public boolean isOmitNullProperty() {
return delegate.isOmitNullProperty();
}
@Override
@Nullable
@@ -315,4 +320,9 @@ class UnwrappedMongoPersistentProperty implements MongoPersistentProperty {
public <T> PersistentPropertyAccessor<T> getAccessorForOwner(T owner) {
return delegate.getAccessorForOwner(owner);
}
@Override
public boolean isPropertyOmittableOnNull() {
return delegate.isPropertyOmittableOnNull();
}
}

View File

@@ -146,6 +146,13 @@ public class BasicMongoPersistentPropertyUnitTests {
assertThat(property.isTextScoreProperty()).isTrue();
}
@Test // DATAMONGO-2551
public void shouldDetectOmittableOnNullPropertyCorrectly() {
MongoPersistentProperty property = getPropertyFor(DocumentWithOmittableOnNullProperty.class, "write");
assertThat(property.isPropertyOmittableOnNull()).isTrue();
}
@Test // DATAMONGO-976
public void shouldDetectTextScoreAsReadOnlyProperty() {
@@ -297,6 +304,12 @@ public class BasicMongoPersistentPropertyUnitTests {
@TextScore Float score;
}
static class DocumentWithOmittableOnNullProperty {
@org.springframework.data.mongodb.core.mapping.Field("write") org.springframework.data.mongodb.core.mapping.Field.Write write;
}
static class DocumentWithExplicitlyRenamedIdProperty {
@org.springframework.data.mongodb.core.mapping.Field("id") String id;