diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
index 037b753ef..3eeda7911 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
@@ -1316,57 +1316,28 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
}
/**
- * Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter
- *
- * The query document is specified as a standard DBObject and so is the fields specification.
+ * Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter.
+ * The query document is specified as a standard {@link DBObject} and so is the fields specification.
*
- * @param collectionName name of the collection to retrieve the objects from
- * @param query the query document that specifies the criteria used to find a record
- * @param fields the document that specifies the fields to be returned
+ * @param collectionName name of the collection to retrieve the objects from.
+ * @param query the query document that specifies the criteria used to find a record.
+ * @param fields the document that specifies the fields to be returned.
* @param entityClass the parameterized type of the returned list.
- * @return the List of converted objects.
+ * @return the {@link List} of converted objects.
*/
protected T doFindOne(String collectionName, DBObject query, DBObject fields, Class entityClass) {
- EntityReader super T, DBObject> readerToUse = this.mongoConverter;
+
MongoPersistentEntity> entity = mappingContext.getPersistentEntity(entityClass);
DBObject mappedQuery = queryMapper.getMappedObject(query, entity);
-
- return executeFindOneInternal(new FindOneCallback(mappedQuery, fields), new ReadDbObjectCallback(readerToUse,
- entityClass), collectionName);
- }
-
- /**
- * Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. The object is
- * converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless configured
- * otherwise, an instance of MappingMongoConverter will be used. The query document is specified as a standard
- * DBObject and so is the fields specification. Can be overridden by subclasses.
- *
- * @param collectionName name of the collection to retrieve the objects from
- * @param query the query document that specifies the criteria used to find a record
- * @param fields the document that specifies the fields to be returned
- * @param entityClass the parameterized type of the returned list.
- * @param preparer allows for customization of the DBCursor used when iterating over the result set, (apply limits,
- * skips and so on).
- * @return the List of converted objects.
- */
- protected List doFind(String collectionName, DBObject query, DBObject fields, Class entityClass,
- CursorPreparer preparer) {
- return doFind(collectionName, query, fields, entityClass, preparer, new ReadDbObjectCallback(mongoConverter,
- entityClass));
- }
-
- protected List doFind(String collectionName, DBObject query, DBObject fields, Class entityClass,
- CursorPreparer preparer, DbObjectCallback objectCallback) {
-
- MongoPersistentEntity> entity = mappingContext.getPersistentEntity(entityClass);
+ DBObject mappedFields = fields == null ? null : queryMapper.getMappedObject(fields, entity);
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug(String.format("find using query: %s fields: %s for class: %s in collection: %s",
- serializeToJsonSafely(query), fields, entityClass, collectionName));
+ LOGGER.debug(String.format("findOne using query: %s fields: %s for class: %s in collection: %s",
+ serializeToJsonSafely(query), mappedFields, entityClass, collectionName));
}
- return executeFindMultiInternal(new FindCallback(queryMapper.getMappedObject(query, entity), fields), preparer,
- objectCallback, collectionName);
+ return executeFindOneInternal(new FindOneCallback(mappedQuery, mappedFields), new ReadDbObjectCallback(
+ this.mongoConverter, entityClass), collectionName);
}
/**
@@ -1380,14 +1351,43 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* @return the List of converted objects.
*/
protected List doFind(String collectionName, DBObject query, DBObject fields, Class entityClass) {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("find using query: " + query + " fields: " + fields + " for class: " + entityClass
- + " in collection: " + collectionName);
- }
- EntityReader super T, DBObject> readerToUse = this.mongoConverter;
+ return doFind(collectionName, query, fields, entityClass, null, new ReadDbObjectCallback(this.mongoConverter,
+ entityClass));
+ }
+
+ /**
+ * Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. The object is
+ * converted from the MongoDB native representation using an instance of {@see MongoConverter}. The query document is
+ * specified as a standard DBObject and so is the fields specification.
+ *
+ * @param collectionName name of the collection to retrieve the objects from.
+ * @param query the query document that specifies the criteria used to find a record.
+ * @param fields the document that specifies the fields to be returned.
+ * @param entityClass the parameterized type of the returned list.
+ * @param preparer allows for customization of the {@link DBCursor} used when iterating over the result set, (apply
+ * limits, skips and so on).
+ * @return the {@link List} of converted objects.
+ */
+ protected List doFind(String collectionName, DBObject query, DBObject fields, Class entityClass,
+ CursorPreparer preparer) {
+ return doFind(collectionName, query, fields, entityClass, preparer, new ReadDbObjectCallback(mongoConverter,
+ entityClass));
+ }
+
+ protected List doFind(String collectionName, DBObject query, DBObject fields, Class entityClass,
+ CursorPreparer preparer, DbObjectCallback objectCallback) {
+
MongoPersistentEntity> entity = mappingContext.getPersistentEntity(entityClass);
- return executeFindMultiInternal(new FindCallback(queryMapper.getMappedObject(query, entity), fields), null,
- new ReadDbObjectCallback(readerToUse, entityClass), collectionName);
+ DBObject mappedFields = fields == null ? null : queryMapper.getMappedObject(fields, entity);
+ DBObject mappedQuery = queryMapper.getMappedObject(query, entity);
+
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug(String.format("find using query: %s fields: %s for class: %s in collection: %s",
+ serializeToJsonSafely(query), mappedFields, entityClass, collectionName));
+ }
+
+ return executeFindMultiInternal(new FindCallback(mappedQuery, mappedFields), preparer, objectCallback,
+ collectionName);
}
protected DBObject convertToDbObject(CollectionOptions collectionOptions) {
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 287f339e0..f2673e7d1 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
@@ -154,6 +154,8 @@ public class MongoTemplateTests {
template.dropCollection("collection");
template.dropCollection("personX");
template.dropCollection(Document.class);
+ template.dropCollection(ObjectWith3AliasedFields.class);
+ template.dropCollection(ObjectWith3AliasedFieldsAndNestedAddress.class);
}
@Test
@@ -1706,6 +1708,141 @@ public class MongoTemplateTests {
assertThat(result.model.value(), is(newModelValue));
}
+ /**
+ * @see DATAMONGO-702
+ */
+ @Test
+ public void queryShouldSupportRealAndAliasedPropertyNamesForFieldInclusions() {
+
+ ObjectWith3AliasedFields obj = new ObjectWith3AliasedFields();
+ obj.id = "4711";
+ obj.property1 = "P1";
+ obj.property2 = "P2";
+ obj.property3 = "P3";
+
+ template.insert(obj);
+
+ Query query = new Query(Criteria.where("id").is(obj.id));
+ query.fields() //
+ .include("property2") // real property name
+ .include("prop3"); // aliased property name
+
+ ObjectWith3AliasedFields result = template.findOne(query, ObjectWith3AliasedFields.class);
+
+ assertThat(result.id, is(obj.id));
+ assertThat(result.property1, is(nullValue()));
+ assertThat(result.property2, is(obj.property2));
+ assertThat(result.property3, is(obj.property3));
+ }
+
+ /**
+ * @see DATAMONGO-702
+ */
+ @Test
+ public void queryShouldSupportRealAndAliasedPropertyNamesForFieldExclusions() {
+
+ ObjectWith3AliasedFields obj = new ObjectWith3AliasedFields();
+ obj.id = "4711";
+ obj.property1 = "P1";
+ obj.property2 = "P2";
+ obj.property3 = "P3";
+
+ template.insert(obj);
+
+ Query query = new Query(Criteria.where("id").is(obj.id));
+ query.fields() //
+ .exclude("property2") // real property name
+ .exclude("prop3"); // aliased property name
+
+ ObjectWith3AliasedFields result = template.findOne(query, ObjectWith3AliasedFields.class);
+
+ assertThat(result.id, is(obj.id));
+ assertThat(result.property1, is(obj.property1));
+ assertThat(result.property2, is(nullValue()));
+ assertThat(result.property3, is(nullValue()));
+ }
+
+ /**
+ * @see DATAMONGO-702
+ */
+ @Test
+ public void findMultipleWithQueryShouldSupportRealAndAliasedPropertyNamesForFieldExclusions() {
+
+ ObjectWith3AliasedFields obj0 = new ObjectWith3AliasedFields();
+ obj0.id = "4711";
+ obj0.property1 = "P10";
+ obj0.property2 = "P20";
+ obj0.property3 = "P30";
+ ObjectWith3AliasedFields obj1 = new ObjectWith3AliasedFields();
+ obj1.id = "4712";
+ obj1.property1 = "P11";
+ obj1.property2 = "P21";
+ obj1.property3 = "P31";
+
+ template.insert(obj0);
+ template.insert(obj1);
+
+ Query query = new Query(Criteria.where("id").in(obj0.id, obj1.id));
+ query.fields() //
+ .exclude("property2") // real property name
+ .exclude("prop3"); // aliased property name
+
+ List results = template.find(query, ObjectWith3AliasedFields.class);
+
+ assertThat(results, is(notNullValue()));
+ assertThat(results.size(), is(2));
+
+ ObjectWith3AliasedFields result0 = results.get(0);
+ assertThat(result0, is(notNullValue()));
+ assertThat(result0.id, is(obj0.id));
+ assertThat(result0.property1, is(obj0.property1));
+ assertThat(result0.property2, is(nullValue()));
+ assertThat(result0.property3, is(nullValue()));
+
+ ObjectWith3AliasedFields result1 = results.get(1);
+ assertThat(result1, is(notNullValue()));
+ assertThat(result1.id, is(obj1.id));
+ assertThat(result1.property1, is(obj1.property1));
+ assertThat(result1.property2, is(nullValue()));
+ assertThat(result1.property3, is(nullValue()));
+ }
+
+ /**
+ * @see DATAMONGO-702
+ */
+ @Test
+ public void queryShouldSupportNestedPropertyNamesForFieldInclusions() {
+
+ ObjectWith3AliasedFieldsAndNestedAddress obj = new ObjectWith3AliasedFieldsAndNestedAddress();
+ obj.id = "4711";
+ obj.property1 = "P1";
+ obj.property2 = "P2";
+ obj.property3 = "P3";
+ Address address = new Address();
+ String stateValue = "WA";
+ address.state = stateValue;
+ address.city = "Washington";
+ obj.address = address;
+
+ template.insert(obj);
+
+ Query query = new Query(Criteria.where("id").is(obj.id));
+ query.fields() //
+ .include("property2") // real property name
+ .include("address.state"); // aliased property name
+
+ ObjectWith3AliasedFieldsAndNestedAddress result = template.findOne(query,
+ ObjectWith3AliasedFieldsAndNestedAddress.class);
+
+ assertThat(result.id, is(obj.id));
+ assertThat(result.property1, is(nullValue()));
+ assertThat(result.property2, is(obj.property2));
+ assertThat(result.property3, is(nullValue()));
+ assertThat(result.address, is(notNullValue()));
+ assertThat(result.address.city, is(nullValue()));
+ assertThat(result.address.state, is(stateValue));
+ }
+
static interface Model {
String value();
@@ -1819,4 +1956,16 @@ public class MongoTemplateTests {
@Id String id;
Date date;
}
+
+ static class ObjectWith3AliasedFields {
+
+ @Id String id;
+ @Field("prop1") String property1;
+ @Field("prop2") String property2;
+ @Field("prop3") String property3;
+ }
+
+ static class ObjectWith3AliasedFieldsAndNestedAddress extends ObjectWith3AliasedFields {
+ @Field("adr") Address address;
+ }
}