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 ded2b9bf7..b341345c9 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 @@ -186,6 +186,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); @@ -2223,6 +2226,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 entry = new HashMap(); + 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 entry = new HashMap(); + 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 entry = new HashMap(); + 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 models = new ArrayList(); + 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 models = new ArrayList(); + 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 models = Arrays.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.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 entry = new ArrayList(); + 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 */ @@ -2628,6 +2851,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 */ @@ -2834,12 +3080,41 @@ public class MongoTemplateTests { List values; } + static class DocumentWithCollectionOfSamples + { + @Id String id; + List samples; + } + static class DocumentWithMultipleCollections { @Id String id; List string1; List string2; } + static class DocumentWithNestedCollection + { + @Id String id; + List> models = new ArrayList>(); + } + + static class DocumentWithNestedList + { + @Id String id; + List> models = new ArrayList>(); + } + + static class DocumentWithEmbeddedDocumentWithCollection + { + @Id String id; + DocumentWithCollection embeddedDocument; + + DocumentWithEmbeddedDocumentWithCollection(DocumentWithCollection embeddedDocument) + { + this.embeddedDocument = embeddedDocument; + } + } + static interface Model { String value();