DATAMONGO-2323 - Fix query(…) and stream(…) to be used with BSON Document.

MongoTemplate.stream(…), MongoTemplate.query(…) and ReactiveMongoTemplate.query(…) now no longer fail when used with BSON Document.class.

Previously, field mapping failed because it required an entity type. Now we gracefully back off when find methods are used with a simple Document entity type.
This commit is contained in:
Mark Paluch
2019-07-17 14:28:11 +02:00
parent 387348b615
commit 46de82fe0b
5 changed files with 41 additions and 21 deletions

View File

@@ -376,8 +376,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
* @see org.springframework.data.mongodb.core.MongoOperations#executeAsStream(org.springframework.data.mongodb.core.query.Query, java.lang.Class) * @see org.springframework.data.mongodb.core.MongoOperations#executeAsStream(org.springframework.data.mongodb.core.query.Query, java.lang.Class)
*/ */
@Override @Override
public <T> CloseableIterator<T> stream(final Query query, final Class<T> entityType) { public <T> CloseableIterator<T> stream(Query query, Class<T> entityType) {
return stream(query, entityType, getCollectionName(entityType)); return stream(query, entityType, getCollectionName(entityType));
} }
@@ -386,11 +385,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
* @see org.springframework.data.mongodb.core.MongoOperations#stream(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String) * @see org.springframework.data.mongodb.core.MongoOperations#stream(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
*/ */
@Override @Override
public <T> CloseableIterator<T> stream(final Query query, final Class<T> entityType, final String collectionName) { public <T> CloseableIterator<T> stream(Query query, Class<T> entityType, String collectionName) {
return doStream(query, entityType, collectionName, entityType); return doStream(query, entityType, collectionName, entityType);
} }
protected <T> CloseableIterator<T> doStream(final Query query, final Class<?> entityType, final String collectionName, protected <T> CloseableIterator<T> doStream(Query query, final Class<?> entityType, String collectionName,
Class<T> returnType) { Class<T> returnType) {
Assert.notNull(query, "Query must not be null!"); Assert.notNull(query, "Query must not be null!");
@@ -404,7 +403,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
public CloseableIterator<T> doInCollection(MongoCollection<Document> collection) public CloseableIterator<T> doInCollection(MongoCollection<Document> collection)
throws MongoException, DataAccessException { throws MongoException, DataAccessException {
MongoPersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(entityType); MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityType);
Document mappedFields = getMappedFieldsObject(query.getFieldsObject(), persistentEntity, returnType); Document mappedFields = getMappedFieldsObject(query.getFieldsObject(), persistentEntity, returnType);
Document mappedQuery = queryMapper.getMappedObject(query.getQueryObject(), persistentEntity); Document mappedQuery = queryMapper.getMappedObject(query.getQueryObject(), persistentEntity);
@@ -2419,7 +2418,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
<S, T> List<T> doFind(String collectionName, Document query, Document fields, Class<S> sourceClass, <S, T> List<T> doFind(String collectionName, Document query, Document fields, Class<S> sourceClass,
Class<T> targetClass, CursorPreparer preparer) { Class<T> targetClass, CursorPreparer preparer) {
MongoPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(sourceClass); MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(sourceClass);
Document mappedFields = getMappedFieldsObject(fields, entity, targetClass); Document mappedFields = getMappedFieldsObject(fields, entity, targetClass);
Document mappedQuery = queryMapper.getMappedObject(query, entity); Document mappedQuery = queryMapper.getMappedObject(query, entity);
@@ -2754,7 +2753,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return queryMapper.getMappedSort(query.getSortObject(), mappingContext.getPersistentEntity(type)); return queryMapper.getMappedSort(query.getSortObject(), mappingContext.getPersistentEntity(type));
} }
private Document getMappedFieldsObject(Document fields, MongoPersistentEntity<?> entity, Class<?> targetType) { private Document getMappedFieldsObject(Document fields, @Nullable MongoPersistentEntity<?> entity,
Class<?> targetType) {
if (entity == null) {
return fields;
}
Document projectedFields = propertyOperations.computeFieldsForProjection(projectionFactory, fields, Document projectedFields = propertyOperations.computeFieldsForProjection(projectionFactory, fields,
entity.getType(), targetType); entity.getType(), targetType);

View File

@@ -375,8 +375,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @see org.springframework.data.mongodb.core.ReactiveMongoOperations#reactiveIndexOps(java.lang.Class) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#reactiveIndexOps(java.lang.Class)
*/ */
public ReactiveIndexOperations indexOps(Class<?> entityClass) { public ReactiveIndexOperations indexOps(Class<?> entityClass) {
return new DefaultReactiveIndexOperations(this, getCollectionName(entityClass), this.queryMapper, return new DefaultReactiveIndexOperations(this, getCollectionName(entityClass), this.queryMapper, entityClass);
entityClass);
} }
public String getCollectionName(Class<?> entityClass) { public String getCollectionName(Class<?> entityClass) {
@@ -615,8 +614,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
*/ */
public <T> Mono<MongoCollection<Document>> createCollection(Class<T> entityClass, public <T> Mono<MongoCollection<Document>> createCollection(Class<T> entityClass,
@Nullable CollectionOptions collectionOptions) { @Nullable CollectionOptions collectionOptions) {
return doCreateCollection(getCollectionName(entityClass), return doCreateCollection(getCollectionName(entityClass), convertToCreateCollectionOptions(collectionOptions, entityClass));
convertToCreateCollectionOptions(collectionOptions, entityClass));
} }
/* /*
@@ -1965,8 +1963,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
public <T> Flux<T> mapReduce(Query filterQuery, Class<?> domainType, Class<T> resultType, String mapFunction, public <T> Flux<T> mapReduce(Query filterQuery, Class<?> domainType, Class<T> resultType, String mapFunction,
String reduceFunction, MapReduceOptions options) { String reduceFunction, MapReduceOptions options) {
return mapReduce(filterQuery, domainType, getCollectionName(domainType), resultType, mapFunction, return mapReduce(filterQuery, domainType, getCollectionName(domainType), resultType, mapFunction, reduceFunction,
reduceFunction, options); options);
} }
/* /*
@@ -2255,7 +2253,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
<S, T> Flux<T> doFind(String collectionName, Document query, Document fields, Class<S> sourceClass, <S, T> Flux<T> doFind(String collectionName, Document query, Document fields, Class<S> sourceClass,
Class<T> targetClass, FindPublisherPreparer preparer) { Class<T> targetClass, FindPublisherPreparer preparer) {
MongoPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(sourceClass); MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(sourceClass);
Document mappedFields = getMappedFieldsObject(fields, entity, targetClass); Document mappedFields = getMappedFieldsObject(fields, entity, targetClass);
Document mappedQuery = queryMapper.getMappedObject(query, entity); Document mappedQuery = queryMapper.getMappedObject(query, entity);
@@ -2269,7 +2267,12 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
new ProjectingReadCallback<>(mongoConverter, sourceClass, targetClass, collectionName), collectionName); new ProjectingReadCallback<>(mongoConverter, sourceClass, targetClass, collectionName), collectionName);
} }
private Document getMappedFieldsObject(Document fields, MongoPersistentEntity<?> entity, Class<?> targetType) { private Document getMappedFieldsObject(Document fields, @Nullable MongoPersistentEntity<?> entity,
Class<?> targetType) {
if (entity == null) {
return fields;
}
Document projectedFields = propertyOperations.computeFieldsForProjection(projectionFactory, fields, Document projectedFields = propertyOperations.computeFieldsForProjection(projectionFactory, fields,
entity.getType(), targetType); entity.getType(), targetType);

View File

@@ -147,6 +147,13 @@ public class ExecutableFindOperationSupportTests {
.hasSize(1); .hasSize(1);
} }
@Test // DATAMONGO-2323
public void findAllAsDocument() {
assertThat(
template.query(Document.class).inCollection(STAR_WARS).matching(query(where("firstname").is("luke"))).all())
.hasSize(1);
}
@Test // DATAMONGO-1563 @Test // DATAMONGO-1563
public void findAllByWithProjection() { public void findAllByWithProjection() {

View File

@@ -3346,7 +3346,7 @@ public class MongoTemplateTests {
assertThat(loaded.bigDeciamVal, equalTo(new BigDecimal("800"))); assertThat(loaded.bigDeciamVal, equalTo(new BigDecimal("800")));
} }
@Test // DATAMONGO-1431 @Test // DATAMONGO-1431, DATAMONGO-2323
public void streamExecutionUsesExplicitCollectionName() { public void streamExecutionUsesExplicitCollectionName() {
template.remove(new Query(), "some_special_collection"); template.remove(new Query(), "some_special_collection");
@@ -3357,14 +3357,14 @@ public class MongoTemplateTests {
template.insert(document, "some_special_collection"); template.insert(document, "some_special_collection");
CloseableIterator<Document> stream = template.stream(new Query(), Document.class); CloseableIterator<Document> stream = template.stream(new Query(), Document.class);
assertThat(stream.hasNext(), is(false)); assertThat(stream.hasNext(), is(false));
stream = template.stream(new Query(), Document.class, "some_special_collection"); CloseableIterator<org.bson.Document> stream2 = template.stream(new Query(where("_id").is(document.id)),
org.bson.Document.class, "some_special_collection");
assertThat(stream.hasNext(), is(true)); assertThat(stream2.hasNext()).isTrue();
assertThat(stream.next().id, is(document.id)); assertThat(stream2.next().get("_id")).isEqualTo(new ObjectId(document.id));
assertThat(stream.hasNext(), is(false)); assertThat(stream2.hasNext()).isFalse();
} }
@Test // DATAMONGO-1194 @Test // DATAMONGO-1194

View File

@@ -134,6 +134,12 @@ public class ReactiveFindOperationSupportTests {
StepVerifier.create(template.query(Human.class).inCollection(STAR_WARS).all()).expectNextCount(2).verifyComplete(); StepVerifier.create(template.query(Human.class).inCollection(STAR_WARS).all()).expectNextCount(2).verifyComplete();
} }
@Test // DATAMONGO-2323
public void findAllAsDocumentDocument() {
StepVerifier.create(template.query(Document.class).inCollection(STAR_WARS).all()).expectNextCount(2)
.verifyComplete();
}
@Test // DATAMONGO-1719 @Test // DATAMONGO-1719
public void findAllWithProjection() { public void findAllWithProjection() {