From e987a853ac578980c088c1b9a03e44549f613dbb Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 17 Nov 2016 15:10:51 +0100 Subject: [PATCH] DATAMONGO-1509 - Polishing. Adopt type hint assertion for existing _class field checks. Simplify test code to use Collections.singletonList instead of Arrays.asList. Replace BasicDBList with List in JavaDoc. Use type inference for DocumentTestUtils.getAsDBList to avoid casts in test code. Extend documentation. Original pull request: #411. --- .../data/mongodb/core/DocumentTestUtils.java | 8 ++++---- .../data/mongodb/core/MongoTemplateTests.java | 6 +++--- .../core/convert/UpdateMapperUnitTests.java | 15 +++++++-------- .../event/ApplicationContextEventTests.java | 3 ++- src/main/asciidoc/new-features.adoc | 6 ++++++ .../asciidoc/reference/mongo-repositories.adoc | 2 ++ src/main/asciidoc/reference/mongodb.adoc | 12 +++++++----- 7 files changed, 31 insertions(+), 21 deletions(-) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DocumentTestUtils.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DocumentTestUtils.java index f6c0f8384..741c3aeae 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DocumentTestUtils.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DocumentTestUtils.java @@ -49,18 +49,18 @@ public abstract class DocumentTestUtils { /** * Expects the field with the given key to be not {@literal null} and a {@link BasicDBList}. * - * @param source the {@link Document} to lookup the {@link BasicDBList} in - * @param key the key of the field to find the {@link BasicDBList} in + * @param source the {@link Document} to lookup the {@link List} in + * @param key the key of the field to find the {@link List} in * @return */ - public static List getAsDBList(Document source, String key) { + public static List getAsDBList(Document source, String key) { return getTypedValue(source, key, List.class); } /** * Expects the list element with the given index to be a non-{@literal null} {@link Document} and returns it. * - * @param source the {@link BasicDBList} to look up the {@link Document} element in + * @param source the {@link List} to look up the {@link Document} element in * @param index the index of the element expected to contain a {@link Document} * @return */ 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 1b567948d..7bcd343a8 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 @@ -3482,7 +3482,7 @@ public class MongoTemplateTests { Document document = new Document(); - template.insertAll(Arrays.asList(document)); + template.insertAll(Collections.singletonList(document)); assertThat(document.id, is(notNullValue())); } @@ -3492,9 +3492,9 @@ public class MongoTemplateTests { * @see DATAMONGO-1509 */ @Test - public void findsByGnericNestedListElements() { + public void findsByGenericNestedListElements() { - List modelList = Arrays.asList(new ModelA("value")); + List modelList = Collections.singletonList(new ModelA("value")); DocumentWithCollection dwc = new DocumentWithCollection(modelList); template.insert(dwc); 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 a566bd10a..58c7ea4e3 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 @@ -102,7 +102,7 @@ public class UpdateMapperUnitTests { Document push = getAsDocument(mappedObject, "$push"); Document list = getAsDocument(push, "aliased"); - assertThat(list.get("_class"), is(ConcreteChildClass.class.getName())); + assertTypeHint(list, ConcreteChildClass.class); } /** @@ -119,7 +119,7 @@ public class UpdateMapperUnitTests { Document set = getAsDocument(mappedObject, "$set"); Document modelDocument = (Document) set.get("model"); - assertThat(modelDocument.get("_class"), not(nullValue())); + assertTypeHint(modelDocument, ModelImpl.class); } /** @@ -168,7 +168,7 @@ public class UpdateMapperUnitTests { Document set = getAsDocument(mappedObject, "$set"); Document modelDocument = getAsDocument(set, "aliased.$"); - assertThat(modelDocument.get("_class"), is(ConcreteChildClass.class.getName())); + assertTypeHint(modelDocument, ConcreteChildClass.class); } /** @@ -205,8 +205,8 @@ public class UpdateMapperUnitTests { Document someObject = getAsDocument(document, "aliased.$.someObject"); assertThat(someObject, is(notNullValue())); - assertThat(someObject.get("_class"), is(ConcreteChildClass.class.getName())); assertThat(someObject.get("value"), is("bubu")); + assertTypeHint(someObject, ConcreteChildClass.class); } /** @@ -276,9 +276,9 @@ public class UpdateMapperUnitTests { Document push = getAsDocument(mappedObject, "$push"); Document model = getAsDocument(push, "models"); - List each = getAsDBList(model, "$each"); + List each = getAsDBList(model, "$each"); - assertThat(((Document) each.get(0)).get("_class").toString(), equalTo(ListModel.class.getName())); + assertTypeHint(each.get(0), ListModel.class); } /** @@ -566,8 +566,7 @@ public class UpdateMapperUnitTests { List each = getAsDBList(values, "$each"); for (Object updateValue : each) { - assertThat(((Document) updateValue).get("_class").toString(), - equalTo("org.springframework.data.mongodb.core.convert.UpdateMapperUnitTests$ModelImpl")); + assertTypeHint((Document) updateValue, ModelImpl.class); } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/ApplicationContextEventTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/ApplicationContextEventTests.java index bc258a5d8..5f64df458 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/ApplicationContextEventTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/ApplicationContextEventTests.java @@ -19,6 +19,7 @@ import static org.hamcrest.collection.IsCollectionWithSize.*; import static org.hamcrest.core.Is.*; import static org.hamcrest.core.IsEqual.*; import static org.junit.Assert.*; +import static org.springframework.data.mongodb.core.DocumentTestUtils.assertTypeHint; import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*; @@ -421,9 +422,9 @@ public class ApplicationContextEventTests { assertEquals(p.getId(), p2.getId()); assertEquals(p.getText(), p2.getText()); - assertEquals("org.springframework.data.mongodb.core.mapping.PersonPojoStringId", document.get("_class")); assertEquals("1", document.get("_id")); assertEquals("Text", document.get("text")); + assertTypeHint(document, PersonPojoStringId.class); } @Data diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 8066c6a08..98e753396 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -1,6 +1,12 @@ [[new-features]] = New & Noteworthy +[[new-features.2-0-0]] +== What's new in Spring Data MongoDB 2.0 +* Upgrade to Java 8. +* Usage of the `Document` API instead of `DBObject`. +* <>. + [[new-features.1-10-0]] == What's new in Spring Data MongoDB 1.10 * Support for `$min`, `$max` and `$slice` operators via `Update`. diff --git a/src/main/asciidoc/reference/mongo-repositories.adoc b/src/main/asciidoc/reference/mongo-repositories.adoc index eb053f892..d56783007 100644 --- a/src/main/asciidoc/reference/mongo-repositories.adoc +++ b/src/main/asciidoc/reference/mongo-repositories.adoc @@ -273,6 +273,8 @@ NOTE: Note that for version 1.0 we currently don't support referring to paramete | `{"location" : {"$exists" : exists }}` |=== +NOTE: If the property criterion compares a document, the order of the fields and exact equality in the document matters. + [[mongodb.repositories.queries.delete]] === Repository delete queries diff --git a/src/main/asciidoc/reference/mongodb.adoc b/src/main/asciidoc/reference/mongodb.adoc index ada5948fc..5f8387e37 100644 --- a/src/main/asciidoc/reference/mongodb.adoc +++ b/src/main/asciidoc/reference/mongodb.adoc @@ -666,7 +666,8 @@ When querying and updating `MongoTemplate` will use the converter to handle conv As MongoDB collections can contain documents that represent instances of a variety of types. A great example here is if you store a hierarchy of classes or simply have a class with a property of type `Object`. In the latter case the values held inside that property have to be read in correctly when retrieving the object. Thus we need a mechanism to store type information alongside the actual document. -To achieve that the `MappingMongoConverter` uses a `MongoTypeMapper` abstraction with `DefaultMongoTypeMapper` as it's main implementation. Its default behavior is storing the fully qualified classname under `_class` inside the document for the top-level document as well as for every value if it's a complex type and a subtype of the property type declared. +To achieve that the `MappingMongoConverter` uses a `MongoTypeMapper` abstraction with `DefaultMongoTypeMapper` as it's main implementation. Its default behavior is storing the fully qualified classname under `_class` inside the document. Type hints are written for top-level documents as well as for every value if it's a complex type and a subtype of the property type declared. + .Type mapping ==== @@ -685,13 +686,14 @@ sample.value = new Person(); mongoTemplate.save(sample); -{ "_class" : "com.acme.Sample", - "value" : { "_class" : "com.acme.Person" } +{ + "value" : { "_class" : "com.acme.Person" }, + "_class" : "com.acme.Sample" } ---- ==== -As you can see we store the type information for the actual root class persistent as well as for the nested type as it is complex and a subtype of `Contact`. So if you're now using `mongoTemplate.findAll(Object.class, "sample")` we are able to find out that the document stored shall be a `Sample` instance. We are also able to find out that the value property shall be a `Person` actually. +As you can see we store the type information as last field for the actual root class as well as for the nested type as it is complex and a subtype of `Contact`. So if you're now using `mongoTemplate.findAll(Object.class, "sample")` we are able to find out that the document stored shall be a `Sample` instance. We are also able to find out that the value property shall be a `Person` actually. ==== Customizing type mapping @@ -1053,7 +1055,7 @@ As you can see most methods return the `Criteria` object to provide a fluent sty * `Criteria` *gte* `(Object o)` Creates a criterion using the `$gte` operator * `Criteria` *in* `(Object... o)` Creates a criterion using the `$in` operator for a varargs argument. * `Criteria` *in* `(Collection collection)` Creates a criterion using the `$in` operator using a collection -* `Criteria` *is* `(Object o)` Creates a criterion using the `$is` operator +* `Criteria` *is* `(Object o)` Creates a criterion using field matching (`{ key:value }`). If the specified value is a document, the order of the fields and exact equality in the document matters. * `Criteria` *lt* `(Object o)` Creates a criterion using the `$lt` operator * `Criteria` *lte* `(Object o)` Creates a criterion using the `$lte` operator * `Criteria` *mod* `(Number value, Number remainder)` Creates a criterion using the `$mod` operator