Browse Source

DATAMONGO-1210 - Add breaking test case for findAndModify/addToSet/each.

The problem stems from the inconsistent handling of type hints such as MongoTemplate.save(…) does not add a type hint, but findAndModify(…) does. The same values are then treated differently by MongoDB, depending on whether they have a type hint or not. To verify this behavior, you can manually add the (superfluous) type hint to the saved object - findAndModify will then work as expected.

Additional tests demonstrate that findAndModify(…) removes type hints from complex documents in collections that are either nested in another collection or in a document, or doesn't add them in the first place.

Original pull requests: #290, #291.
Related pull request: #292.
CLA: 119820150506013701 (Stefan Ganzer)
pull/299/merge
Stefan Ganzer 11 years ago committed by Oliver Gierke
parent
commit
e4db466ab9
  1. 275
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java

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

@ -189,6 +189,9 @@ public class MongoTemplateTests { @@ -189,6 +189,9 @@ public class MongoTemplateTests {
template.dropCollection(DocumentWithCollection.class);
template.dropCollection(DocumentWithCollectionOfSimpleType.class);
template.dropCollection(DocumentWithMultipleCollections.class);
template.dropCollection(DocumentWithNestedCollection.class);
template.dropCollection(DocumentWithEmbeddedDocumentWithCollection.class);
template.dropCollection(DocumentWithNestedList.class);
template.dropCollection(DocumentWithDBRefCollection.class);
template.dropCollection(SomeContent.class);
template.dropCollection(SomeTemplate.class);
@ -2207,6 +2210,226 @@ public class MongoTemplateTests { @@ -2207,6 +2210,226 @@ 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
@Test
public void findAndModifyShouldRetainTypeInformationWithinUpdatedTypeOnDocumentWithNestedCollection()
{
DocumentWithNestedCollection doc = new DocumentWithNestedCollection();
Map<String, Model> entry = new HashMap<String, Model>();
entry.put("key1", new ModelA("value1"));
doc.models.add(entry);
template.save(doc);
entry.put("key2", new ModelA("value2"));
Query query = query(where("id").is(doc.id));
Update update = Update.update("models", Collections.singletonList(entry));
assertThat(template.findOne(query, DocumentWithNestedCollection.class), notNullValue());
template.findAndModify(query, update, DocumentWithNestedCollection.class);
DocumentWithNestedCollection retrieved = template.findOne(query, DocumentWithNestedCollection.class);
assertThat(retrieved, is(notNullValue()));
assertThat(retrieved.id, is(doc.id));
assertThat(retrieved.models.get(0).entrySet(), hasSize(2));
assertThat(retrieved.models.get(0).get("key1"), instanceOf(ModelA.class));
assertThat(retrieved.models.get(0).get("key1").value(), equalTo("value1"));
assertThat(retrieved.models.get(0).get("key2"), instanceOf(ModelA.class));
assertThat(retrieved.models.get(0).get("key2").value(), equalTo("value2"));
}
// Update first list element
// Fails in 1.6.2+
@Test
public void findAndModifyShouldRetainTypeInformationWithinUpdatedTypeOnDocumentWithNestedCollection2()
{
DocumentWithNestedCollection doc = new DocumentWithNestedCollection();
Map<String, Model> entry = new HashMap<String, Model>();
entry.put("key1", new ModelA("value1"));
doc.models.add(entry);
template.save(doc);
entry.put("key2", new ModelA("value2"));
Query query = query(where("id").is(doc.id));
Update update = Update.update("models.0", entry);
assertThat(template.findOne(query, DocumentWithNestedCollection.class), notNullValue());
template.findAndModify(query, update, DocumentWithNestedCollection.class);
DocumentWithNestedCollection retrieved = template.findOne(query, DocumentWithNestedCollection.class);
assertThat(retrieved, is(notNullValue()));
assertThat(retrieved.id, is(doc.id));
assertThat(retrieved.models.get(0).entrySet(), hasSize(2));
assertThat(retrieved.models.get(0).get("key1"), instanceOf(ModelA.class));
assertThat(retrieved.models.get(0).get("key1").value(), equalTo("value1"));
assertThat(retrieved.models.get(0).get("key2"), instanceOf(ModelA.class));
assertThat(retrieved.models.get(0).get("key2").value(), equalTo("value2"));
}
// Add second list element
// Fails in 1.6.2+
@Test
public void findAndModifyShouldAddTypeInformationOnDocumentWithNestedCollection2()
{
DocumentWithNestedCollection doc = new DocumentWithNestedCollection();
Map<String, Model> entry = new HashMap<String, Model>();
entry.put("key1", new ModelA("value1"));
doc.models.add(entry);
template.save(doc);
Query query = query(where("id").is(doc.id));
Update update = Update.update("models.1", Collections.singletonMap("key2", new ModelA("value2")));
assertThat(template.findOne(query, DocumentWithNestedCollection.class), notNullValue());
template.findAndModify(query, update, DocumentWithNestedCollection.class);
DocumentWithNestedCollection retrieved = template.findOne(query, DocumentWithNestedCollection.class);
assertThat(retrieved, is(notNullValue()));
assertThat(retrieved.id, is(doc.id));
assertThat(retrieved.models.get(0).entrySet(), hasSize(1));
assertThat(retrieved.models.get(1).entrySet(), hasSize(1));
assertThat(retrieved.models.get(0).get("key1"), instanceOf(ModelA.class));
assertThat(retrieved.models.get(0).get("key1").value(), equalTo("value1"));
assertThat(retrieved.models.get(1).get("key2"), instanceOf(ModelA.class));
assertThat(retrieved.models.get(1).get("key2").value(), equalTo("value2"));
}
// Update the collection of the embedded document
// Fails in 1.6.0+
@Test
public void findAndModifyShouldRetainTypeInformationWithinUpdatedTypeOnEmbeddedDocumentWithCollection() throws Exception
{
List<Model> models = new ArrayList<Model>();
models.add(new ModelA("value1"));
DocumentWithEmbeddedDocumentWithCollection doc = new DocumentWithEmbeddedDocumentWithCollection(new DocumentWithCollection(models));
template.save(doc);
Query query = query(where("id").is(doc.id));
Update update = Update.update("embeddedDocument.models.0", new ModelA("value2"));
assertThat(template.findOne(query, DocumentWithEmbeddedDocumentWithCollection.class), notNullValue());
template.findAndModify(query, update, 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+
@Test
public void findAndModifyShouldAddTypeInformationWithinUpdatedTypeOnEmbeddedDocumentWithCollection2() throws Exception
{
List<Model> models = new ArrayList<Model>();
models.add(new ModelA("value1"));
DocumentWithEmbeddedDocumentWithCollection doc = new DocumentWithEmbeddedDocumentWithCollection(new DocumentWithCollection(models));
template.save(doc);
Query query = query(where("id").is(doc.id));
Update update = Update.update("embeddedDocument.models.1", new ModelA("value2"));
assertThat(template.findOne(query, DocumentWithEmbeddedDocumentWithCollection.class), notNullValue());
template.findAndModify(query, update, DocumentWithEmbeddedDocumentWithCollection.class);
DocumentWithEmbeddedDocumentWithCollection retrieved = template.findOne(query, DocumentWithEmbeddedDocumentWithCollection.class);
assertThat(retrieved, notNullValue());
assertThat(retrieved.embeddedDocument.models, hasSize(2));
assertThat(retrieved.embeddedDocument.models.get(0).value(), is("value1"));
assertThat(retrieved.embeddedDocument.models.get(1).value(), is("value2"));
}
// Rewrite the embedded document
// Fails in 1.6.0+
@Test
public void findAndModifyShouldAddTypeInformationWithinUpdatedTypeOnEmbeddedDocumentWithCollection3() throws Exception
{
List<Model> models = Arrays.<Model>asList(new ModelA("value1"));
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"))));
assertThat(template.findOne(query, DocumentWithEmbeddedDocumentWithCollection.class), notNullValue());
template.findAndModify(query, update, 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+
@Test
public void findAndModifyShouldAddTypeInformationWithinUpdatedTypeOnDocumentWithNestedLists()
{
DocumentWithNestedList doc = new DocumentWithNestedList();
List<Model> entry = new ArrayList<Model>();
entry.add(new ModelA("value1"));
doc.models.add(entry);
template.save(doc);
Query query = query(where("id").is(doc.id));
assertThat(template.findOne(query, DocumentWithNestedList.class), notNullValue());
Update update = Update.update("models.0.1", new ModelA("value2"));
template.findAndModify(query, update, DocumentWithNestedList.class);
DocumentWithNestedList retrieved = template.findOne(query, DocumentWithNestedList.class);
assertThat(retrieved, is(notNullValue()));
assertThat(retrieved.id, is(doc.id));
assertThat(retrieved.models.get(0), hasSize(2));
assertThat(retrieved.models.get(0).get(0), instanceOf(ModelA.class));
assertThat(retrieved.models.get(0).get(0).value(), equalTo("value1"));
assertThat(retrieved.models.get(0).get(1), instanceOf(ModelA.class));
assertThat(retrieved.models.get(0).get(1).value(), equalTo("value2"));
}
/**
* @see DATAMONGO-407
*/
@ -2612,6 +2835,29 @@ public class MongoTemplateTests { @@ -2612,6 +2835,29 @@ public class MongoTemplateTests {
assertThat(template.findOne(query, DocumentWithCollectionOfSimpleType.class).values, hasSize(3));
}
@Test
public void findAndModifyAddToSetWithEachShouldNotAddDuplicatesNorTypeHintForSimpleDocuments() {
DocumentWithCollectionOfSamples doc = new DocumentWithCollectionOfSamples();
doc.samples = Arrays.asList(new Sample(null, "sample1"));
template.save(doc);
Query query = query(where("id").is(doc.id));
assertThat(template.findOne(query, DocumentWithCollectionOfSamples.class), notNullValue());
Update update = new Update().addToSet("samples").each(Arrays.asList(new Sample(null, "sample2"), new Sample(null, "sample1")));
template.findAndModify(query, update, DocumentWithCollectionOfSamples.class);
DocumentWithCollectionOfSamples retrieved = template.findOne(query, DocumentWithCollectionOfSamples.class);
assertThat(retrieved, notNullValue());
assertThat(retrieved.samples, hasSize(2));
assertThat(retrieved.samples.get(0).field, is("sample1"));
assertThat(retrieved.samples.get(1).field, is("sample2"));
}
/**
* @see DATAMONGO-888
*/
@ -2856,12 +3102,41 @@ public class MongoTemplateTests { @@ -2856,12 +3102,41 @@ public class MongoTemplateTests {
List<String> values;
}
static class DocumentWithCollectionOfSamples
{
@Id String id;
List<Sample> samples;
}
static class DocumentWithMultipleCollections {
@Id String id;
List<String> string1;
List<String> string2;
}
static class DocumentWithNestedCollection
{
@Id String id;
List<Map<String, Model>> models = new ArrayList<Map<String, Model>>();
}
static class DocumentWithNestedList
{
@Id String id;
List<List<Model>> models = new ArrayList<List<Model>>();
}
static class DocumentWithEmbeddedDocumentWithCollection
{
@Id String id;
DocumentWithCollection embeddedDocument;
DocumentWithEmbeddedDocumentWithCollection(DocumentWithCollection embeddedDocument)
{
this.embeddedDocument = embeddedDocument;
}
}
static interface Model {
String value();

Loading…
Cancel
Save