Browse Source

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.
pull/860/head
Divya Srivastava 5 years ago committed by Mark Paluch
parent
commit
b1020d19ba
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 3
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  2. 14
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java
  3. 25
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Field.java
  4. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java
  5. 10
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/UnwrappedMongoPersistentProperty.java
  6. 13
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java

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

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

14
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java

@ -285,4 +285,18 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
public boolean isTextScoreProperty() { public boolean isTextScoreProperty() {
return isAnnotationPresent(TextScore.class); 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;
}
} }

25
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Field.java

@ -34,6 +34,21 @@ import org.springframework.core.annotation.AliasFor;
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
public @interface Field { 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()}. * 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 * @since 2.2
*/ */
FieldType targetType() default FieldType.IMPLICIT; 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;
} }

18
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java

@ -105,6 +105,24 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
*/ */
boolean isTextScoreProperty(); 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. * Returns the {@link DBRef} if the property is a reference.
* *

10
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/UnwrappedMongoPersistentProperty.java

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

13
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java

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

Loading…
Cancel
Save