Polishing.

Reorder methods and types. Rename MongoPersistentProperty.isOmitNullProperty to writeNullValues. Adapt caching MongoPersistentProperty and add tests.

Tweak Javadoc wording, add author and since tags.

See #3407
Original pull request: #3646.
This commit is contained in:
Mark Paluch
2021-06-14 09:30:08 +02:00
parent b1020d19ba
commit c217618d9d
11 changed files with 242 additions and 102 deletions

View File

@@ -103,6 +103,7 @@ import com.mongodb.DBRef;
* @author Mark Paluch
* @author Roman Puchkovskiy
* @author Heesu Jung
* @author Divya Srivastava
*/
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
@@ -737,6 +738,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
continue;
}
if (prop.isAssociation()) {
writeAssociation(prop.getRequiredAssociation(), accessor, dbObjectAccessor);
continue;
}
@@ -744,13 +746,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
Object value = accessor.getProperty(prop);
if (value == null) {
if(!prop.isPropertyOmittableOnNull()) {
writeSimpleInternal(value, bson , prop);
if (prop.writeNullValues()) {
dbObjectAccessor.put(prop, null);
}
continue;
}
if (!conversions.isSimpleType(value.getClass())) {
} else if (!conversions.isSimpleType(value.getClass())) {
writePropertyInternal(value, dbObjectAccessor, prop);
} else {
writeSimpleInternal(value, bson, prop);
@@ -763,7 +762,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
MongoPersistentProperty inverseProp = association.getInverse();
writePropertyInternal(accessor.getProperty(inverseProp), dbObjectAccessor, inverseProp);
Object value = accessor.getProperty(inverseProp);
if (value == null && !inverseProp.isUnwrapped() && inverseProp.writeNullValues()) {
dbObjectAccessor.put(inverseProp, null);
return;
}
writePropertyInternal(value, dbObjectAccessor, inverseProp);
}
@SuppressWarnings({ "unchecked" })

View File

@@ -41,6 +41,7 @@ import org.springframework.util.StringUtils;
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
* @author Divya Srivastava
*/
public class BasicMongoPersistentProperty extends AnnotationBasedPersistentProperty<MongoPersistentProperty>
implements MongoPersistentProperty {
@@ -214,6 +215,19 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
return annotation != null ? annotation.order() : Integer.MAX_VALUE;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#skipNullValues()
*/
@Override
public boolean writeNullValues() {
org.springframework.data.mongodb.core.mapping.Field annotation = findAnnotation(
org.springframework.data.mongodb.core.mapping.Field.class);
return annotation != null && annotation.write() == Field.Write.ALWAYS;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#createAssociation()
@@ -286,17 +300,4 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
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

@@ -33,6 +33,7 @@ public class CachingMongoPersistentProperty extends BasicMongoPersistentProperty
private boolean dbRefResolved;
private @Nullable DBRef dbref;
private @Nullable String fieldName;
private @Nullable Boolean writeNullValues;
private @Nullable Class<?> fieldType;
private @Nullable Boolean usePropertyAccess;
private @Nullable Boolean isTransient;
@@ -90,6 +91,20 @@ public class CachingMongoPersistentProperty extends BasicMongoPersistentProperty
return this.fieldName;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.BasicMongoPersistentProperty#skipNullValues()
*/
@Override
public boolean writeNullValues() {
if (this.writeNullValues == null) {
this.writeNullValues = super.writeNullValues();
}
return this.writeNullValues;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.BasicMongoPersistentProperty#getFieldType()

View File

@@ -28,27 +28,13 @@ import org.springframework.core.annotation.AliasFor;
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Divya Srivastava
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@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()}.
*
@@ -82,12 +68,32 @@ public @interface Field {
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 }.
* Write rules when to include a property value upon conversion. If set to {@link Write#NON_NULL} (default)
* {@literal null} values are not written to the target {@code Document}. 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.
* <strong>NOTE</strong>Setting the value to {@link Write#ALWAYS} may lead to increased document size.
*
* @return {@link Write#NON_NULL} by default.
* @since 3.3
*/
Write write() default Write.NON_NULL;
/**
* Enumeration of write strategies to define when a property is included for write conversion.
*
* @since 3.3
*/
enum Write {
/**
* Value that indicates that property is to be always included, independent of value of the property.
*/
ALWAYS,
/**
* Value that indicates that only properties with non-{@literal null} values are to be included.
*/
NON_NULL
}
}

View File

@@ -28,6 +28,7 @@ import org.springframework.lang.Nullable;
* @author Patryk Wasik
* @author Thomas Darimont
* @author Christoph Strobl
* @author Divya Srivastava
*/
public interface MongoPersistentProperty extends PersistentProperty<MongoPersistentProperty> {
@@ -54,6 +55,15 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
*/
int getFieldOrder();
/**
* Returns whether the property should be written to the database if its value is {@literal null}.
*
* @return
* @since 3.3
* @see Field.Write
*/
boolean writeNullValues();
/**
* Returns whether the property is a {@link com.mongodb.DBRef}. If this returns {@literal true} you can expect
* {@link #getDBRef()} to return an non-{@literal null} value.
@@ -104,24 +114,6 @@ 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

@@ -63,6 +63,11 @@ class UnwrappedMongoPersistentProperty implements MongoPersistentProperty {
return delegate.getFieldOrder();
}
@Override
public boolean writeNullValues() {
return delegate.writeNullValues();
}
@Override
public boolean isDbReference() {
return delegate.isDbReference();
@@ -92,11 +97,6 @@ class UnwrappedMongoPersistentProperty implements MongoPersistentProperty {
public boolean isTextScoreProperty() {
return delegate.isTextScoreProperty();
}
@Override
public boolean isOmitNullProperty() {
return delegate.isOmitNullProperty();
}
@Override
@Nullable
@@ -321,8 +321,4 @@ class UnwrappedMongoPersistentProperty implements MongoPersistentProperty {
return delegate.getAccessorForOwner(owner);
}
@Override
public boolean isPropertyOmittableOnNull() {
return delegate.isPropertyOmittableOnNull();
}
}

View File

@@ -24,6 +24,7 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.With;
@@ -1692,7 +1693,7 @@ public class MongoTemplateTests {
assertThat(template.count(query, collectionName)).isEqualTo(1L);
}
@Test // DATAMONGO-571
@Test // DATAMONGO-571, GH-3407
public void nullsPropertiesForVersionObjectUpdates() {
VersionedPerson person = new VersionedPerson();
@@ -1702,11 +1703,17 @@ public class MongoTemplateTests {
template.save(person);
assertThat(person.id).isNotNull();
person.firstname = null;
person.lastname = null;
template.save(person);
person = template.findOne(query(where("id").is(person.id)), VersionedPerson.class);
assertThat(person.firstname).isNull();
assertThat(person.lastname).isNull();
org.bson.Document document = template.findOne(query(where("_id").is(person.id)), org.bson.Document.class,
"versionedPerson");
assertThat(document).doesNotContainKey("firstname").containsEntry("lastname", null);
}
@Test // DATAMONGO-571
@@ -3703,6 +3710,64 @@ public class MongoTemplateTests {
assertThat(template.find(new BasicQuery("{}").with(Sort.by("id")), WithIdAndFieldAnnotation.class)).isNotEmpty();
}
@Test // GH-3407
void shouldWriteSubdocumentWithNullCorrectly() {
template.dropCollection(WithSubdocument.class);
WithSubdocument doc = new WithSubdocument();
SubdocumentWithWriteNull subdoc = new SubdocumentWithWriteNull("Walter", "White");
doc.subdocument = subdoc;
template.save(doc);
org.bson.Document loaded = template.findById(doc.id, org.bson.Document.class, "withSubdocument");
assertThat(loaded.get("subdocument", org.bson.Document.class)).hasSize(3).containsEntry("firstname", "Walter")
.containsEntry("nickname", null);
}
@Test // GH-3407
void shouldUpdateSubdocumentWithNullCorrectly() {
template.dropCollection(WithSubdocument.class);
WithSubdocument doc = new WithSubdocument();
SubdocumentWithWriteNull subdoc = new SubdocumentWithWriteNull("Walter", "White");
subdoc.nickname = "Heisenberg";
doc.subdocument = subdoc;
template.save(doc);
String id = doc.id;
doc.id = null;
subdoc.nickname = null;
template.update(WithSubdocument.class).replaceWith(doc).findAndReplaceValue();
org.bson.Document loaded = template.findById(id, org.bson.Document.class, "withSubdocument");
assertThat(loaded.get("subdocument", org.bson.Document.class)).hasSize(3).containsEntry("firstname", "Walter")
.containsEntry("nickname", null);
}
@Test // GH-3407
void shouldFindSubdocumentWithNullCorrectly() {
template.dropCollection(WithSubdocument.class);
WithSubdocument doc = new WithSubdocument();
SubdocumentWithWriteNull subdoc = new SubdocumentWithWriteNull("Walter", "White");
doc.subdocument = subdoc;
template.save(doc);
org.bson.Document loaded = template.findOne(query(where("subdocument").is(subdoc)), org.bson.Document.class,
"withSubdocument");
assertThat(loaded).isNotNull();
}
private AtomicReference<ImmutableVersioned> createAfterSaveReference() {
AtomicReference<ImmutableVersioned> saved = new AtomicReference<>();
@@ -4020,7 +4085,8 @@ public class MongoTemplateTests {
static class VersionedPerson {
@Version Long version;
String id, firstname, lastname;
String id, firstname;
@Field(write = Field.Write.ALWAYS) String lastname;
}
static class TypeWithFieldAnnotation {
@@ -4247,4 +4313,22 @@ public class MongoTemplateTests {
String value;
}
@Data
static class WithSubdocument {
@Id //
@Field(name = "_id") //
String id;
SubdocumentWithWriteNull subdocument;
}
@Data
@RequiredArgsConstructor
static class SubdocumentWithWriteNull {
final String firstname, lastname;
@Field(write = Field.Write.ALWAYS) String nickname;
}
}

View File

@@ -1139,7 +1139,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
.containsEntry("$geoNear.near.coordinates.[1]", 2D);
}
@Test // DATAMONGO-2155
@Test // DATAMONGO-2155, GH-3407
void saveVersionedEntityShouldCallUpdateCorrectly() {
when(updateResult.getModifiedCount()).thenReturn(1L);
@@ -1157,7 +1157,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
assertThat(queryCaptor.getValue()).isEqualTo(new Document("_id", 1).append("version", 10));
assertThat(updateCaptor.getValue())
.isEqualTo(new Document("version", 11).append("_class", VersionedEntity.class.getName()));
.isEqualTo(new Document("version", 11).append("_class", VersionedEntity.class.getName()).append("name", null));
}
@Test // DATAMONGO-1783
@@ -2273,6 +2273,8 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
@Id Integer id;
@Version Integer version;
@Field(write = Field.Write.ALWAYS) String name;
}
enum MyConverter implements Converter<AutogenerateableId, String> {

View File

@@ -2520,6 +2520,18 @@ class MappingMongoConverterUnitTests {
assertThat(target.typeImplementingMap).isEqualTo(new TypeImplementingMap("one", 2));
}
@Test // GH-3407
void shouldWriteNullPropertyCorrectly() {
WithFieldWrite fieldWrite = new WithFieldWrite();
org.bson.Document document = new org.bson.Document();
converter.write(fieldWrite, document);
assertThat(document).containsEntry("writeAlways", null).doesNotContainKey("writeNonNull");
assertThat(document).containsEntry("writeAlwaysPerson", null).doesNotContainKey("writeNonNullPerson");
}
static class GenericType<T> {
T content;
}
@@ -3165,4 +3177,20 @@ class MappingMongoConverterUnitTests {
return null;
}
}
static class WithFieldWrite {
@org.springframework.data.mongodb.core.mapping.Field(
write = org.springframework.data.mongodb.core.mapping.Field.Write.NON_NULL) Integer writeNonNull;
@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.DBRef @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.DBRef @org.springframework.data.mongodb.core.mapping.Field(
write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Person writeAlwaysPerson;
}
}

View File

@@ -48,25 +48,26 @@ import org.springframework.util.ReflectionUtils;
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @author Divya Srivastava
*/
public class BasicMongoPersistentPropertyUnitTests {
MongoPersistentEntity<Person> entity;
private MongoPersistentEntity<Person> entity;
@BeforeEach
public void setup() {
void setup() {
entity = new BasicMongoPersistentEntity<>(ClassTypeInformation.from(Person.class));
}
@Test
public void usesAnnotatedFieldName() {
void usesAnnotatedFieldName() {
Field field = ReflectionUtils.findField(Person.class, "firstname");
assertThat(getPropertyFor(field).getFieldName()).isEqualTo("foo");
}
@Test
public void returns_IdForIdProperty() {
void returns_IdForIdProperty() {
Field field = ReflectionUtils.findField(Person.class, "id");
MongoPersistentProperty property = getPropertyFor(field);
assertThat(property.isIdProperty()).isTrue();
@@ -74,19 +75,19 @@ public class BasicMongoPersistentPropertyUnitTests {
}
@Test
public void returnsPropertyNameForUnannotatedProperties() {
void returnsPropertyNameForUnannotatedProperties() {
Field field = ReflectionUtils.findField(Person.class, "lastname");
assertThat(getPropertyFor(field).getFieldName()).isEqualTo("lastname");
}
@Test
public void preventsNegativeOrder() {
void preventsNegativeOrder() {
getPropertyFor(ReflectionUtils.findField(Person.class, "ssn"));
}
@Test // DATAMONGO-553
public void usesPropertyAccessForThrowableCause() {
void usesPropertyAccessForThrowableCause() {
BasicMongoPersistentEntity<Throwable> entity = new BasicMongoPersistentEntity<>(
ClassTypeInformation.from(Throwable.class));
@@ -96,7 +97,7 @@ public class BasicMongoPersistentPropertyUnitTests {
}
@Test // DATAMONGO-607
public void usesCustomFieldNamingStrategyByDefault() throws Exception {
void usesCustomFieldNamingStrategyByDefault() throws Exception {
ClassTypeInformation<Person> type = ClassTypeInformation.from(Person.class);
Field field = ReflectionUtils.findField(Person.class, "lastname");
@@ -113,7 +114,7 @@ public class BasicMongoPersistentPropertyUnitTests {
}
@Test // DATAMONGO-607
public void rejectsInvalidValueReturnedByFieldNamingStrategy() {
void rejectsInvalidValueReturnedByFieldNamingStrategy() {
ClassTypeInformation<Person> type = ClassTypeInformation.from(Person.class);
Field field = ReflectionUtils.findField(Person.class, "lastname");
@@ -126,49 +127,42 @@ public class BasicMongoPersistentPropertyUnitTests {
}
@Test // DATAMONGO-937
public void shouldDetectAnnotatedLanguagePropertyCorrectly() {
void shouldDetectAnnotatedLanguagePropertyCorrectly() {
MongoPersistentProperty property = getPropertyFor(DocumentWithLanguageProperty.class, "lang");
assertThat(property.isLanguageProperty()).isTrue();
}
@Test // DATAMONGO-937
public void shouldDetectImplicitLanguagePropertyCorrectly() {
void shouldDetectImplicitLanguagePropertyCorrectly() {
MongoPersistentProperty property = getPropertyFor(DocumentWithImplicitLanguageProperty.class, "language");
assertThat(property.isLanguageProperty()).isTrue();
}
@Test // DATAMONGO-976
public void shouldDetectTextScorePropertyCorrectly() {
void shouldDetectTextScorePropertyCorrectly() {
MongoPersistentProperty property = getPropertyFor(DocumentWithTextScoreProperty.class, "score");
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() {
void shouldDetectTextScoreAsReadOnlyProperty() {
MongoPersistentProperty property = getPropertyFor(DocumentWithTextScoreProperty.class, "score");
assertThat(property.isWritable()).isFalse();
}
@Test // DATAMONGO-1050
public void shouldNotConsiderExplicitlyNameFieldAsIdProperty() {
void shouldNotConsiderExplicitlyNameFieldAsIdProperty() {
MongoPersistentProperty property = getPropertyFor(DocumentWithExplicitlyRenamedIdProperty.class, "id");
assertThat(property.isIdProperty()).isFalse();
}
@Test // DATAMONGO-1050
public void shouldConsiderPropertyAsIdWhenExplicitlyAnnotatedWithIdEvenWhenExplicitlyNamePresent() {
void shouldConsiderPropertyAsIdWhenExplicitlyAnnotatedWithIdEvenWhenExplicitlyNamePresent() {
MongoPersistentProperty property = getPropertyFor(DocumentWithExplicitlyRenamedIdPropertyHavingIdAnnotation.class,
"id");
@@ -176,7 +170,7 @@ public class BasicMongoPersistentPropertyUnitTests {
}
@Test // DATAMONGO-1373
public void shouldConsiderComposedAnnotationsForIdField() {
void shouldConsiderComposedAnnotationsForIdField() {
MongoPersistentProperty property = getPropertyFor(DocumentWithComposedAnnotations.class, "myId");
assertThat(property.isIdProperty()).isTrue();
@@ -184,14 +178,14 @@ public class BasicMongoPersistentPropertyUnitTests {
}
@Test // DATAMONGO-1373
public void shouldConsiderComposedAnnotationsForFields() {
void shouldConsiderComposedAnnotationsForFields() {
MongoPersistentProperty property = getPropertyFor(DocumentWithComposedAnnotations.class, "myField");
assertThat(property.getFieldName()).isEqualTo("myField");
}
@Test // DATAMONGO-1737
public void honorsFieldOrderWhenIteratingOverProperties() {
void honorsFieldOrderWhenIteratingOverProperties() {
MongoMappingContext context = new MongoMappingContext();
MongoPersistentEntity<?> entity = context.getPersistentEntity(Sample.class);
@@ -203,36 +197,45 @@ public class BasicMongoPersistentPropertyUnitTests {
assertThat(properties).containsExactly("first", "second", "third");
}
@Test // GH-3407
void shouldDetectWritability() {
assertThat(getPropertyFor(WithFieldWrite.class, "fieldWithDefaults").writeNullValues()).isFalse();
assertThat(getPropertyFor(WithFieldWrite.class, "fieldWithField").writeNullValues()).isFalse();
assertThat(getPropertyFor(WithFieldWrite.class, "writeNonNull").writeNullValues()).isFalse();
assertThat(getPropertyFor(WithFieldWrite.class, "writeAlways").writeNullValues()).isTrue();
}
@Test // DATAMONGO-1798
public void fieldTypeShouldReturnActualTypeForNonIdProperties() {
void fieldTypeShouldReturnActualTypeForNonIdProperties() {
MongoPersistentProperty property = getPropertyFor(Person.class, "lastname");
assertThat(property.getFieldType()).isEqualTo(String.class);
}
@Test // DATAMONGO-1798
public void fieldTypeShouldBeObjectIdForPropertiesAnnotatedWithCommonsId() {
void fieldTypeShouldBeObjectIdForPropertiesAnnotatedWithCommonsId() {
MongoPersistentProperty property = getPropertyFor(Person.class, "id");
assertThat(property.getFieldType()).isEqualTo(ObjectId.class);
}
@Test // DATAMONGO-1798
public void fieldTypeShouldBeImplicitForPropertiesAnnotatedWithMongoId() {
void fieldTypeShouldBeImplicitForPropertiesAnnotatedWithMongoId() {
MongoPersistentProperty property = getPropertyFor(WithStringMongoId.class, "id");
assertThat(property.getFieldType()).isEqualTo(String.class);
}
@Test // DATAMONGO-1798
public void fieldTypeShouldBeObjectIdForPropertiesAnnotatedWithMongoIdAndTargetTypeObjectId() {
void fieldTypeShouldBeObjectIdForPropertiesAnnotatedWithMongoIdAndTargetTypeObjectId() {
MongoPersistentProperty property = getPropertyFor(WithStringMongoIdMappedToObjectId.class, "id");
assertThat(property.getFieldType()).isEqualTo(ObjectId.class);
}
@Test // DATAMONGO-2460
public void fieldTypeShouldBeDocumentForPropertiesAnnotatedIdWhenAComplexTypeAndFieldTypeImplicit() {
void fieldTypeShouldBeDocumentForPropertiesAnnotatedIdWhenAComplexTypeAndFieldTypeImplicit() {
MongoPersistentProperty property = getPropertyFor(WithComplexId.class, "id");
assertThat(property.getFieldType()).isEqualTo(Document.class);
@@ -304,9 +307,15 @@ public class BasicMongoPersistentPropertyUnitTests {
@TextScore Float score;
}
static class DocumentWithOmittableOnNullProperty {
static class WithFieldWrite {
@org.springframework.data.mongodb.core.mapping.Field("write") org.springframework.data.mongodb.core.mapping.Field.Write write;
int fieldWithDefaults;
@org.springframework.data.mongodb.core.mapping.Field int fieldWithField;
@org.springframework.data.mongodb.core.mapping.Field(
write = org.springframework.data.mongodb.core.mapping.Field.Write.NON_NULL) Integer writeNonNull;
@org.springframework.data.mongodb.core.mapping.Field(
write = org.springframework.data.mongodb.core.mapping.Field.Write.ALWAYS) Integer writeAlways;
}

View File

@@ -5,6 +5,7 @@
== What's New in Spring Data MongoDB 3.3
* Extended support for <<mapping-usage.document-references, referencing>> entities.
* Include/exclude `null` properties on write to `Document` through `@Field(write=…)`.
[[new-features.3.2]]
== What's New in Spring Data MongoDB 3.2