diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index 1776255ff..ea0d35678 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -1019,6 +1019,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App return removeTypeInfoRecursively(newDbo); } + if (typeInformation.getType().equals(NestedDocument.class)) { + return removeTypeInfo(newDbo); + } + return !obj.getClass().equals(typeInformation.getType()) ? newDbo : removeTypeInfoRecursively(newDbo); } @@ -1033,7 +1037,35 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App } /** - * Removes the type information from the conversion result. + * Removes only the type information from the root document. + * + * @param object + * @return + */ + private Object removeTypeInfo(Object object) { + + if (!(object instanceof DBObject)) { + return object; + } + + DBObject dbObject = (DBObject) object; + String keyToRemove = null; + for (String key : dbObject.keySet()) { + + if (typeMapper.isTypeKey(key)) { + keyToRemove = key; + } + } + + if (keyToRemove != null) { + dbObject.removeField(keyToRemove); + } + + return dbObject; + } + + /** + * Removes the type information from the entire conversion result. * * @param object * @return @@ -1194,4 +1226,15 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App DBObject readRef(DBRef ref) { return dbRefResolver.fetch(ref); } + + /** + * Marker class used to indicate we have a non root document object here that might be used within an update - so we + * need to preserve type hints for potential nested elements but need to remove it on top level. + * + * @author Christoph Strobl + * @since 1.8 + */ + static class NestedDocument { + + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java index ef9d8a6cf..b6f1292c0 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java @@ -826,7 +826,7 @@ public class QueryMapper { try { - PropertyPath path = PropertyPath.from(pathExpression, entity.getTypeInformation()); + PropertyPath path = PropertyPath.from(pathExpression.replaceAll("\\.\\d", ""), entity.getTypeInformation()); PersistentPropertyPath propertyPath = mappingContext.getPersistentPropertyPath(path); Iterator iterator = propertyPath.iterator(); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java index c9314b965..d3e89c6ba 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.util.Map.Entry; import org.springframework.core.convert.converter.Converter; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.context.MappingContext; +import org.springframework.data.mongodb.core.convert.MappingMongoConverter.NestedDocument; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty.PropertyToFieldNameConverter; @@ -29,6 +30,7 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update.Modifier; import org.springframework.data.mongodb.core.query.Update.Modifiers; import org.springframework.data.util.ClassTypeInformation; +import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; import com.mongodb.BasicDBObject; @@ -43,6 +45,7 @@ import com.mongodb.DBObject; */ public class UpdateMapper extends QueryMapper { + private static final ClassTypeInformation NESTED_DOCUMENT = ClassTypeInformation.from(NestedDocument.class); private final MongoConverter converter; /** @@ -66,7 +69,7 @@ public class UpdateMapper extends QueryMapper { @Override protected Object delegateConvertToMongoType(Object source, MongoPersistentEntity entity) { return entity == null ? super.delegateConvertToMongoType(source, null) : converter.convertToMongoType(source, - entity.getTypeInformation()); + getTypeHintForEntity(entity)); } /* @@ -97,14 +100,14 @@ public class UpdateMapper extends QueryMapper { if (rawValue instanceof Modifier) { - value = getMappedValue((Modifier) rawValue); + value = getMappedValue(field, (Modifier) rawValue); } else if (rawValue instanceof Modifiers) { DBObject modificationOperations = new BasicDBObject(); for (Modifier modifier : ((Modifiers) rawValue).getModifiers()) { - modificationOperations.putAll(getMappedValue(modifier).toMap()); + modificationOperations.putAll(getMappedValue(field, modifier).toMap()); } value = modificationOperations; @@ -132,12 +135,40 @@ public class UpdateMapper extends QueryMapper { return value instanceof Query; } - private DBObject getMappedValue(Modifier modifier) { + private DBObject getMappedValue(Field field, Modifier modifier) { - Object value = converter.convertToMongoType(modifier.getValue(), ClassTypeInformation.OBJECT); + Object value = converter.convertToMongoType(modifier.getValue(), getTypeHintForField(field)); return new BasicDBObject(modifier.getKey(), value); } + private TypeInformation getTypeHintForField(Field field) { + + if (field == null || field.getProperty() == null) { + return ClassTypeInformation.OBJECT; + } + + if (field.getProperty().getActualType().isInterface() + || java.lang.reflect.Modifier.isAbstract(field.getProperty().getActualType().getModifiers())) { + return ClassTypeInformation.OBJECT; + } + + return NESTED_DOCUMENT; + } + + private TypeInformation getTypeHintForEntity(MongoPersistentEntity entity) { + return processTypeHintForNestedDocuments(entity.getTypeInformation()); + } + + private TypeInformation processTypeHintForNestedDocuments(TypeInformation info) { + + Class type = info.getActualType().getType(); + if (type.isInterface() || java.lang.reflect.Modifier.isAbstract(type.getModifiers())) { + return info; + } + return NESTED_DOCUMENT; + + } + /* * (non-Javadoc) * @see org.springframework.data.mongodb.core.convert.QueryMapper#createPropertyField(org.springframework.data.mongodb.core.mapping.MongoPersistentEntity, java.lang.String, org.springframework.data.mapping.context.MappingContext) @@ -233,7 +264,35 @@ public class UpdateMapper extends QueryMapper { protected String mapPropertyName(MongoPersistentProperty property) { String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property); - return iterator.hasNext() && iterator.next().equals("$") ? String.format("%s.$", mappedName) : mappedName; + + boolean inspect = iterator.hasNext(); + while (inspect) { + + String partial = iterator.next(); + + boolean isPositional = isPositionalParameter(partial); + if (isPositional) { + mappedName += "." + partial; + } + + inspect = isPositional && iterator.hasNext(); + } + + return mappedName; + } + + boolean isPositionalParameter(String partial) { + + if (partial.equals("$")) { + return true; + } + + try { + Long.valueOf(partial); + return true; + } catch (NumberFormatException e) { + return false; + } } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java index da9ae7aa2..914d4bd4c 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java @@ -196,6 +196,7 @@ public class MongoTemplateTests { template.dropCollection(SomeContent.class); template.dropCollection(SomeTemplate.class); template.dropCollection(Address.class); + template.dropCollection(DocumentWithCollectionOfSamples.class); } @Test @@ -2210,11 +2211,12 @@ public class MongoTemplateTests { assertThat(retrieved.model.value(), equalTo("value2")); } - // Rewrite the whole collection - // Passes in 1.6.0+, but changes order position of type hint _class + /** + * @see DATAMONGO-1210 + */ @Test - public void findAndModifyShouldRetainTypeInformationWithinUpdatedTypeOnDocumentWithNestedCollection() - { + public void findAndModifyShouldRetainTypeInformationWithinUpdatedTypeOnDocumentWithNestedCollectionWhenWholeCollectionIsReplaced() { + DocumentWithNestedCollection doc = new DocumentWithNestedCollection(); Map entry = new HashMap(); @@ -2246,12 +2248,12 @@ public class MongoTemplateTests { assertThat(retrieved.models.get(0).get("key2").value(), equalTo("value2")); } - - // Update first list element - // Fails in 1.6.2+ + /** + * @see DATAMONGO-1210 + */ @Test - public void findAndModifyShouldRetainTypeInformationWithinUpdatedTypeOnDocumentWithNestedCollection2() - { + public void findAndModifyShouldRetainTypeInformationWithinUpdatedTypeOnDocumentWithNestedCollectionWhenFirstElementIsReplaced() { + DocumentWithNestedCollection doc = new DocumentWithNestedCollection(); Map entry = new HashMap(); @@ -2283,11 +2285,12 @@ public class MongoTemplateTests { assertThat(retrieved.models.get(0).get("key2").value(), equalTo("value2")); } - // Add second list element - // Fails in 1.6.2+ + /** + * @see DATAMONGO-1210 + */ @Test - public void findAndModifyShouldAddTypeInformationOnDocumentWithNestedCollection2() - { + public void findAndModifyShouldAddTypeInformationOnDocumentWithNestedCollectionObjectInsertedAtSecondIndex() { + DocumentWithNestedCollection doc = new DocumentWithNestedCollection(); Map entry = new HashMap(); @@ -2318,15 +2321,18 @@ public class MongoTemplateTests { assertThat(retrieved.models.get(1).get("key2").value(), equalTo("value2")); } - // Update the collection of the embedded document - // Fails in 1.6.0+ + /** + * @see DATAMONGO-1210 + */ @Test - public void findAndModifyShouldRetainTypeInformationWithinUpdatedTypeOnEmbeddedDocumentWithCollection() throws Exception - { + public void findAndModifyShouldRetainTypeInformationWithinUpdatedTypeOnEmbeddedDocumentWithCollectionWhenUpdatingPositionedElement() + throws Exception { + List models = new ArrayList(); models.add(new ModelA("value1")); - DocumentWithEmbeddedDocumentWithCollection doc = new DocumentWithEmbeddedDocumentWithCollection(new DocumentWithCollection(models)); + DocumentWithEmbeddedDocumentWithCollection doc = new DocumentWithEmbeddedDocumentWithCollection( + new DocumentWithCollection(models)); template.save(doc); @@ -2337,22 +2343,26 @@ public class MongoTemplateTests { template.findAndModify(query, update, DocumentWithEmbeddedDocumentWithCollection.class); - DocumentWithEmbeddedDocumentWithCollection retrieved = template.findOne(query, DocumentWithEmbeddedDocumentWithCollection.class); + DocumentWithEmbeddedDocumentWithCollection retrieved = template.findOne(query, + DocumentWithEmbeddedDocumentWithCollection.class); assertThat(retrieved, notNullValue()); assertThat(retrieved.embeddedDocument.models, hasSize(1)); assertThat(retrieved.embeddedDocument.models.get(0).value(), is("value2")); } - // Update the collection of the embedded document - // Fails in 1.6.0+ + /** + * @see DATAMONGO-1210 + */ @Test - public void findAndModifyShouldAddTypeInformationWithinUpdatedTypeOnEmbeddedDocumentWithCollection2() throws Exception - { + public void findAndModifyShouldAddTypeInformationWithinUpdatedTypeOnEmbeddedDocumentWithCollectionWhenUpdatingSecondElement() + throws Exception { + List models = new ArrayList(); models.add(new ModelA("value1")); - DocumentWithEmbeddedDocumentWithCollection doc = new DocumentWithEmbeddedDocumentWithCollection(new DocumentWithCollection(models)); + DocumentWithEmbeddedDocumentWithCollection doc = new DocumentWithEmbeddedDocumentWithCollection( + new DocumentWithCollection(models)); template.save(doc); @@ -2363,7 +2373,8 @@ public class MongoTemplateTests { template.findAndModify(query, update, DocumentWithEmbeddedDocumentWithCollection.class); - DocumentWithEmbeddedDocumentWithCollection retrieved = template.findOne(query, DocumentWithEmbeddedDocumentWithCollection.class); + DocumentWithEmbeddedDocumentWithCollection retrieved = template.findOne(query, + DocumentWithEmbeddedDocumentWithCollection.class); assertThat(retrieved, notNullValue()); assertThat(retrieved.embeddedDocument.models, hasSize(2)); @@ -2371,35 +2382,42 @@ public class MongoTemplateTests { assertThat(retrieved.embeddedDocument.models.get(1).value(), is("value2")); } - // Rewrite the embedded document - // Fails in 1.6.0+ + /** + * @see DATAMONGO-1210 + */ @Test - public void findAndModifyShouldAddTypeInformationWithinUpdatedTypeOnEmbeddedDocumentWithCollection3() throws Exception - { - List models = Arrays.asList(new ModelA("value1")); + public void findAndModifyShouldAddTypeInformationWithinUpdatedTypeOnEmbeddedDocumentWithCollectionWhenRewriting() + throws Exception { + + List models = Arrays. asList(new ModelA("value1")); - DocumentWithEmbeddedDocumentWithCollection doc = new DocumentWithEmbeddedDocumentWithCollection(new DocumentWithCollection(models)); + DocumentWithEmbeddedDocumentWithCollection doc = new DocumentWithEmbeddedDocumentWithCollection( + new DocumentWithCollection(models)); template.save(doc); Query query = query(where("id").is(doc.id)); - Update update = Update.update("embeddedDocument", new DocumentWithCollection(Arrays.asList(new ModelA("value2")))); + Update update = Update.update("embeddedDocument", + new DocumentWithCollection(Arrays. asList(new ModelA("value2")))); assertThat(template.findOne(query, DocumentWithEmbeddedDocumentWithCollection.class), notNullValue()); template.findAndModify(query, update, DocumentWithEmbeddedDocumentWithCollection.class); - DocumentWithEmbeddedDocumentWithCollection retrieved = template.findOne(query, DocumentWithEmbeddedDocumentWithCollection.class); + DocumentWithEmbeddedDocumentWithCollection retrieved = template.findOne(query, + DocumentWithEmbeddedDocumentWithCollection.class); assertThat(retrieved, notNullValue()); assertThat(retrieved.embeddedDocument.models, hasSize(1)); assertThat(retrieved.embeddedDocument.models.get(0).value(), is("value2")); } - // Fails in 1.6.0+ + /** + * @see DATAMONGO-1210 + */ @Test - public void findAndModifyShouldAddTypeInformationWithinUpdatedTypeOnDocumentWithNestedLists() - { + public void findAndModifyShouldAddTypeInformationWithinUpdatedTypeOnDocumentWithNestedLists() { + DocumentWithNestedList doc = new DocumentWithNestedList(); List entry = new ArrayList(); @@ -2835,8 +2853,12 @@ public class MongoTemplateTests { assertThat(template.findOne(query, DocumentWithCollectionOfSimpleType.class).values, hasSize(3)); } + /** + * @see DATAMONGO-1210 + */ @Test public void findAndModifyAddToSetWithEachShouldNotAddDuplicatesNorTypeHintForSimpleDocuments() { + DocumentWithCollectionOfSamples doc = new DocumentWithCollectionOfSamples(); doc.samples = Arrays.asList(new Sample(null, "sample1")); @@ -2846,7 +2868,7 @@ public class MongoTemplateTests { assertThat(template.findOne(query, DocumentWithCollectionOfSamples.class), notNullValue()); - Update update = new Update().addToSet("samples").each(Arrays.asList(new Sample(null, "sample2"), new Sample(null, "sample1"))); + Update update = new Update().addToSet("samples").each(new Sample(null, "sample2"), new Sample(null, "sample1")); template.findAndModify(query, update, DocumentWithCollectionOfSamples.class); @@ -3102,8 +3124,7 @@ public class MongoTemplateTests { List values; } - static class DocumentWithCollectionOfSamples - { + static class DocumentWithCollectionOfSamples { @Id String id; List samples; } @@ -3114,25 +3135,21 @@ public class MongoTemplateTests { List string2; } - static class DocumentWithNestedCollection - { + static class DocumentWithNestedCollection { @Id String id; List> models = new ArrayList>(); } - static class DocumentWithNestedList - { + static class DocumentWithNestedList { @Id String id; List> models = new ArrayList>(); - } + } - static class DocumentWithEmbeddedDocumentWithCollection - { + static class DocumentWithEmbeddedDocumentWithCollection { @Id String id; DocumentWithCollection embeddedDocument; - DocumentWithEmbeddedDocumentWithCollection(DocumentWithCollection embeddedDocument) - { + DocumentWithEmbeddedDocumentWithCollection(DocumentWithCollection embeddedDocument) { this.embeddedDocument = embeddedDocument; } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java index d2cc763bb..b88b773fc 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java @@ -20,8 +20,10 @@ import static org.hamcrest.collection.IsMapContaining.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import static org.springframework.data.mongodb.core.DBObjectTestUtils.*; +import static org.springframework.data.mongodb.test.util.IsBsonObject.*; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.hamcrest.Matcher; @@ -524,7 +526,6 @@ public class UpdateMapperUnitTests { assertThat(((DBObject) updateValue).get("_class").toString(), equalTo("org.springframework.data.mongodb.core.convert.UpdateMapperUnitTests$ModelImpl")); } - } /** @@ -595,6 +596,109 @@ public class UpdateMapperUnitTests { assertThat($unset, equalTo(new BasicDBObjectBuilder().add("dbRefAnnotatedList.$", 1).get())); } + /** + * @see DATAMONGO-1210 + */ + @Test + public void mappingEachOperatorShouldNotAddTypeInfoForNonInterfaceNonAbstractTypes() { + + Update update = new Update().addToSet("nestedDocs").each(new NestedDocument("nested-1"), + new NestedDocument("nested-2")); + + DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), + context.getPersistentEntity(DocumentWithNestedCollection.class)); + + assertThat(mappedUpdate, isBsonObject().notContaining("$addToSet.nestedDocs.$each.[0]._class")); + assertThat(mappedUpdate, isBsonObject().notContaining("$addToSet.nestedDocs.$each.[1]._class")); + } + + /** + * @see DATAMONGO-1210 + */ + @Test + public void mappingEachOperatorShouldAddTypeHintForInterfaceTypes() { + + Update update = new Update().addToSet("models").each(new ModelImpl(1), new ModelImpl(2)); + + DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), + context.getPersistentEntity(ListModelWrapper.class)); + + assertThat(mappedUpdate, isBsonObject().containing("$addToSet.models.$each.[0]._class", ModelImpl.class.getName())); + assertThat(mappedUpdate, isBsonObject().containing("$addToSet.models.$each.[1]._class", ModelImpl.class.getName())); + } + + /** + * @see DATAMONGO-1210 + */ + @Test + public void mappingEachOperatorShouldAddTypeHintForAbstractTypes() { + + Update update = new Update().addToSet("list").each(new ConcreteChildClass("foo", "one"), + new ConcreteChildClass("bar", "two")); + + DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), + context.getPersistentEntity(ParentClass.class)); + + assertThat(mappedUpdate, + isBsonObject().containing("$addToSet.aliased.$each.[0]._class", ConcreteChildClass.class.getName())); + assertThat(mappedUpdate, + isBsonObject().containing("$addToSet.aliased.$each.[1]._class", ConcreteChildClass.class.getName())); + } + + /** + * @see DATAMONGO-1210 + */ + @Test + public void mappingShouldOnlyRemoveTypeHintFromTopLevelTypeInCaseOfNestedDocument() { + + WrapperAroundInterfaceType wait = new WrapperAroundInterfaceType(); + wait.interfaceType = new ModelImpl(1); + + Update update = new Update().addToSet("listHoldingConcretyTypeWithInterfaceTypeAttribute").each(wait); + DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), + context.getPersistentEntity(DomainTypeWithListOfConcreteTypesHavingSingleInterfaceTypeAttribute.class)); + + assertThat(mappedUpdate, + isBsonObject().notContaining("$addToSet.listHoldingConcretyTypeWithInterfaceTypeAttribute.$each.[0]._class")); + assertThat( + mappedUpdate, + isBsonObject().containing( + "$addToSet.listHoldingConcretyTypeWithInterfaceTypeAttribute.$each.[0].interfaceType._class", + ModelImpl.class.getName())); + } + + /** + * @see DATAMONGO-1210 + */ + @Test + public void mappingShouldRetainTypeInformationOfNestedListWhenUpdatingConcreteyParentType() { + + ListModelWrapper lmw = new ListModelWrapper(); + lmw.models = Collections. singletonList(new ModelImpl(1)); + + Update update = new Update().set("concreteTypeWithListAttributeOfInterfaceType", lmw); + DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), + context.getPersistentEntity(DomainTypeWrappingConcreteyTypeHavingListOfInterfaceTypeAttributes.class)); + + assertThat(mappedUpdate, isBsonObject().notContaining("$set.concreteTypeWithListAttributeOfInterfaceType._class")); + assertThat( + mappedUpdate, + isBsonObject().containing("$set.concreteTypeWithListAttributeOfInterfaceType.models.[0]._class", + ModelImpl.class.getName())); + } + + static class DomainTypeWrappingConcreteyTypeHavingListOfInterfaceTypeAttributes { + ListModelWrapper concreteTypeWithListAttributeOfInterfaceType; + } + + static class DomainTypeWithListOfConcreteTypesHavingSingleInterfaceTypeAttribute { + List listHoldingConcretyTypeWithInterfaceTypeAttribute; + } + + static class WrapperAroundInterfaceType { + Model interfaceType; + } + @org.springframework.data.mongodb.core.mapping.Document(collection = "DocumentWithReferenceToInterface") static interface DocumentWithReferenceToInterface { @@ -728,6 +832,10 @@ public class UpdateMapperUnitTests { static class DomainEntity { List collectionOfNestedEntities; + + public List getCollectionOfNestedEntities() { + return collectionOfNestedEntities; + } } static class NestedEntity { @@ -770,4 +878,19 @@ public class UpdateMapperUnitTests { @Field("mapped") DocumentWithDBRefCollection nested; } + + static class DocumentWithNestedCollection { + List nestedDocs; + } + + static class NestedDocument { + String name; + + public NestedDocument(String name) { + super(); + this.name = name; + } + + } + } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/IsBsonObject.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/IsBsonObject.java index 04f4b4ce9..0657dd131 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/IsBsonObject.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/IsBsonObject.java @@ -90,6 +90,10 @@ public class IsBsonObject extends TypeSafeMatcher { return false; } + if (o != null && expectation.not) { + return false; + } + } return true; }