Browse Source

DATAMONGO-1210 - Fixed type hints for usage with findAndModify(…).

We now inspect the actual field type during update mapping and provide a type hint accordingly. Simple, non interface and non abstract types will no longer be decorated with the _class attribute. We now honor positional parameters when trying to map paths to properties. This allows more decent type mapping since we have now access to the meta model which allows us to check if presence of type hint (aka _class) is required.

We now add a special type hint indicating nested types to the converter. This allows more fine grained removal of _class property without the need to break the contract of MongoWriter.convertToMongoType(…).

Original pull request: #292.
pull/299/merge
Christoph Strobl 11 years ago committed by Oliver Gierke
parent
commit
394f695416
  1. 45
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  2. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java
  3. 73
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java
  4. 113
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java
  5. 125
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java
  6. 4
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/IsBsonObject.java

45
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 @@ -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 @@ -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 @@ -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 {
}
}

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java

@ -826,7 +826,7 @@ public class QueryMapper { @@ -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<MongoPersistentProperty> propertyPath = mappingContext.getPersistentPropertyPath(path);
Iterator<MongoPersistentProperty> iterator = propertyPath.iterator();

73
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java

@ -1,5 +1,5 @@ @@ -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; @@ -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; @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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;
}
}
}

113
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java

@ -196,6 +196,7 @@ public class MongoTemplateTests { @@ -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 { @@ -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<String, Model> entry = new HashMap<String, Model>();
@ -2246,12 +2248,12 @@ public class MongoTemplateTests { @@ -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<String, Model> entry = new HashMap<String, Model>();
@ -2283,11 +2285,12 @@ public class MongoTemplateTests { @@ -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<String, Model> entry = new HashMap<String, Model>();
@ -2318,15 +2321,18 @@ public class MongoTemplateTests { @@ -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<Model> models = new ArrayList<Model>();
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 { @@ -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<Model> models = new ArrayList<Model>();
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 { @@ -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 { @@ -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<Model> models = Arrays.<Model>asList(new ModelA("value1"));
public void findAndModifyShouldAddTypeInformationWithinUpdatedTypeOnEmbeddedDocumentWithCollectionWhenRewriting()
throws Exception {
List<Model> models = Arrays.<Model> 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.<Model>asList(new ModelA("value2"))));
Update update = Update.update("embeddedDocument",
new DocumentWithCollection(Arrays.<Model> 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<Model> entry = new ArrayList<Model>();
@ -2835,8 +2853,12 @@ public class MongoTemplateTests { @@ -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 { @@ -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 { @@ -3102,8 +3124,7 @@ public class MongoTemplateTests {
List<String> values;
}
static class DocumentWithCollectionOfSamples
{
static class DocumentWithCollectionOfSamples {
@Id String id;
List<Sample> samples;
}
@ -3114,25 +3135,21 @@ public class MongoTemplateTests { @@ -3114,25 +3135,21 @@ public class MongoTemplateTests {
List<String> string2;
}
static class DocumentWithNestedCollection
{
static class DocumentWithNestedCollection {
@Id String id;
List<Map<String, Model>> models = new ArrayList<Map<String, Model>>();
}
static class DocumentWithNestedList
{
static class DocumentWithNestedList {
@Id String id;
List<List<Model>> models = new ArrayList<List<Model>>();
}
}
static class DocumentWithEmbeddedDocumentWithCollection
{
static class DocumentWithEmbeddedDocumentWithCollection {
@Id String id;
DocumentWithCollection embeddedDocument;
DocumentWithEmbeddedDocumentWithCollection(DocumentWithCollection embeddedDocument)
{
DocumentWithEmbeddedDocumentWithCollection(DocumentWithCollection embeddedDocument) {
this.embeddedDocument = embeddedDocument;
}
}

125
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java

@ -20,8 +20,10 @@ import static org.hamcrest.collection.IsMapContaining.*; @@ -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 { @@ -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 { @@ -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.<Model> 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<WrapperAroundInterfaceType> 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 { @@ -728,6 +832,10 @@ public class UpdateMapperUnitTests {
static class DomainEntity {
List<NestedEntity> collectionOfNestedEntities;
public List<NestedEntity> getCollectionOfNestedEntities() {
return collectionOfNestedEntities;
}
}
static class NestedEntity {
@ -770,4 +878,19 @@ public class UpdateMapperUnitTests { @@ -770,4 +878,19 @@ public class UpdateMapperUnitTests {
@Field("mapped") DocumentWithDBRefCollection nested;
}
static class DocumentWithNestedCollection {
List<NestedDocument> nestedDocs;
}
static class NestedDocument {
String name;
public NestedDocument(String name) {
super();
this.name = name;
}
}
}

4
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/IsBsonObject.java

@ -90,6 +90,10 @@ public class IsBsonObject<T extends BSONObject> extends TypeSafeMatcher<T> { @@ -90,6 +90,10 @@ public class IsBsonObject<T extends BSONObject> extends TypeSafeMatcher<T> {
return false;
}
if (o != null && expectation.not) {
return false;
}
}
return true;
}

Loading…
Cancel
Save