Browse Source

DATAMONGO-1444 - Polishing.

- Update Javadoc comments and reference documentation.
- Introduce Adapter for blocking IndexOperations.
- Remove transaction synchronization.
- Remove unused types.
- Remove dropDupos options from indexes.
- Prevent usage of Querydsl along with reactive repository.
- Use ReactiveQueryMethod in ReactiveMongoQuery.
pull/411/merge
Christoph Strobl 9 years ago committed by Oliver Gierke
parent
commit
e0f371f648
  1. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractReactiveMongoConfiguration.java
  2. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java
  3. 7
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoConfigurationSupport.java
  4. 27
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultIndexOperations.java
  5. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultReactiveIndexOperations.java
  6. 24
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexConverters.java
  7. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexOperations.java
  8. 66
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexOperationsAdapter.java
  9. 3
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexOperationsProvider.java
  10. 5
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveCollectionCallback.java
  11. 5
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveDatabaseCallback.java
  12. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveIndexOperations.java
  13. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoClientFactoryBean.java
  14. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoClientSettingsFactoryBean.java
  15. 88
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoDatabaseHolder.java
  16. 109
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoDbUtils.java
  17. 17
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java
  18. 160
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
  19. 21
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java
  20. 15
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/IndexInfo.java
  21. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java
  22. 1
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/ReactiveMongoRepositoriesRegistrar.java
  23. 11
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/ReactiveMongoRepositoryConfigurationExtension.java
  24. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/RepositoryType.java
  25. 27
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java
  26. 24
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoParameterAccessor.java
  27. 20
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryMethod.java
  28. 16
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactivePartTreeMongoQuery.java
  29. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveStringBasedMongoQuery.java
  30. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/IndexEnsuringQueryCreationListener.java
  31. 16
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactory.java
  32. 39
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveChunk.java
  33. 3
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactory.java
  34. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactoryBean.java
  35. 1
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactivePageImpl.java
  36. 13
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleReactiveMongoRepository.java
  37. 1
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AbstractReactiveMongoConfigurationUnitTests.java
  38. 1
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java
  39. 9
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateExecuteTests.java
  40. 29
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateIndexTests.java
  41. 63
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateTests.java
  42. 2
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/IndexInfoUnitTests.java
  43. 13
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests.java
  44. 165
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/performance/ReactivePerformanceTests.java
  45. 3
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java
  46. 3
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/SimpleReactiveMongoRepositoryTests.java
  47. 3
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/ReactiveStringBasedMongoQueryUnitTests.java
  48. 4
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/ReactivePageImplUnitTests.java
  49. 8
      src/main/asciidoc/reference/reactive-mongo-repositories.adoc
  50. 96
      src/main/asciidoc/reference/reactive-mongodb.adoc

6
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractReactiveMongoConfiguration.java

@ -18,7 +18,9 @@ package org.springframework.data.mongodb.config; @@ -18,7 +18,9 @@ package org.springframework.data.mongodb.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
@ -50,7 +52,7 @@ public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurat @@ -50,7 +52,7 @@ public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurat
* @return
*/
@Bean
public ReactiveMongoTemplate reactiveMongoTemplate() throws Exception {
public ReactiveMongoOperations reactiveMongoTemplate() throws Exception {
return new ReactiveMongoTemplate(mongoDbFactory(), mappingMongoConverter());
}
@ -64,7 +66,7 @@ public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurat @@ -64,7 +66,7 @@ public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurat
* @throws Exception
*/
@Bean
public SimpleReactiveMongoDatabaseFactory mongoDbFactory() {
public ReactiveMongoDatabaseFactory mongoDbFactory() {
return new SimpleReactiveMongoDatabaseFactory(mongoClient(), getDatabaseName());
}

8
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2011-2014 the original author or authors.
* Copyright 2011-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -73,6 +73,7 @@ import org.w3c.dom.Element; @@ -73,6 +73,7 @@ import org.w3c.dom.Element;
* @author Maciej Walkowiak
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
*/
public class MappingMongoConverterParser implements BeanDefinitionParser {
@ -121,6 +122,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser { @@ -121,6 +122,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
}
if(!registry.containsBeanDefinition("indexOperationsProvider")){
BeanDefinitionBuilder indexOperationsProviderBuilder = BeanDefinitionBuilder.genericBeanDefinition("org.springframework.data.mongodb.core.DefaultIndexOperationsProvider");
indexOperationsProviderBuilder.addConstructorArgReference(dbFactoryRef);
parserContext.registerBeanComponent(new BeanComponentDefinition(indexOperationsProviderBuilder.getBeanDefinition(), "indexOperationsProvider"));
@ -129,9 +131,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser { @@ -129,9 +131,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
try {
registry.getBeanDefinition(INDEX_HELPER_BEAN_NAME);
} catch (NoSuchBeanDefinitionException ignored) {
if (!StringUtils.hasText(dbFactoryRef)) {
dbFactoryRef = DB_FACTORY_BEAN_NAME;
}
BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
indexHelperBuilder.addConstructorArgReference(ctxRef);

7
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoConfigurationSupport.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
package org.springframework.data.mongodb.config;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@ -28,7 +29,9 @@ import org.springframework.core.convert.converter.Converter; @@ -28,7 +29,9 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
import org.springframework.data.mapping.model.FieldNamingStrategy;
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
@ -106,7 +109,9 @@ public abstract class MongoConfigurationSupport { @@ -106,7 +109,9 @@ public abstract class MongoConfigurationSupport {
*/
@Bean
public IsNewStrategyFactory isNewStrategyFactory() throws ClassNotFoundException {
return new CachingIsNewStrategyFactory(new MappingContextIsNewStrategyFactory(mongoMappingContext()));
return new CachingIsNewStrategyFactory(new MappingContextIsNewStrategyFactory(
new PersistentEntities(Arrays.<MappingContext<?, ?>> asList(new MappingContext[] { mongoMappingContext() }))));
}
/**

27
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultIndexOperations.java

@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import static org.springframework.data.mongodb.core.MongoTemplate.potentiallyConvertRuntimeException;
import static org.springframework.data.mongodb.core.MongoTemplate.*;
import java.util.ArrayList;
import java.util.List;
@ -65,19 +65,18 @@ public class DefaultIndexOperations implements IndexOperations { @@ -65,19 +65,18 @@ public class DefaultIndexOperations implements IndexOperations {
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.IndexOperations#ensureIndex(org.springframework.data.mongodb.core.index.IndexDefinition)
*/
public void ensureIndex(final IndexDefinition indexDefinition) {
execute(collection -> {
public String ensureIndex(final IndexDefinition indexDefinition) {
return execute(collection -> {
Document indexOptions = indexDefinition.getIndexOptions();
if (indexOptions != null) {
IndexOptions ops = IndexConverters.DEFINITION_TO_MONGO_INDEX_OPTIONS.convert(indexDefinition);
collection.createIndex(indexDefinition.getIndexKeys(), ops);
} else {
collection.createIndex(indexDefinition.getIndexKeys());
IndexOptions ops = IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition);
return collection.createIndex(indexDefinition.getIndexKeys(), ops);
}
return null;
return collection.createIndex(indexDefinition.getIndexKeys());
});
}
@ -86,11 +85,10 @@ public class DefaultIndexOperations implements IndexOperations { @@ -86,11 +85,10 @@ public class DefaultIndexOperations implements IndexOperations {
* @see org.springframework.data.mongodb.core.IndexOperations#dropIndex(java.lang.String)
*/
public void dropIndex(final String name) {
execute(new CollectionCallback<Void>() {
public Void doInCollection(MongoCollection<Document> collection) throws MongoException, DataAccessException {
collection.dropIndex(name);
return null;
}
execute(collection -> {
collection.dropIndex(name);
return null;
});
}
@ -110,6 +108,7 @@ public class DefaultIndexOperations implements IndexOperations { @@ -110,6 +108,7 @@ public class DefaultIndexOperations implements IndexOperations {
public List<IndexInfo> getIndexInfo() {
return execute(new CollectionCallback<List<IndexInfo>>() {
public List<IndexInfo> doInCollection(MongoCollection<Document> collection)
throws MongoException, DataAccessException {
@ -124,7 +123,7 @@ public class DefaultIndexOperations implements IndexOperations { @@ -124,7 +123,7 @@ public class DefaultIndexOperations implements IndexOperations {
while (cursor.hasNext()) {
Document ix = cursor.next();
IndexInfo indexInfo = IndexConverters.DOCUMENT_INDEX_INFO.convert(ix);
IndexInfo indexInfo = IndexConverters.documentToIndexInfoConverter().convert(ix);
indexInfoList.add(indexInfo);
}

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultReactiveIndexOperations.java

@ -62,7 +62,7 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations { @@ -62,7 +62,7 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
if (indexOptions != null) {
return collection.createIndex(indexDefinition.getIndexKeys(),
IndexConverters.DEFINITION_TO_MONGO_INDEX_OPTIONS.convert(indexDefinition));
IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition));
}
return collection.createIndex(indexDefinition.getIndexKeys());
@ -96,7 +96,7 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations { @@ -96,7 +96,7 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
ListIndexesPublisher<Document> indexesPublisher = collection.listIndexes(Document.class);
return Flux.from(indexesPublisher).map(t -> IndexConverters.DOCUMENT_INDEX_INFO.convert(t));
return Flux.from(indexesPublisher).map(IndexConverters.documentToIndexInfoConverter()::convert);
});
}
}

24
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexConverters.java

@ -37,12 +37,13 @@ import com.mongodb.client.model.IndexOptions; @@ -37,12 +37,13 @@ import com.mongodb.client.model.IndexOptions;
* {@link Converter Converters} for index-related MongoDB documents/types.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
abstract class IndexConverters {
public final static Converter<IndexDefinition, IndexOptions> DEFINITION_TO_MONGO_INDEX_OPTIONS;
public final static Converter<Document, IndexInfo> DOCUMENT_INDEX_INFO;
private static final Converter<IndexDefinition, IndexOptions> DEFINITION_TO_MONGO_INDEX_OPTIONS;
private static final Converter<Document, IndexInfo> DOCUMENT_INDEX_INFO;
private static final Double ONE = Double.valueOf(1);
private static final Double MINUS_ONE = Double.valueOf(-1);
@ -58,6 +59,14 @@ abstract class IndexConverters { @@ -58,6 +59,14 @@ abstract class IndexConverters {
}
static Converter<IndexDefinition, IndexOptions> indexDefinitionToIndexOptionsConverter() {
return DEFINITION_TO_MONGO_INDEX_OPTIONS;
}
static Converter<Document, IndexInfo> documentToIndexInfoConverter() {
return DOCUMENT_INDEX_INFO;
}
private static Converter<IndexDefinition, IndexOptions> getIndexDefinitionIndexOptionsConverter() {
return indexDefinition -> {
@ -115,14 +124,14 @@ abstract class IndexConverters { @@ -115,14 +124,14 @@ abstract class IndexConverters {
private static Converter<Document, IndexInfo> getDocumentIndexInfoConverter() {
return ix -> {
Document keyDbObject = (Document) ix.get("key");
int numberOfElements = keyDbObject.keySet().size();
Document keyDocument = (Document) ix.get("key");
int numberOfElements = keyDocument.keySet().size();
List<IndexField> indexFields = new ArrayList<IndexField>(numberOfElements);
for (String key : keyDbObject.keySet()) {
for (String key : keyDocument.keySet()) {
Object value = keyDbObject.get(key);
Object value = keyDocument.get(key);
if (TWO_D_IDENTIFIERS.contains(value)) {
indexFields.add(IndexField.geo(key));
@ -148,11 +157,10 @@ abstract class IndexConverters { @@ -148,11 +157,10 @@ abstract class IndexConverters {
String name = ix.get("name").toString();
boolean unique = ix.containsKey("unique") ? (Boolean) ix.get("unique") : false;
boolean dropDuplicates = ix.containsKey("dropDups") ? (Boolean) ix.get("dropDups") : false;
boolean sparse = ix.containsKey("sparse") ? (Boolean) ix.get("sparse") : false;
String language = ix.containsKey("default_language") ? (String) ix.get("default_language") : "";
return new IndexInfo(indexFields, name, unique, dropDuplicates, sparse, language);
return new IndexInfo(indexFields, name, unique, sparse, language);
};
}
}

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexOperations.java

@ -35,7 +35,7 @@ public interface IndexOperations { @@ -35,7 +35,7 @@ public interface IndexOperations {
*
* @param indexDefinition must not be {@literal null}.
*/
void ensureIndex(IndexDefinition indexDefinition);
String ensureIndex(IndexDefinition indexDefinition);
/**
* Drops an index from this collection.

66
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexOperationsAdapter.java

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
/*
* Copyright 2016. the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import java.util.List;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.util.Assert;
/**
* Adapter for creating synchronous {@link IndexOperations}.
*
* @author Christoph Strobl
* @since 2.0
*/
public interface IndexOperationsAdapter extends IndexOperations {
/**
* Obtain a blocking variant of {@link IndexOperations} wrapping {@link ReactiveIndexOperations}.
*
* @param reactiveIndexOperations must not be {@literal null}.
* @return never {@literal null}
*/
static IndexOperationsAdapter blocking(ReactiveIndexOperations reactiveIndexOperations) {
Assert.notNull(reactiveIndexOperations, "ReactiveIndexOperations must not be null!");
return new IndexOperationsAdapter() {
@Override
public String ensureIndex(IndexDefinition indexDefinition) {
return reactiveIndexOperations.ensureIndex(indexDefinition).block();
}
@Override
public void dropIndex(String name) {
reactiveIndexOperations.dropIndex(name).block();
}
@Override
public void dropAllIndexes() {
reactiveIndexOperations.dropAllIndexes().block();
}
@Override
public List<IndexInfo> getIndexInfo() {
return reactiveIndexOperations.getIndexInfo().collectList().block();
}
};
}
}

3
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexOperationsProvider.java

@ -16,11 +16,10 @@ @@ -16,11 +16,10 @@
package org.springframework.data.mongodb.core;
import org.springframework.dao.support.PersistenceExceptionTranslator;
/**
* TODO: Revisit for a better pattern.
* @author Mark Paluch
* @since 2.0
*/
public interface IndexOperationsProvider {

5
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveCollectionCallback.java

@ -22,6 +22,11 @@ import com.mongodb.reactivestreams.client.MongoCollection; @@ -22,6 +22,11 @@ import com.mongodb.reactivestreams.client.MongoCollection;
import org.bson.Document;
import org.reactivestreams.Publisher;
/**
* @author Mark Paluch
* @param <T>
* @since 2.0
*/
public interface ReactiveCollectionCallback<T> {
Publisher<T> doInCollection(MongoCollection<Document> collection) throws MongoException, DataAccessException;

5
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveDatabaseCallback.java

@ -21,6 +21,11 @@ import com.mongodb.MongoException; @@ -21,6 +21,11 @@ import com.mongodb.MongoException;
import com.mongodb.reactivestreams.client.MongoDatabase;
import org.reactivestreams.Publisher;
/**
* @author Mark Paluch
* @param <T>
* @since 2.0
*/
public interface ReactiveDatabaseCallback<T> {
Publisher<T> doInDB(MongoDatabase db) throws MongoException, DataAccessException;

6
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveIndexOperations.java

@ -15,6 +15,8 @@ @@ -15,6 +15,8 @@
*/
package org.springframework.data.mongodb.core;
import java.util.List;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
@ -25,7 +27,8 @@ import reactor.core.publisher.Mono; @@ -25,7 +27,8 @@ import reactor.core.publisher.Mono;
* Index operations on a collection.
*
* @author Mark Paluch
* @since 1.11
* @author Christoph Strobl
* @since 2.0
*/
public interface ReactiveIndexOperations {
@ -55,4 +58,5 @@ public interface ReactiveIndexOperations { @@ -55,4 +58,5 @@ public interface ReactiveIndexOperations {
* @return index information on the collection
*/
Flux<IndexInfo> getIndexInfo();
}

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoClientFactoryBean.java

@ -29,6 +29,8 @@ import com.mongodb.reactivestreams.client.MongoClients; @@ -29,6 +29,8 @@ import com.mongodb.reactivestreams.client.MongoClients;
* Convenient factory for configuring a reactive streams {@link MongoClient}.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public class ReactiveMongoClientFactoryBean extends AbstractFactoryBean<MongoClient>
implements PersistenceExceptionTranslator {
@ -122,6 +124,6 @@ public class ReactiveMongoClientFactoryBean extends AbstractFactoryBean<MongoCli @@ -122,6 +124,6 @@ public class ReactiveMongoClientFactoryBean extends AbstractFactoryBean<MongoCli
@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return DEFAULT_EXCEPTION_TRANSLATOR.translateExceptionIfPossible(ex);
return exceptionTranslator.translateExceptionIfPossible(ex);
}
}

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoClientSettingsFactoryBean.java

@ -38,7 +38,7 @@ import com.mongodb.connection.StreamFactoryFactory; @@ -38,7 +38,7 @@ import com.mongodb.connection.StreamFactoryFactory;
* A factory bean for construction of a {@link MongoClientSettings} instance to be used with the async MongoDB driver.
*
* @author Mark Paluch
* @since 1.7
* @since 2.0
*/
public class ReactiveMongoClientSettingsFactoryBean extends AbstractFactoryBean<MongoClientSettings> {

88
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoDatabaseHolder.java

@ -1,88 +0,0 @@ @@ -1,88 +0,0 @@
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import com.mongodb.reactivestreams.client.MongoDatabase;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.util.Assert;
/**
* @author Mark Paluch
*/
class ReactiveMongoDatabaseHolder extends ResourceHolderSupport {
private static final Object DEFAULT_KEY = new Object();
private final Map<Object, MongoDatabase> dbMap = new ConcurrentHashMap<Object, MongoDatabase>();
public ReactiveMongoDatabaseHolder(MongoDatabase db) {
addMongoDatabase(db);
}
public ReactiveMongoDatabaseHolder(Object key, MongoDatabase db) {
addMongoDatabase(key, db);
}
public MongoDatabase getMongoDatabase() {
return getMongoDatabase(DEFAULT_KEY);
}
public MongoDatabase getMongoDatabase(Object key) {
return this.dbMap.get(key);
}
public MongoDatabase getAnyMongoDatabase() {
if (!this.dbMap.isEmpty()) {
return this.dbMap.values().iterator().next();
}
return null;
}
public void addMongoDatabase(MongoDatabase session) {
addMongoDatabase(DEFAULT_KEY, session);
}
public void addMongoDatabase(Object key, MongoDatabase session) {
Assert.notNull(key, "Key must not be null");
Assert.notNull(session, "DB must not be null");
this.dbMap.put(key, session);
}
public MongoDatabase removeMongoDatabase(Object key) {
return this.dbMap.remove(key);
}
public boolean containsMongoDatabase(MongoDatabase session) {
return this.dbMap.containsValue(session);
}
public boolean isEmpty() {
return this.dbMap.isEmpty();
}
public boolean doesNotHoldNonDefaultMongoDatabase() {
synchronized (this.dbMap) {
return this.dbMap.isEmpty() || (this.dbMap.size() == 1 && this.dbMap.containsKey(DEFAULT_KEY));
}
}
}

109
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoDbUtils.java

@ -17,24 +17,17 @@ package org.springframework.data.mongodb.core; @@ -17,24 +17,17 @@ package org.springframework.data.mongodb.core;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoDatabase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mongodb.util.MongoClientVersion;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Helper class featuring helper methods for internal MongoDb classes. Mainly intended for internal use within the
* framework.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public abstract class ReactiveMongoDbUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(ReactiveMongoDbUtils.class);
/**
* Private constructor to prevent instantiation.
*/
@ -48,103 +41,11 @@ public abstract class ReactiveMongoDbUtils { @@ -48,103 +41,11 @@ public abstract class ReactiveMongoDbUtils {
* @return the {@link MongoDatabase} connection
*/
public static MongoDatabase getMongoDatabase(MongoClient mongo, String databaseName) {
return doGetMongoDatabase(mongo, databaseName, UserCredentials.NO_CREDENTIALS, true, databaseName);
}
private static MongoDatabase doGetMongoDatabase(MongoClient mongo, String databaseName, UserCredentials credentials,
boolean allowCreate, String authenticationDatabaseName) {
ReactiveMongoDatabaseHolder dbHolder = (ReactiveMongoDatabaseHolder) TransactionSynchronizationManager
.getResource(mongo);
// Do we have a populated holder and TX sync active?
if (dbHolder != null && !dbHolder.isEmpty() && TransactionSynchronizationManager.isSynchronizationActive()) {
MongoDatabase db = dbHolder.getMongoDatabase(databaseName);
// DB found but not yet synchronized
if (db != null && !dbHolder.isSynchronizedWithTransaction()) {
LOGGER.debug("Registering Spring transaction synchronization for existing MongoDB {}.", databaseName);
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(dbHolder, mongo));
dbHolder.setSynchronizedWithTransaction(true);
}
if (db != null) {
return db;
}
}
// Lookup fresh database instance
LOGGER.debug("Getting Mongo Database name=[{}]", databaseName);
MongoDatabase db = mongo.getDatabase(databaseName);
// TX sync active, bind new database to thread
if (TransactionSynchronizationManager.isSynchronizationActive()) {
LOGGER.debug("Registering Spring transaction synchronization for MongoDB instance {}.", databaseName);
ReactiveMongoDatabaseHolder holderToUse = dbHolder;
if (holderToUse == null) {
holderToUse = new ReactiveMongoDatabaseHolder(databaseName, db);
} else {
holderToUse.addMongoDatabase(databaseName, db);
}
// synchronize holder only if not yet synchronized
if (!holderToUse.isSynchronizedWithTransaction()) {
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo));
holderToUse.setSynchronizedWithTransaction(true);
}
if (holderToUse != dbHolder) {
TransactionSynchronizationManager.bindResource(mongo, holderToUse);
}
}
// Check whether we are allowed to return the DB.
if (!allowCreate && !isDBTransactional(db, mongo)) {
throw new IllegalStateException(
"No Mongo DB bound to thread, " + "and configuration does not allow creation of non-transactional one here");
}
return db;
return doGetMongoDatabase(mongo, databaseName, true);
}
/**
* Return whether the given DB instance is transactional, that is, bound to the current thread by Spring's transaction
* facilities.
*
* @param db the DB to check
* @param mongoClient the Mongo instance that the DB was created with (may be <code>null</code>)
* @return whether the DB is transactional
*/
public static boolean isDBTransactional(MongoDatabase db, MongoClient mongoClient) {
if (mongoClient == null) {
return false;
}
ReactiveMongoDatabaseHolder dbHolder = (ReactiveMongoDatabaseHolder) TransactionSynchronizationManager
.getResource(mongoClient);
return dbHolder != null && dbHolder.containsMongoDatabase(db);
private static MongoDatabase doGetMongoDatabase(MongoClient mongo, String databaseName, boolean allowCreate) {
return mongo.getDatabase(databaseName);
}
/**
* Check if credentials present. In case we're using a mongo-java-driver version 3 or above we do not have the need
* for authentication as the auth data has to be provided within the MongoClient
*
* @param credentials
* @return
*/
private static boolean requiresAuthDbAuthentication(UserCredentials credentials) {
if (credentials == null || !credentials.hasUsername()) {
return false;
}
return !MongoClientVersion.isMongo3Driver();
}
}

17
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java

@ -21,7 +21,6 @@ import org.bson.Document; @@ -21,7 +21,6 @@ import org.bson.Document;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.query.BasicQuery;
@ -46,6 +45,7 @@ import reactor.core.publisher.Mono; @@ -46,6 +45,7 @@ import reactor.core.publisher.Mono;
* {@link ReactiveMongoOperations} is deferred until subscriber subscribes to the {@link Publisher}.
*
* @author Mark Paluch
* @author Christoph Strobl
* @see Flux
* @see Mono
* @see http://projectreactor.io/docs/
@ -67,20 +67,6 @@ public interface ReactiveMongoOperations { @@ -67,20 +67,6 @@ public interface ReactiveMongoOperations {
*/
ReactiveIndexOperations reactiveIndexOps(Class<?> entityClass);
/**
* Returns the operations that can be performed on indexes
*
* @return index operations on the named collection
*/
IndexOperations indexOps(String collectionName);
/**
* Returns the operations that can be performed on indexes
*
* @return index operations on the named collection associated with the given entity class
*/
IndexOperations indexOps(Class<?> entityClass);
/**
* Execute the a MongoDB command expressed as a JSON string. This will call the method JSON.parse that is part of the
* MongoDB driver to convert the JSON string to a DBObject. Any errors that result from executing this command will be
@ -955,4 +941,5 @@ public interface ReactiveMongoOperations { @@ -955,4 +941,5 @@ public interface ReactiveMongoOperations {
* @return
*/
MongoConverter getConverter();
}

160
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java

@ -60,7 +60,6 @@ import org.springframework.data.mapping.model.ConvertingPropertyAccessor; @@ -60,7 +60,6 @@ import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate.DocumentCallback;
import org.springframework.data.mongodb.core.convert.DbRefProxyHandler;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DbRefResolverCallback;
@ -69,8 +68,6 @@ import org.springframework.data.mongodb.core.convert.MongoConverter; @@ -69,8 +68,6 @@ import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.convert.MongoWriter;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.convert.UpdateMapper;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.index.MongoMappingEventPublisher;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
@ -128,11 +125,12 @@ import reactor.util.function.Tuple2; @@ -128,11 +125,12 @@ import reactor.util.function.Tuple2;
* extract results. This class executes BSON queries or updates, initiating iteration over {@link FindPublisher} and
* catching MongoDB exceptions and translating them to the generic, more informative exception hierarchy defined in the
* org.springframework.dao package. Can be used within a service implementation via direct instantiation with a
* {@link SimpleReactiveMongoDatabaseFactory} reference, or get prepared in an application context and given to services as
* bean reference. Note: The {@link SimpleReactiveMongoDatabaseFactory} should always be configured as a bean in the
* {@link SimpleReactiveMongoDatabaseFactory} reference, or get prepared in an application context and given to services
* as bean reference. Note: The {@link SimpleReactiveMongoDatabaseFactory} should always be configured as a bean in the
* application context, in the first case given to the service directly, in the second case to the prepared template.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public class ReactiveMongoTemplate implements ReactiveMongoOperations, ApplicationContextAware {
@ -211,7 +209,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -211,7 +209,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
if (null != mappingContext && mappingContext instanceof MongoMappingContext) {
indexCreator = new MongoPersistentEntityIndexCreator((MongoMappingContext) mappingContext,
new BlockingIndexOptionsProvider(this));
(collectionName) -> IndexOperationsAdapter.blocking(reactiveIndexOps(collectionName)));
eventPublisher = new MongoMappingEventPublisher(indexCreator);
if (mappingContext instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher);
@ -329,20 +327,6 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -329,20 +327,6 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return new DefaultReactiveIndexOperations(this, determineCollectionName(entityClass));
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ReactiveMongoOperations#reactiveIndexOps(java.lang.String)
*/
public IndexOperations indexOps(String collectionName) {
return new BlockingIndexOperations(new DefaultReactiveIndexOperations(this, collectionName));
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ReactiveMongoOperations#reactiveIndexOps(java.lang.Class)
*/
public IndexOperations indexOps(Class<?> entityClass) {
return new BlockingIndexOperations(new DefaultReactiveIndexOperations(this, determineCollectionName(entityClass)));
}
public String getCollectionName(Class<?> entityClass) {
return this.determineCollectionName(entityClass);
}
@ -480,7 +464,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -480,7 +464,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @see org.springframework.data.mongodb.core.ReactiveMongoOperations#createCollection(java.lang.Class, org.springframework.data.mongodb.core.CollectionOptions)
*/
public <T> Mono<MongoCollection<Document>> createCollection(Class<T> entityClass,
CollectionOptions collectionOptions) {
CollectionOptions collectionOptions) {
return createCollection(determineCollectionName(entityClass), collectionOptions);
}
@ -495,7 +479,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -495,7 +479,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @see org.springframework.data.mongodb.core.ReactiveMongoOperations#createCollection(java.lang.String, org.springframework.data.mongodb.core.CollectionOptions)
*/
public Mono<MongoCollection<Document>> createCollection(final String collectionName,
final CollectionOptions collectionOptions) {
final CollectionOptions collectionOptions) {
return doCreateCollection(collectionName, convertToCreateCollectionOptions(collectionOptions));
}
@ -730,7 +714,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -730,7 +714,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @see org.springframework.data.mongodb.core.ReactiveMongoOperations#findAndModify(org.springframework.data.mongodb.core.query.Query, org.springframework.data.mongodb.core.query.Update, org.springframework.data.mongodb.core.FindAndModifyOptions, java.lang.Class, java.lang.String)
*/
public <T> Mono<T> findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass,
String collectionName) {
String collectionName) {
return doFindAndModify(collectionName, query.getQueryObject(), query.getFieldsObject(),
getMappedSortObject(query, entityClass), entityClass, update, options);
}
@ -777,7 +761,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -777,7 +761,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
final Document Document = query == null ? null
: queryMapper.getMappedObject(query.getQueryObject(),
entityClass == null ? null : mappingContext.getPersistentEntity(entityClass));
entityClass == null ? null : mappingContext.getPersistentEntity(entityClass));
return collection.count(Document);
});
@ -904,7 +888,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -904,7 +888,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
protected <T> Flux<T> doInsertBatch(final String collectionName, final Collection<? extends T> batchToSave,
final MongoWriter<Object> writer) {
final MongoWriter<Object> writer) {
Assert.notNull(writer);
@ -1094,7 +1078,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1094,7 +1078,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
private MongoCollection<Document> prepareCollection(MongoCollection<Document> collection,
WriteConcern writeConcernToUse) {
WriteConcern writeConcernToUse) {
MongoCollection<Document> collectionToUse = collection;
if (writeConcernToUse != null) {
@ -1194,12 +1178,12 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1194,12 +1178,12 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @see org.springframework.data.mongodb.core.ReactiveMongoOperations#updateMulti(org.springframework.data.mongodb.core.query.Query, org.springframework.data.mongodb.core.query.Update, java.lang.Class, java.lang.String)
*/
public Mono<UpdateResult> updateMulti(final Query query, final Update update, Class<?> entityClass,
String collectionName) {
String collectionName) {
return doUpdate(collectionName, query, update, entityClass, false, true);
}
protected Mono<UpdateResult> doUpdate(final String collectionName, final Query query, final Update update,
final Class<?> entityClass, final boolean upsert, final boolean multi) {
final Class<?> entityClass, final boolean upsert, final boolean multi) {
MongoPersistentEntity<?> entity = entityClass == null ? null : getPersistentEntity(entityClass);
@ -1413,7 +1397,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1413,7 +1397,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
protected <T> Mono<DeleteResult> doRemove(final String collectionName, final Query query,
final Class<T> entityClass) {
final Class<T> entityClass) {
if (query == null) {
throw new InvalidDataAccessApiUsageException("Query passed in to remove can't be null!");
@ -1437,7 +1421,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1437,7 +1421,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Remove using query: {} in collection: {}.",
new Object[]{serializeToJsonSafely(dboq), collectionName});
new Object[] { serializeToJsonSafely(dboq), collectionName });
}
return collectionToUse.deleteMany(dboq);
@ -1534,7 +1518,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1534,7 +1518,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @return the collection that was created
*/
protected Mono<MongoCollection<Document>> doCreateCollection(final String collectionName,
final CreateCollectionOptions collectionOptions) {
final CreateCollectionOptions collectionOptions) {
return createMono(db -> db.createCollection(collectionName, collectionOptions)).map(success -> {
@ -1596,17 +1580,17 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1596,17 +1580,17 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @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).
* limits, skips and so on).
* @return the {@link List} of converted objects.
*/
protected <T> Flux<T> doFind(String collectionName, Document query, Document fields, Class<T> entityClass,
FindPublisherPreparer preparer) {
FindPublisherPreparer preparer) {
return doFind(collectionName, query, fields, entityClass, preparer,
new ReadDocumentCallback<T>(mongoConverter, entityClass, collectionName));
}
protected <S, T> Flux<T> doFind(String collectionName, Document query, Document fields, Class<S> entityClass,
FindPublisherPreparer preparer, DocumentCallback<T> objectCallback) {
FindPublisherPreparer preparer, DocumentCallback<T> objectCallback) {
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
@ -1654,7 +1638,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1654,7 +1638,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @return the List of converted objects.
*/
protected <T> Mono<T> doFindAndRemove(String collectionName, Document query, Document fields, Document sort,
Class<T> entityClass) {
Class<T> entityClass) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("findAndRemove using query: %s fields: %s sort: %s for class: %s in collection: %s",
@ -1668,7 +1652,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1668,7 +1652,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
protected <T> Mono<T> doFindAndModify(String collectionName, Document query, Document fields, Document sort,
Class<T> entityClass, Update update, FindAndModifyOptions options) {
Class<T> entityClass, Update update, FindAndModifyOptions options) {
FindAndModifyOptions optionsToUse;
if (options == null) {
@ -1687,13 +1671,10 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1687,13 +1671,10 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
Document mappedUpdate = updateMapper.getMappedObject(update.getUpdateObject(), entity);
if (LOGGER.isDebugEnabled()) {
LOGGER
.debug(
String.format(
"findAndModify using query: %s fields: %s sort: %s for class: %s and update: %s "
+ "in collection: %s",
serializeToJsonSafely(mappedQuery), fields, sort, entityClass, serializeToJsonSafely(mappedUpdate),
collectionName));
LOGGER.debug(String.format(
"findAndModify using query: %s fields: %s sort: %s for class: %s and update: %s " + "in collection: %s",
serializeToJsonSafely(mappedQuery), fields, sort, entityClass, serializeToJsonSafely(mappedUpdate),
collectionName));
}
return executeFindOneInternal(new FindAndModifyCallback(mappedQuery, fields, sort, mappedUpdate, optionsToUse),
@ -1828,7 +1809,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1828,7 +1809,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @return
*/
private <T> Mono<T> executeFindOneInternal(ReactiveCollectionCallback<Document> collectionCallback,
DocumentCallback<T> objectCallback, String collectionName) {
DocumentCallback<T> objectCallback, String collectionName) {
return createMono(collectionName,
collection -> Mono.from(collectionCallback.doInCollection(collection)).map(objectCallback::doWith));
@ -1846,14 +1827,14 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1846,14 +1827,14 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
*
* @param collectionCallback the callback to retrieve the {@link FindPublisher} with, must not be {@literal null}.
* @param preparer the {@link FindPublisherPreparer} to potentially modify the {@link FindPublisher} before iterating
* over it, may be {@literal null}
* over it, may be {@literal null}
* @param objectCallback the {@link DocumentCallback} to transform {@link Document}s into the actual domain type, must
* not be {@literal null}.
* not be {@literal null}.
* @param collectionName the collection to be queried, must not be {@literal null}.
* @return
*/
private <T> Flux<T> executeFindMultiInternal(ReactiveCollectionQueryCallback<Document> collectionCallback,
FindPublisherPreparer preparer, DocumentCallback<T> objectCallback, String collectionName) {
FindPublisherPreparer preparer, DocumentCallback<T> objectCallback, String collectionName) {
return createFlux(collectionName, collection -> {
@ -1921,7 +1902,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -1921,7 +1902,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @return
*/
private static RuntimeException potentiallyConvertRuntimeException(RuntimeException ex,
PersistenceExceptionTranslator exceptionTranslator) {
PersistenceExceptionTranslator exceptionTranslator) {
RuntimeException resolved = exceptionTranslator.translateExceptionIfPossible(ex);
return resolved == null ? ex : resolved;
}
@ -2137,7 +2118,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -2137,7 +2118,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
private final FindAndModifyOptions options;
FindAndModifyCallback(Document query, Document fields, Document sort, Document update,
FindAndModifyOptions options) {
FindAndModifyOptions options) {
this.query = query;
this.fields = fields;
@ -2160,7 +2141,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -2160,7 +2141,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
private FindOneAndUpdateOptions convertToFindOneAndUpdateOptions(FindAndModifyOptions options, Document fields,
Document sort) {
Document sort) {
FindOneAndUpdateOptions result = new FindOneAndUpdateOptions();
@ -2299,29 +2280,29 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -2299,29 +2280,29 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
this.type = type;
}
public <T> FindPublisher<T> prepare(FindPublisher<T> cursor) {
public <T> FindPublisher<T> prepare(FindPublisher<T> findPublisher) {
if (query == null) {
return cursor;
return findPublisher;
}
if (query.getSkip() <= 0 && query.getLimit() <= 0 && query.getSortObject() == null
&& !StringUtils.hasText(query.getHint()) && !query.getMeta().hasValues()) {
return cursor;
return findPublisher;
}
FindPublisher<T> cursorToUse = cursor;
FindPublisher<T> findPublisherToUse = findPublisher;
try {
if (query.getSkip() > 0) {
cursorToUse = cursorToUse.skip(query.getSkip());
findPublisherToUse = findPublisherToUse.skip(query.getSkip());
}
if (query.getLimit() > 0) {
cursorToUse = cursorToUse.limit(query.getLimit());
findPublisherToUse = findPublisherToUse.limit(query.getLimit());
}
if (query.getSortObject() != null) {
Document sortDbo = type != null ? getMappedSortObject(query, type) : query.getSortObject();
cursorToUse = cursorToUse.sort(sortDbo);
Document sort = type != null ? getMappedSortObject(query, type) : query.getSortObject();
findPublisherToUse = findPublisherToUse.sort(sort);
}
BasicDBObject modifiers = new BasicDBObject();
@ -2336,13 +2317,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -2336,13 +2317,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
if (!modifiers.isEmpty()) {
cursorToUse = cursorToUse.modifiers(modifiers);
findPublisherToUse = findPublisherToUse.modifiers(modifiers);
}
} catch (RuntimeException e) {
throw potentiallyConvertRuntimeException(e, exceptionTranslator);
}
return cursorToUse;
return findPublisherToUse;
}
}
@ -2353,8 +2334,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -2353,8 +2334,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
@Override
public <T> FindPublisher<T> prepare(FindPublisher<T> cursor) {
return super.prepare(cursor.cursorType(CursorType.TailableAwait));
public <T> FindPublisher<T> prepare(FindPublisher<T> findPublisher) {
return super.prepare(findPublisher.cursorType(CursorType.TailableAwait));
}
}
@ -2371,13 +2352,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -2371,13 +2352,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
DbRefProxyHandler proxyHandler) {
DbRefProxyHandler proxyHandler) {
return null;
}
@Override
public DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation,
MongoPersistentEntity<?> entity, Object id) {
MongoPersistentEntity<?> entity, Object id) {
return null;
}
@ -2391,55 +2372,4 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -2391,55 +2372,4 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return null;
}
}
/**
* @author Mark Paluch
*/
private static class BlockingIndexOptionsProvider implements IndexOperationsProvider {
private final ReactiveMongoOperations mongoOperations;
public BlockingIndexOptionsProvider(ReactiveMongoOperations mongoOperations) {
this.mongoOperations = mongoOperations;
}
@Override
public IndexOperations indexOps(String collectionName) {
return new BlockingIndexOperations(mongoOperations.reactiveIndexOps(collectionName));
}
}
/**
* Blocking {@link IndexOperations} overlay to synchronize calls.
*
* @author Mark Paluch
*/
private static class BlockingIndexOperations implements IndexOperations {
private final ReactiveIndexOperations reactiveIndexOperations;
public BlockingIndexOperations(ReactiveIndexOperations reactiveIndexOperations) {
this.reactiveIndexOperations = reactiveIndexOperations;
}
@Override
public void ensureIndex(IndexDefinition indexDefinition) {
reactiveIndexOperations.ensureIndex(indexDefinition).block();
}
@Override
public void dropIndex(String name) {
reactiveIndexOperations.dropIndex(name).block();
}
@Override
public void dropAllIndexes() {
reactiveIndexOperations.dropAllIndexes().block();
}
@Override
public List<IndexInfo> getIndexInfo() {
return reactiveIndexOperations.getIndexInfo().collectList().block();
}
}
}

21
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java

@ -82,7 +82,6 @@ abstract class MongoConverters { @@ -82,7 +82,6 @@ abstract class MongoConverters {
converters.add(DocumentToNamedMongoScriptConverter.INSTANCE);
converters.add(CurrencyToStringConverter.INSTANCE);
converters.add(StringToCurrencyConverter.INSTANCE);
converters.add(NumberToNumberConverterFactory.INSTANCE);
converters.add(AtomicIntegerToIntegerConverter.INSTANCE);
converters.add(AtomicLongToLongConverter.INSTANCE);
converters.add(LongToAtomicLongConverter.INSTANCE);
@ -297,26 +296,6 @@ abstract class MongoConverters { @@ -297,26 +296,6 @@ abstract class MongoConverters {
}
}
@ReadingConverter
public static enum PublisherToFluxConverter implements Converter<Publisher<?>, Flux<?>> {
INSTANCE;
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public Flux<?> convert(Publisher<?> source) {
if(source instanceof Flux){
return (Flux<?>) source;
}
return Flux.from((Publisher<?>) source);
}
}
/**
* {@link Converter} implementation converting ISO 4217 {@link String} into {@link Currency}.
*

15
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/IndexInfo.java

@ -34,17 +34,15 @@ public class IndexInfo { @@ -34,17 +34,15 @@ public class IndexInfo {
private final String name;
private final boolean unique;
private final boolean dropDuplicates;
private final boolean sparse;
private final String language;
public IndexInfo(List<IndexField> indexFields, String name, boolean unique, boolean dropDuplicates, boolean sparse,
public IndexInfo(List<IndexField> indexFields, String name, boolean unique, boolean sparse,
String language) {
this.indexFields = Collections.unmodifiableList(indexFields);
this.name = name;
this.unique = unique;
this.dropDuplicates = dropDuplicates;
this.sparse = sparse;
this.language = language;
}
@ -84,10 +82,6 @@ public class IndexInfo { @@ -84,10 +82,6 @@ public class IndexInfo {
return unique;
}
public boolean isDropDuplicates() {
return dropDuplicates;
}
public boolean isSparse() {
return sparse;
}
@ -102,8 +96,7 @@ public class IndexInfo { @@ -102,8 +96,7 @@ public class IndexInfo {
@Override
public String toString() {
return "IndexInfo [indexFields=" + indexFields + ", name=" + name + ", unique=" + unique + ", dropDuplicates="
+ dropDuplicates + ", sparse=" + sparse + ", language=" + language + "]";
return "IndexInfo [indexFields=" + indexFields + ", name=" + name + ", unique=" + unique + ", sparse=" + sparse + ", language=" + language + "]";
}
@Override
@ -111,7 +104,6 @@ public class IndexInfo { @@ -111,7 +104,6 @@ public class IndexInfo {
final int prime = 31;
int result = 1;
result = prime * result + (dropDuplicates ? 1231 : 1237);
result = prime * result + ObjectUtils.nullSafeHashCode(indexFields);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + (sparse ? 1231 : 1237);
@ -132,9 +124,6 @@ public class IndexInfo { @@ -132,9 +124,6 @@ public class IndexInfo {
return false;
}
IndexInfo other = (IndexInfo) obj;
if (dropDuplicates != other.dropDuplicates) {
return false;
}
if (indexFields == null) {
if (other.indexFields != null) {
return false;

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java

@ -152,7 +152,7 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati @@ -152,7 +152,7 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
return repositoryConfigurations.stream().filter(configuration -> {
Class<?> repositoryInterface = super.loadRepositoryInterface(configuration, loader);
Class<?> repositoryInterface = loadRepositoryInterface(configuration, loader);
return !RepositoryType.isReactiveRepository(repositoryInterface);
}).collect(Collectors.toList());

1
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/ReactiveMongoRepositoriesRegistrar.java

@ -26,6 +26,7 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi @@ -26,6 +26,7 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
* Mongo-specific {@link ImportBeanDefinitionRegistrar}.
*
* @author Mark Paluch
* @since 2.0
*/
class ReactiveMongoRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport {

11
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/ReactiveMongoRepositoryConfigurationExtension.java

@ -45,6 +45,8 @@ import org.w3c.dom.Element; @@ -45,6 +45,8 @@ import org.w3c.dom.Element;
* Reactive {@link RepositoryConfigurationExtension} for MongoDB.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public class ReactiveMongoRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
@ -161,11 +163,8 @@ public class ReactiveMongoRepositoryConfigurationExtension extends RepositoryCon @@ -161,11 +163,8 @@ public class ReactiveMongoRepositoryConfigurationExtension extends RepositoryCon
Collection<RepositoryConfiguration<T>> repositoryConfigurations = super.getRepositoryConfigurations(configSource,
loader, strictMatchesOnly);
return repositoryConfigurations.stream().filter(configuration -> {
Class<?> repositoryInterface = super.loadRepositoryInterface(configuration, loader);
return RepositoryType.isReactiveRepository(repositoryInterface);
}).collect(Collectors.toList());
return repositoryConfigurations.stream()
.filter(configuration -> RepositoryType.isReactiveRepository(loadRepositoryInterface(configuration, loader)))
.collect(Collectors.toList());
}
}

18
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/RepositoryType.java

@ -16,8 +16,11 @@ @@ -16,8 +16,11 @@
package org.springframework.data.mongodb.repository.config;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.springframework.data.repository.util.ReactiveWrappers;
import org.springframework.util.ReflectionUtils;
import lombok.experimental.UtilityClass;
@ -25,6 +28,8 @@ import lombok.experimental.UtilityClass; @@ -25,6 +28,8 @@ import lombok.experimental.UtilityClass;
* Utility class to discover whether a repository interface uses reactive wrapper types.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
@UtilityClass
class RepositoryType {
@ -41,16 +46,9 @@ class RepositoryType { @@ -41,16 +46,9 @@ class RepositoryType {
return false;
}
Method[] methods = repositoryInterface.getMethods();
for (Method method : methods) {
if (usesReactiveWrappers(method)) {
return true;
}
}
return false;
List<Method> reactiveMethods = new ArrayList<>();
ReflectionUtils.doWithMethods(repositoryInterface, reactiveMethods::add, RepositoryType::usesReactiveWrappers);
return !reactiveMethods.isEmpty();
}
private static boolean usesReactiveWrappers(Method method) {

27
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java

@ -44,10 +44,12 @@ import reactor.core.publisher.Mono; @@ -44,10 +44,12 @@ import reactor.core.publisher.Mono;
* Base class for reactive {@link RepositoryQuery} implementations for MongoDB.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
private final MongoQueryMethod method;
private final ReactiveMongoQueryMethod method;
private final ReactiveMongoOperations operations;
private final EntityInstantiators instantiators;
@ -59,7 +61,7 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { @@ -59,7 +61,7 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
* @param operations must not be {@literal null}.
* @param conversionService must not be {@literal null}.
*/
public AbstractReactiveMongoQuery(MongoQueryMethod method, ReactiveMongoOperations operations,
public AbstractReactiveMongoQuery(ReactiveMongoQueryMethod method, ReactiveMongoOperations operations,
ConversionService conversionService) {
Assert.notNull(method, "MongoQueryMethod must not be null!");
@ -84,13 +86,8 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { @@ -84,13 +86,8 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
*/
public Object execute(Object[] parameters) {
boolean hasReactiveParameters = hasReactiveWrapperParameter();
if (hasReactiveParameters) {
return executeDeferred(parameters);
}
return execute(new MongoParametersParameterAccessor(method, parameters));
return method.hasReactiveWrapperParameter() ? executeDeferred(parameters)
: execute(new MongoParametersParameterAccessor(method, parameters));
}
@SuppressWarnings("unchecked")
@ -120,16 +117,6 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { @@ -120,16 +117,6 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
return execution.execute(query, processor.getReturnedType().getDomainType(), collection);
}
private boolean hasReactiveWrapperParameter() {
for (MongoParameters.MongoParameter mongoParameter : method.getParameters()) {
if (ReactiveWrapperConverters.supports(mongoParameter.getType())) {
return true;
}
}
return false;
}
/**
* Returns the execution instance to use.
*
@ -153,7 +140,7 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { @@ -153,7 +140,7 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
return new SlicedExecution(operations, accessor.getPageable());
} else if (isInfiniteStream(method)) {
return new TailExecution(operations, accessor.getPageable());
} else if (method.isCollectionQuery()) {
} else if (method.isCollectionQuery()) {
return new CollectionExecution(operations, accessor.getPageable());
} else if (method.isPageQuery()) {
return new PagedExecution(operations, accessor.getPageable());

24
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoParameterAccessor.java

@ -15,6 +15,9 @@ @@ -15,6 +15,9 @@
*/
package org.springframework.data.mongodb.repository.query;
import java.util.ArrayList;
import java.util.List;
import org.springframework.data.repository.util.ReactiveWrapperConverters;
import org.springframework.data.repository.util.ReactiveWrappers;
@ -27,35 +30,34 @@ import reactor.core.publisher.MonoProcessor; @@ -27,35 +30,34 @@ import reactor.core.publisher.MonoProcessor;
* to reactive parameter wrapper types upon creation. This class performs synchronization when acessing parameters.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
class ReactiveMongoParameterAccessor extends MongoParametersParameterAccessor {
private final Object[] values;
private final MonoProcessor<?>[] subscriptions;
private final List<MonoProcessor<?>> subscriptions;
public ReactiveMongoParameterAccessor(MongoQueryMethod method, Object[] values) {
super(method, values);
this.values = values;
this.subscriptions = new MonoProcessor<?>[values.length];
this.subscriptions = new ArrayList<>(values.length);
for (int i = 0; i < values.length; i++) {
Object value = values[i];
if (value == null) {
continue;
}
if (!ReactiveWrappers.supports(value.getClass())) {
if (value == null || !ReactiveWrappers.supports(value.getClass())) {
subscriptions.add(null);
continue;
}
if (ReactiveWrappers.isSingleValueType(value.getClass())) {
subscriptions[i] = ReactiveWrapperConverters.toWrapper(value, Mono.class).subscribe();
subscriptions.add(ReactiveWrapperConverters.toWrapper(value, Mono.class).subscribe());
} else {
subscriptions[i] = ReactiveWrapperConverters.toWrapper(value, Flux.class).collectList().subscribe();
subscriptions.add(ReactiveWrapperConverters.toWrapper(value, Flux.class).collectList().subscribe());
}
}
}
@ -67,8 +69,8 @@ class ReactiveMongoParameterAccessor extends MongoParametersParameterAccessor { @@ -67,8 +69,8 @@ class ReactiveMongoParameterAccessor extends MongoParametersParameterAccessor {
@Override
protected <T> T getValue(int index) {
if (subscriptions[index] != null) {
return (T) subscriptions[index].block();
if (subscriptions.get(index) != null) {
return (T) subscriptions.get(index).block();
}
return super.getValue(index);

20
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryMethod.java

@ -27,8 +27,10 @@ import org.springframework.data.geo.GeoResult; @@ -27,8 +27,10 @@ import org.springframework.data.geo.GeoResult;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.repository.query.MongoParameters.MongoParameter;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.util.ReactiveWrapperConverters;
import org.springframework.data.repository.util.ReactiveWrappers;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
@ -37,6 +39,7 @@ import org.springframework.data.util.TypeInformation; @@ -37,6 +39,7 @@ import org.springframework.data.util.TypeInformation;
* Reactive specific implementation of {@link MongoQueryMethod}.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public class ReactiveMongoQueryMethod extends MongoQueryMethod {
@ -147,4 +150,21 @@ public class ReactiveMongoQueryMethod extends MongoQueryMethod { @@ -147,4 +150,21 @@ public class ReactiveMongoQueryMethod extends MongoQueryMethod {
public boolean isStreamQuery() {
return true;
}
/**
* Check if the given {@link org.springframework.data.repository.query.QueryMethod} receives a reactive parameter
* wrapper as one of its parameters.
*
* @return
*/
public boolean hasReactiveWrapperParameter() {
for (MongoParameter mongoParameter : getParameters()) {
if (ReactiveWrapperConverters.supports(mongoParameter.getType())) {
return true;
}
}
return false;
}
}

16
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactivePartTreeMongoQuery.java

@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.repository.query;
import org.bson.Document;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.MongoTemplate;
@ -37,6 +38,8 @@ import com.mongodb.util.JSONParseException; @@ -37,6 +38,8 @@ import com.mongodb.util.JSONParseException;
* Reactive PartTree {@link RepositoryQuery} implementation for Mongo.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery {
@ -52,7 +55,7 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery { @@ -52,7 +55,7 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery {
* @param mongoOperations must not be {@literal null}.
* @param conversionService must not be {@literal null}.
*/
public ReactivePartTreeMongoQuery(MongoQueryMethod method, ReactiveMongoOperations mongoOperations, ConversionService conversionService) {
public ReactivePartTreeMongoQuery(ReactiveMongoQueryMethod method, ReactiveMongoOperations mongoOperations, ConversionService conversionService) {
super(method, mongoOperations, conversionService);
@ -90,19 +93,14 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery { @@ -90,19 +93,14 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery {
query.addCriteria(textCriteria);
}
String fieldSpec = this.getQueryMethod().getFieldSpecification();
String fieldSpec = getQueryMethod().getFieldSpecification();
if (!StringUtils.hasText(fieldSpec)) {
ReturnedType returnedType = processor.withDynamicProjection(accessor).getReturnedType();
if (returnedType.isProjecting()) {
Field fields = query.fields();
for (String field : returnedType.getInputProperties()) {
fields.include(field);
}
returnedType.getInputProperties().forEach(query.fields()::include);
}
return query;
@ -110,7 +108,7 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery { @@ -110,7 +108,7 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery {
try {
BasicQuery result = new BasicQuery(query.getQueryObject().toJson(), fieldSpec);
BasicQuery result = new BasicQuery(query.getQueryObject(), Document.parse(fieldSpec));
result.setSortObject(query.getSortObject());
return result;

6
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveStringBasedMongoQuery.java

@ -36,6 +36,8 @@ import org.springframework.util.Assert; @@ -36,6 +36,8 @@ import org.springframework.util.Assert;
* Query to use a plain JSON String to create the {@link Query} to actually execute.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
@ -60,7 +62,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery { @@ -60,7 +62,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
* @param evaluationContextProvider must not be {@literal null}.
* @param conversionService must not be {@literal null}.
*/
public ReactiveStringBasedMongoQuery(MongoQueryMethod method, ReactiveMongoOperations mongoOperations,
public ReactiveStringBasedMongoQuery(ReactiveMongoQueryMethod method, ReactiveMongoOperations mongoOperations,
SpelExpressionParser expressionParser, EvaluationContextProvider evaluationContextProvider, ConversionService conversionService) {
this(method.getAnnotatedQuery(), method, mongoOperations, expressionParser, evaluationContextProvider, conversionService);
}
@ -75,7 +77,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery { @@ -75,7 +77,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
* @param expressionParser must not be {@literal null}.
* @param conversionService must not be {@literal null}.
*/
public ReactiveStringBasedMongoQuery(String query, MongoQueryMethod method, ReactiveMongoOperations mongoOperations,
public ReactiveStringBasedMongoQuery(String query, ReactiveMongoQueryMethod method, ReactiveMongoOperations mongoOperations,
SpelExpressionParser expressionParser, EvaluationContextProvider evaluationContextProvider, ConversionService conversionService) {
super(method, mongoOperations, conversionService);

6
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/IndexEnsuringQueryCreationListener.java

@ -22,6 +22,7 @@ import java.util.Set; @@ -22,6 +22,7 @@ import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.IndexOperationsProvider;
import org.springframework.data.mongodb.core.MongoOperations;
@ -40,6 +41,7 @@ import org.springframework.util.Assert; @@ -40,6 +41,7 @@ import org.springframework.util.Assert;
*
* @author Oliver Gierke
* @author Mark Paluch
* @author Christoph Strobl
*/
class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTreeMongoQuery> {
@ -81,7 +83,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr @@ -81,7 +83,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr
// Add fixed sorting criteria to index
if (sort != null) {
for (Sort.Order order : sort) {
for (Order order : sort) {
index.on(order.getProperty(), order.getDirection());
}
}
@ -97,7 +99,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr @@ -97,7 +99,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr
return Direction.DESC;
}
org.springframework.data.domain.Sort.Order order = sort.getOrderFor(property);
Order order = sort.getOrderFor(property);
return order == null ? Direction.DESC : order.isAscending() ? Direction.ASC : Direction.DESC;
}
}

16
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactory.java

@ -20,6 +20,7 @@ import static org.springframework.data.querydsl.QueryDslUtils.*; @@ -20,6 +20,7 @@ import static org.springframework.data.querydsl.QueryDslUtils.*;
import java.io.Serializable;
import java.lang.reflect.Method;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.core.MongoOperations;
@ -43,6 +44,7 @@ import org.springframework.data.repository.query.RepositoryQuery; @@ -43,6 +44,7 @@ import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.data.repository.reactive.RxJavaCrudRepository;
import org.springframework.data.repository.util.QueryExecutionConverters;
import org.springframework.data.repository.util.ReactiveWrappers;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@ -56,6 +58,7 @@ import org.springframework.util.ClassUtils; @@ -56,6 +58,7 @@ import org.springframework.util.ClassUtils;
*/
public class MongoRepositoryFactory extends RepositoryFactorySupport {
// TODO: to we need this here and in ReactiveWrappers?
private static final boolean PROJECT_REACTOR_PRESENT = ClassUtils.isPresent("reactor.core.publisher.Flux",
QueryExecutionConverters.class.getClassLoader());
private static final boolean RXJAVA_OBSERVABLE_PRESENT = ClassUtils.isPresent("rx.Observable",
@ -86,17 +89,22 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport { @@ -86,17 +89,22 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
boolean isReactiveRepository = (PROJECT_REACTOR_PRESENT && ReactiveCrudRepository.class.isAssignableFrom(metadata.getRepositoryInterface())) || (
RXJAVA_OBSERVABLE_PRESENT && RxJavaCrudRepository.class.isAssignableFrom(metadata.getRepositoryInterface()));
boolean isQueryDslRepository = QUERY_DSL_PRESENT
&& QueryDslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface());
if (isReactiveRepository) {
if(isQueryDslRepository) {
throw new InvalidDataAccessApiUsageException("Cannot combine Querydsl and reactive repository in one interface");
}
return SimpleReactiveMongoRepository.class;
}
boolean isQueryDslRepository = QUERY_DSL_PRESENT
&& QueryDslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface());
return isQueryDslRepository ? QueryDslMongoRepository.class : SimpleMongoRepository.class;
}

39
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveChunk.java

@ -35,7 +35,10 @@ import reactor.core.publisher.MonoProcessor; @@ -35,7 +35,10 @@ import reactor.core.publisher.MonoProcessor;
* A reactive chunk of data restricted by the configured {@link Pageable}.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
//TODO: should that one move to SD Commons
abstract class ReactiveChunk<T> implements Slice<T>, Serializable {
private static final long serialVersionUID = 867755909294344406L;
@ -88,7 +91,7 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable { @@ -88,7 +91,7 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable {
* @see org.springframework.data.domain.Slice#getNumberOfElements()
*/
public int getNumberOfElements() {
return getContent0().size();
return getContent().size();
}
/*
@ -141,7 +144,7 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable { @@ -141,7 +144,7 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable {
* @see org.springframework.data.domain.Slice#hasContent()
*/
public boolean hasContent() {
return !getContent0().isEmpty();
return !getContent().isEmpty();
}
/*
@ -149,7 +152,18 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable { @@ -149,7 +152,18 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable {
* @see org.springframework.data.domain.Slice#getContent()
*/
public List<T> getContent() {
return Collections.unmodifiableList(getContent0());
if (contentCache != null) {
return Collections.unmodifiableList(contentCache);
}
List<T> list = processor.block();
if (list.size() > pageable.getPageSize()) {
return list.subList(0, pageable.getPageSize());
}
return Collections.unmodifiableList(list);
}
/*
@ -165,7 +179,7 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable { @@ -165,7 +179,7 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable {
* @see java.lang.Iterable#iterator()
*/
public Iterator<T> iterator() {
return getContent0().iterator();
return getContent().iterator();
}
/**
@ -178,7 +192,7 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable { @@ -178,7 +192,7 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable {
Assert.notNull(converter, "Converter must not be null!");
List<S> result = new ArrayList<S>(getContent0().size());
List<S> result = new ArrayList<S>(getContent().size());
for (T element : this) {
result.add(converter.convert(element));
@ -187,21 +201,6 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable { @@ -187,21 +201,6 @@ abstract class ReactiveChunk<T> implements Slice<T>, Serializable {
return result;
}
protected List<T> getContent0() {
if (contentCache != null) {
return contentCache;
}
List<T> list = processor.block();
if (list.size() > pageable.getPageSize()) {
return list.subList(0, pageable.getPageSize());
}
return list;
}
/**
* Returns whether the returned list contains more elements than specified by {@link Pageable#getPageSize()}.
*

3
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactory.java

@ -54,6 +54,7 @@ import org.springframework.util.ClassUtils; @@ -54,6 +54,7 @@ import org.springframework.util.ClassUtils;
* Factory to create {@link org.springframework.data.mongodb.repository.ReactiveMongoRepository} instances.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public class ReactiveMongoRepositoryFactory extends RepositoryFactorySupport {
@ -212,7 +213,7 @@ public class ReactiveMongoRepositoryFactory extends RepositoryFactorySupport { @@ -212,7 +213,7 @@ public class ReactiveMongoRepositoryFactory extends RepositoryFactorySupport {
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
NamedQueries namedQueries) {
MongoQueryMethod queryMethod = new ReactiveMongoQueryMethod(method, metadata, factory, mappingContext);
ReactiveMongoQueryMethod queryMethod = new ReactiveMongoQueryMethod(method, metadata, factory, mappingContext);
String namedQueryName = queryMethod.getNamedQueryName();
if (namedQueries.hasQuery(namedQueryName)) {

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactoryBean.java

@ -19,6 +19,7 @@ package org.springframework.data.mongodb.repository.support; @@ -19,6 +19,7 @@ package org.springframework.data.mongodb.repository.support;
import java.io.Serializable;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.IndexOperationsAdapter;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
@ -30,6 +31,7 @@ import org.springframework.util.Assert; @@ -30,6 +31,7 @@ import org.springframework.util.Assert;
* {@link org.springframework.data.mongodb.repository.ReactiveMongoRepository} instances.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
* @see org.springframework.data.repository.reactive.ReactivePagingAndSortingRepository
* @see org.springframework.data.repository.reactive.RxJavaPagingAndSortingRepository
@ -84,7 +86,7 @@ public class ReactiveMongoRepositoryFactoryBean<T extends Repository<S, ID>, S, @@ -84,7 +86,7 @@ public class ReactiveMongoRepositoryFactoryBean<T extends Repository<S, ID>, S,
if (createIndexesForQueryMethods) {
factory.addQueryCreationListener(
new IndexEnsuringQueryCreationListener(collectionName -> operations.indexOps(collectionName)));
new IndexEnsuringQueryCreationListener(collectionName -> IndexOperationsAdapter.blocking(operations.reactiveIndexOps(collectionName))));
}
return factory;

1
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactivePageImpl.java

@ -32,6 +32,7 @@ import reactor.core.publisher.MonoProcessor; @@ -32,6 +32,7 @@ import reactor.core.publisher.MonoProcessor;
* @author Mark Paluch
* @since 2.0
*/
//TODO: should that one move to SD-Commons?
public class ReactivePageImpl<T> extends ReactiveChunk<T> implements Page<T> {
private static final long serialVersionUID = 867755909294344406L;

13
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleReactiveMongoRepository.java

@ -216,9 +216,7 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement @@ -216,9 +216,7 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement
Assert.notNull(entities, "The given Publisher of entities must not be null!");
return Flux.from(entities).flatMap(entity -> {
return mongoOperations.insert(entity, entityInformation.getCollectionName());
});
return Flux.from(entities).flatMap(entity -> mongoOperations.insert(entity, entityInformation.getCollectionName()));
}
public <S extends T> Mono<S> save(S entity) {
@ -272,15 +270,17 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement @@ -272,15 +270,17 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement
});
}
// TODO: should this one really be void?
public Mono<Void> delete(ID id) {
Assert.notNull(id, "The given id must not be null!");
return mongoOperations
.remove(getIdQuery(id), entityInformation.getJavaType(), entityInformation.getCollectionName())
.then();
.remove(getIdQuery(id), entityInformation.getJavaType(), entityInformation.getCollectionName()).then();
}
// TODO: should this one really be void?
public Mono<Void> delete(T entity) {
Assert.notNull(entity, "The given entity must not be null!");
@ -288,6 +288,7 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement @@ -288,6 +288,7 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement
return delete(entityInformation.getId(entity));
}
// TODO: should this one really be void?
public Mono<Void> delete(Iterable<? extends T> entities) {
Assert.notNull(entities, "The given Iterable of entities must not be null!");
@ -295,6 +296,7 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement @@ -295,6 +296,7 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement
return Flux.fromIterable(entities).flatMap(entity -> delete(entityInformation.getId(entity))).then();
}
// TODO: should this one really be void?
@Override
public Mono<Void> delete(Publisher<? extends T> entityStream) {
@ -303,6 +305,7 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement @@ -303,6 +305,7 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement
return Flux.from(entityStream).flatMap(entity -> delete(entityInformation.getId(entity))).then();
}
// TODO: should this one really be void?
public Mono<Void> deleteAll() {
return mongoOperations.remove(new Query(), entityInformation.getCollectionName())
.then(deleteResult -> Mono.empty());

1
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AbstractReactiveMongoConfigurationUnitTests.java

@ -74,7 +74,6 @@ public class AbstractReactiveMongoConfigurationUnitTests { @@ -74,7 +74,6 @@ public class AbstractReactiveMongoConfigurationUnitTests {
*/
@Test
public void doesNotScanPackageIfMappingPackageIsNull() throws ClassNotFoundException {
assertScanningDisabled(null);
}

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

@ -376,7 +376,6 @@ public class MongoTemplateTests { @@ -376,7 +376,6 @@ public class MongoTemplateTests {
assertThat(indexInfoList.size(), is(2));
IndexInfo ii = indexInfoList.get(1);
assertThat(ii.isUnique(), is(true));
assertThat(ii.isDropDuplicates(), is(false));
assertThat(ii.isSparse(), is(false));
List<IndexField> indexFields = ii.getIndexFields();

9
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateExecuteTests.java

@ -33,6 +33,7 @@ import org.junit.runner.RunWith; @@ -33,6 +33,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.data.util.Version;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ -52,22 +53,22 @@ import reactor.test.TestSubscriber; @@ -52,22 +53,22 @@ import reactor.test.TestSubscriber;
@ContextConfiguration("classpath:reactive-infrastructure.xml")
public class ReactiveMongoTemplateExecuteTests {
private static final org.springframework.data.util.Version THREE = org.springframework.data.util.Version.parse("3.0");
private static final Version THREE = Version.parse("3.0");
@Autowired SimpleReactiveMongoDatabaseFactory factory;
@Autowired ReactiveMongoOperations operations;
@Rule public ExpectedException thrown = ExpectedException.none();
org.springframework.data.util.Version mongoVersion;
Version mongoVersion;
@Before
public void setUp() {
cleanUp();
if (mongoVersion == null) {
org.bson.Document result = operations.executeCommand("{ buildInfo: 1 }").block();
mongoVersion = org.springframework.data.util.Version.parse(result.get("version").toString());
Document result = operations.executeCommand("{ buildInfo: 1 }").block();
mongoVersion = Version.parse(result.get("version").toString());
}
}

29
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateIndexTests.java

@ -31,7 +31,6 @@ import org.springframework.beans.factory.annotation.Autowired; @@ -31,7 +31,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.index.Index;
import org.springframework.data.mongodb.core.index.Index.Duplicates;
import org.springframework.data.mongodb.core.index.IndexField;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.util.Version;
@ -50,14 +49,12 @@ import reactor.test.TestSubscriber; @@ -50,14 +49,12 @@ import reactor.test.TestSubscriber;
* Integration test for {@link MongoTemplate}.
*
* @author Mark Paluch
* @author Christoph Strobl
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:reactive-infrastructure.xml")
public class ReactiveMongoTemplateIndexTests {
private static final org.springframework.data.util.Version TWO_DOT_EIGHT = org.springframework.data.util.Version
.parse("2.8");
@Autowired SimpleReactiveMongoDatabaseFactory factory;
@Autowired ReactiveMongoTemplate template;
@ -68,20 +65,11 @@ public class ReactiveMongoTemplateIndexTests { @@ -68,20 +65,11 @@ public class ReactiveMongoTemplateIndexTests {
@Before
public void setUp() {
cleanDb();
queryMongoVersionIfNecessary();
}
@After
public void cleanUp() {}
private void queryMongoVersionIfNecessary() {
if (mongoVersion == null) {
org.bson.Document result = template.executeCommand("{ buildInfo: 1 }").block();
mongoVersion = Version.parse(result.get("version").toString());
}
}
private void cleanDb() {
template.dropCollection(Person.class).block();
}
@ -90,7 +78,6 @@ public class ReactiveMongoTemplateIndexTests { @@ -90,7 +78,6 @@ public class ReactiveMongoTemplateIndexTests {
* @see DATAMONGO-1444
*/
@Test
@SuppressWarnings("deprecation")
public void testEnsureIndexShouldCreateIndex() {
Person p1 = new Person("Oliver");
@ -100,8 +87,7 @@ public class ReactiveMongoTemplateIndexTests { @@ -100,8 +87,7 @@ public class ReactiveMongoTemplateIndexTests {
p2.setAge(40);
template.insert(p2);
template.reactiveIndexOps(Person.class).ensureIndex(new Index().on("age", Direction.DESC).unique())
.block();
template.reactiveIndexOps(Person.class).ensureIndex(new Index().on("age", Direction.DESC).unique()).block();
MongoCollection<Document> coll = template.getCollection(template.getCollectionName(Person.class));
List<Document> indexInfo = Flux.from(coll.listIndexes()).collectList().block();
@ -109,14 +95,14 @@ public class ReactiveMongoTemplateIndexTests { @@ -109,14 +95,14 @@ public class ReactiveMongoTemplateIndexTests {
assertThat(indexInfo.size(), is(2));
Object indexKey = null;
boolean unique = false;
for (org.bson.Document ix : indexInfo) {
for (Document ix : indexInfo) {
if ("age_-1".equals(ix.get("name"))) {
indexKey = ix.get("key");
unique = (Boolean) ix.get("unique");
}
}
assertThat(((org.bson.Document) indexKey), hasEntry("age", -1));
assertThat(((Document) indexKey), hasEntry("age", -1));
assertThat(unique, is(true));
}
@ -124,15 +110,13 @@ public class ReactiveMongoTemplateIndexTests { @@ -124,15 +110,13 @@ public class ReactiveMongoTemplateIndexTests {
* @see DATAMONGO-1444
*/
@Test
@SuppressWarnings("deprecation")
public void getIndexInfoShouldReturnCorrectIndex() {
Person p1 = new Person("Oliver");
p1.setAge(25);
template.insert(p1).block();
template.reactiveIndexOps(Person.class).ensureIndex(new Index().on("age", Direction.DESC).unique())
.block();
template.reactiveIndexOps(Person.class).ensureIndex(new Index().on("age", Direction.DESC).unique()).block();
List<IndexInfo> indexInfoList = Flux.from(template.reactiveIndexOps(Person.class).getIndexInfo()).collectList()
.block();
@ -140,7 +124,6 @@ public class ReactiveMongoTemplateIndexTests { @@ -140,7 +124,6 @@ public class ReactiveMongoTemplateIndexTests {
IndexInfo ii = indexInfoList.get(1);
assertThat(ii.isUnique(), is(true));
assertThat(ii.isDropDuplicates(), is(false));
assertThat(ii.isSparse(), is(false));
List<IndexField> indexFields = ii.getIndexFields();
@ -168,7 +151,7 @@ public class ReactiveMongoTemplateIndexTests { @@ -168,7 +151,7 @@ public class ReactiveMongoTemplateIndexTests {
ListIndexesPublisher<Document> listIndexesPublisher = template
.getCollection(template.getCollectionName(Person.class)).listIndexes();
List<Document> indexInfo = Flux.from(listIndexesPublisher).collectList().block();
org.bson.Document indexKey = null;
Document indexKey = null;
boolean unique = false;
for (Document document : indexInfo) {

63
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateTests.java

@ -74,6 +74,7 @@ import reactor.test.TestSubscriber; @@ -74,6 +74,7 @@ import reactor.test.TestSubscriber;
* Integration test for {@link MongoTemplate}.
*
* @author Mark Paluch
* @author Christoph Strobl
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:reactive-infrastructure.xml")
@ -89,20 +90,11 @@ public class ReactiveMongoTemplateTests { @@ -89,20 +90,11 @@ public class ReactiveMongoTemplateTests {
@Before
public void setUp() {
cleanDb();
queryMongoVersionIfNecessary();
}
@After
public void cleanUp() {}
private void queryMongoVersionIfNecessary() {
if (mongoVersion == null) {
org.bson.Document result = template.executeCommand("{ buildInfo: 1 }").block();
mongoVersion = org.springframework.data.util.Version.parse(result.get("version").toString());
}
}
private void cleanDb() {
template.dropCollection("people") //
.and(template.dropCollection("collection")) //
@ -181,7 +173,7 @@ public class ReactiveMongoTemplateTests { @@ -181,7 +173,7 @@ public class ReactiveMongoTemplateTests {
template.insert(person).block();
TestSubscriber<Person> testSubscriber = TestSubscriber.create();
Flux<Person> flux = template.find(new Query(Criteria.where("_id").is(person.getId())), Person.class);
Flux<Person> flux = template.find(new Query(where("_id").is(person.getId())), Person.class);
flux.subscribe(testSubscriber);
testSubscriber.awaitAndAssertNextValueCount(1);
@ -225,7 +217,7 @@ public class ReactiveMongoTemplateTests { @@ -225,7 +217,7 @@ public class ReactiveMongoTemplateTests {
template.insert(person, "people").block();
TestSubscriber<Person> testSubscriber = TestSubscriber.create();
Flux<Person> flux = template.find(new Query(Criteria.where("_id").is(person.getId())), Person.class, "people");
Flux<Person> flux = template.find(new Query(where("_id").is(person.getId())), Person.class, "people");
flux.subscribe(testSubscriber);
testSubscriber.awaitAndAssertNextValueCount(1);
@ -297,7 +289,7 @@ public class ReactiveMongoTemplateTests { @@ -297,7 +289,7 @@ public class ReactiveMongoTemplateTests {
p.setAge(22);
template.insert(p).block();
Query q1 = new Query(Criteria.where("id").is(p.getId()));
Query q1 = new Query(where("id").is(p.getId()));
PersonWithAList p2 = template.findOne(q1, PersonWithAList.class).block();
assertThat(p2, notNullValue());
assertThat(p2.getWishList().size(), is(0));
@ -345,7 +337,7 @@ public class ReactiveMongoTemplateTests { @@ -345,7 +337,7 @@ public class ReactiveMongoTemplateTests {
template.insert(p3).block();
// test query with a sort
Query q2 = new Query(Criteria.where("age").gt(10));
Query q2 = new Query(where("age").gt(10));
q2.with(new Sort(Direction.DESC, "age"));
PersonWithAList p5 = template.findOne(q2, PersonWithAList.class).block();
assertThat(p5.getFirstName(), is("Mark"));
@ -364,7 +356,7 @@ public class ReactiveMongoTemplateTests { @@ -364,7 +356,7 @@ public class ReactiveMongoTemplateTests {
person.setAge(25);
mongoTemplate.insert(person).block();
Query q = new Query(Criteria.where("BOGUS").gt(22));
Query q = new Query(where("BOGUS").gt(22));
Update u = new Update().set("firstName", "Sven");
mongoTemplate.updateFirst(q, u, Person.class).block();
}
@ -377,9 +369,8 @@ public class ReactiveMongoTemplateTests { @@ -377,9 +369,8 @@ public class ReactiveMongoTemplateTests {
Person person = new Person("Oliver2", 25);
template.insert(person) //
.then(template.updateFirst(new Query(Criteria.where("age").is(25)), new Update().set("firstName", "Sven"),
Person.class)) //
.flatMap(p -> template.find(new Query(Criteria.where("age").is(25)), Person.class))
.then(template.updateFirst(new Query(where("age").is(25)), new Update().set("firstName", "Sven"), Person.class)) //
.flatMap(p -> template.find(new Query(where("age").is(25)), Person.class))
.subscribeWith(TestSubscriber.create()) //
.await() //
.assertValuesWith(result -> {
@ -395,9 +386,8 @@ public class ReactiveMongoTemplateTests { @@ -395,9 +386,8 @@ public class ReactiveMongoTemplateTests {
Person person = new Person("Oliver2", 25);
template.insert(person, "people") //
.then(template.updateFirst(new Query(Criteria.where("age").is(25)), new Update().set("firstName", "Sven"),
"people")) //
.flatMap(p -> template.find(new Query(Criteria.where("age").is(25)), Person.class, "people"))
.then(template.updateFirst(new Query(where("age").is(25)), new Update().set("firstName", "Sven"), "people")) //
.flatMap(p -> template.find(new Query(where("age").is(25)), Person.class, "people"))
.subscribeWith(TestSubscriber.create()) //
.await() //
.assertValuesWith(result -> {
@ -411,13 +401,13 @@ public class ReactiveMongoTemplateTests { @@ -411,13 +401,13 @@ public class ReactiveMongoTemplateTests {
@Test
public void updateMultiByEntityTypeShouldUpdateObjects() throws Exception {
Query query = new Query(new Criteria().orOperator(Criteria.where("firstName").is("Walter Jr"),
Criteria.where("firstName").is("Walter")));
Query query = new Query(
new Criteria().orOperator(where("firstName").is("Walter Jr"), Criteria.where("firstName").is("Walter")));
template.insertAll(Flux.just(new Person("Walter", 50), new Person("Skyler", 43), new Person("Walter Jr", 16))) //
.collectList() //
.flatMap(a -> template.updateMulti(query, new Update().set("firstName", "Walt"), Person.class)) //
.flatMap(p -> template.find(new Query(Criteria.where("firstName").is("Walt")), Person.class)) //
.flatMap(p -> template.find(new Query(where("firstName").is("Walt")), Person.class)) //
.subscribeWith(TestSubscriber.create()) //
.awaitAndAssertNextValueCount(2);
}
@ -428,14 +418,14 @@ public class ReactiveMongoTemplateTests { @@ -428,14 +418,14 @@ public class ReactiveMongoTemplateTests {
@Test
public void updateMultiByCollectionNameShouldUpdateObject() throws Exception {
Query query = new Query(new Criteria().orOperator(Criteria.where("firstName").is("Walter Jr"),
Criteria.where("firstName").is("Walter")));
Query query = new Query(
new Criteria().orOperator(where("firstName").is("Walter Jr"), Criteria.where("firstName").is("Walter")));
template
.insert(Flux.just(new Person("Walter", 50), new Person("Skyler", 43), new Person("Walter Jr", 16)), "people") //
.collectList() //
.flatMap(a -> template.updateMulti(query, new Update().set("firstName", "Walt"), Person.class, "people")) //
.flatMap(p -> template.find(new Query(Criteria.where("firstName").is("Walt")), Person.class, "people")) //
.flatMap(p -> template.find(new Query(where("firstName").is("Walt")), Person.class, "people")) //
.subscribeWith(TestSubscriber.create()) //
.awaitAndAssertNextValueCount(2);
}
@ -482,7 +472,7 @@ public class ReactiveMongoTemplateTests { @@ -482,7 +472,7 @@ public class ReactiveMongoTemplateTests {
thrown.expectMessage("age");
// thrown.expectMessage("failed");
Query query = new Query(Criteria.where("firstName").is("Amol"));
Query query = new Query(where("firstName").is("Amol"));
Update upd = new Update().push("age", 29);
template.updateFirst(query, upd, Person.class).block();
}
@ -627,7 +617,7 @@ public class ReactiveMongoTemplateTests { @@ -627,7 +617,7 @@ public class ReactiveMongoTemplateTests {
@Test
public void doesNotFailOnVersionInitForUnversionedEntity() {
org.bson.Document dbObject = new org.bson.Document();
Document dbObject = new Document();
dbObject.put("firstName", "Oliver");
template.insert(dbObject, template.determineCollectionName(PersonWithVersionPropertyOfTypeInteger.class));
@ -685,7 +675,7 @@ public class ReactiveMongoTemplateTests { @@ -685,7 +675,7 @@ public class ReactiveMongoTemplateTests {
@Test
public void savesPlainDbObjectCorrectly() {
org.bson.Document dbObject = new org.bson.Document("foo", "bar");
Document dbObject = new Document("foo", "bar");
template.save(dbObject, "collection").block();
assertThat(dbObject.containsKey("_id"), is(true));
@ -697,10 +687,10 @@ public class ReactiveMongoTemplateTests { @@ -697,10 +687,10 @@ public class ReactiveMongoTemplateTests {
@Test(expected = InvalidDataAccessApiUsageException.class)
public void rejectsPlainObjectWithOutExplicitCollection() {
org.bson.Document dbObject = new org.bson.Document("foo", "bar");
Document dbObject = new Document("foo", "bar");
template.save(dbObject, "collection").block();
template.findById(dbObject.get("_id"), org.bson.Document.class).block();
template.findById(dbObject.get("_id"), Document.class).block();
}
/**
@ -709,10 +699,10 @@ public class ReactiveMongoTemplateTests { @@ -709,10 +699,10 @@ public class ReactiveMongoTemplateTests {
@Test
public void readsPlainDbObjectById() {
org.bson.Document dbObject = new org.bson.Document("foo", "bar");
Document dbObject = new Document("foo", "bar");
template.save(dbObject, "collection").block();
org.bson.Document result = template.findById(dbObject.get("_id"), org.bson.Document.class, "collection").block();
Document result = template.findById(dbObject.get("_id"), Document.class, "collection").block();
assertThat(result.get("foo"), is(dbObject.get("foo")));
assertThat(result.get("_id"), is(dbObject.get("_id")));
}
@ -729,7 +719,8 @@ public class ReactiveMongoTemplateTests { @@ -729,7 +719,8 @@ public class ReactiveMongoTemplateTests {
new Venue("Maplewood, NJ", -74.2713, 40.73137));
template.insertAll(venues).blockLast();
template.indexOps(Venue.class).ensureIndex(new GeospatialIndex("location").typed(GeoSpatialIndexType.GEO_2D));
IndexOperationsAdapter.blocking(template.reactiveIndexOps(Venue.class))
.ensureIndex(new GeospatialIndex("location").typed(GeoSpatialIndexType.GEO_2D));
NearQuery geoFar = NearQuery.near(-73, 40, Metrics.KILOMETERS).num(10).maxDistance(150, Metrics.KILOMETERS);
@ -931,11 +922,11 @@ public class ReactiveMongoTemplateTests { @@ -931,11 +922,11 @@ public class ReactiveMongoTemplateTests {
@Test
public void savesJsonStringCorrectly() {
org.bson.Document dbObject = new org.bson.Document().append("first", "first").append("second", "second");
Document dbObject = new Document().append("first", "first").append("second", "second");
template.save(dbObject, "collection").block();
org.bson.Document result = template.findAll(org.bson.Document.class, "collection").next().block();
Document result = template.findAll(Document.class, "collection").next().block();
assertThat(result.containsKey("first"), is(true));
}

2
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/IndexInfoUnitTests.java

@ -36,7 +36,7 @@ public class IndexInfoUnitTests { @@ -36,7 +36,7 @@ public class IndexInfoUnitTests {
IndexField fooField = IndexField.create("foo", Direction.ASC);
IndexField barField = IndexField.create("bar", Direction.DESC);
IndexInfo info = new IndexInfo(Arrays.asList(fooField, barField), "myIndex", false, false, false, "");
IndexInfo info = new IndexInfo(Arrays.asList(fooField, barField), "myIndex", false, false, "");
assertThat(info.isIndexForFields(Arrays.asList("foo", "bar")), is(true));
}
}

13
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests.java

@ -37,7 +37,6 @@ import org.springframework.data.annotation.Id; @@ -37,7 +37,6 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.IndexDefinitionHolder;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
@ -64,8 +63,8 @@ public class MongoPersistentEntityIndexCreatorIntegrationTests { @@ -64,8 +63,8 @@ public class MongoPersistentEntityIndexCreatorIntegrationTests {
static final String SAMPLE_TYPE_COLLECTION_NAME = "sampleEntity";
static final String RECURSIVE_TYPE_COLLECTION_NAME = "recursiveGenericTypes";
public static @ClassRule RuleChain rules = RuleChain.outerRule(MongoVersionRule.atLeast(new Version(2, 6))).around(
CleanMongoDB.indexes(Arrays.asList(SAMPLE_TYPE_COLLECTION_NAME, RECURSIVE_TYPE_COLLECTION_NAME)));
public static @ClassRule RuleChain rules = RuleChain.outerRule(MongoVersionRule.atLeast(new Version(2, 6)))
.around(CleanMongoDB.indexes(Arrays.asList(SAMPLE_TYPE_COLLECTION_NAME, RECURSIVE_TYPE_COLLECTION_NAME)));
public @Rule ExpectedException expectedException = ExpectedException.none();
@ -113,11 +112,11 @@ public class MongoPersistentEntityIndexCreatorIntegrationTests { @@ -113,11 +112,11 @@ public class MongoPersistentEntityIndexCreatorIntegrationTests {
MongoPersistentEntityIndexCreator indexCreator = new MongoPersistentEntityIndexCreator(new MongoMappingContext(),
mongoTemplate);
indexCreator.createIndex(new IndexDefinitionHolder("dalinar.kohlin", new Index().named("stormlight")
.on("lastname", Direction.ASC).unique(), "datamongo-1125"));
indexCreator.createIndex(new IndexDefinitionHolder("dalinar.kohlin",
new Index().named("stormlight").on("lastname", Direction.ASC).unique(), "datamongo-1125"));
indexCreator.createIndex(new IndexDefinitionHolder("dalinar.kohlin", new Index().named("stormlight")
.on("lastname", Direction.ASC).sparse(), "datamongo-1125"));
indexCreator.createIndex(new IndexDefinitionHolder("dalinar.kohlin",
new Index().named("stormlight").on("lastname", Direction.ASC).sparse(), "datamongo-1125"));
}
@Document(collection = RECURSIVE_TYPE_COLLECTION_NAME)

165
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/performance/ReactivePerformanceTests.java

@ -18,8 +18,6 @@ package org.springframework.data.mongodb.performance; @@ -18,8 +18,6 @@ package org.springframework.data.mongodb.performance;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*;
import static org.springframework.util.Assert.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.text.DecimalFormat;
import java.util.ArrayList;
@ -43,9 +41,9 @@ import org.junit.Test; @@ -43,9 +41,9 @@ import org.junit.Test;
import org.springframework.core.Constants;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.convert.DbRefProxyHandler;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DbRefResolverCallback;
@ -70,10 +68,12 @@ import com.mongodb.reactivestreams.client.MongoClients; @@ -70,10 +68,12 @@ import com.mongodb.reactivestreams.client.MongoClients;
import com.mongodb.reactivestreams.client.MongoCollection;
import com.mongodb.reactivestreams.client.MongoDatabase;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* Test class to execute performance tests for plain Reactive Streams MongoDB driver usage, {@link ReactiveMongoOperations} and the repositories
* abstraction.
* Test class to execute performance tests for plain Reactive Streams MongoDB driver usage,
* {@link ReactiveMongoOperations} and the repositories abstraction.
*
* @author Mark Paluch
*/
@ -96,22 +96,25 @@ public class ReactivePerformanceTests { @@ -96,22 +96,25 @@ public class ReactivePerformanceTests {
@Before
public void setUp() throws Exception {
this.mongo = MongoClients.create();
mongo = MongoClients.create();
SimpleReactiveMongoDatabaseFactory mongoDbFactory = new SimpleReactiveMongoDatabaseFactory(this.mongo, DATABASE_NAME);
SimpleReactiveMongoDatabaseFactory mongoDbFactory = new SimpleReactiveMongoDatabaseFactory(this.mongo,
DATABASE_NAME);
MongoMappingContext context = new MongoMappingContext();
context.setInitialEntitySet(Collections.singleton(Person.class));
context.afterPropertiesSet();
this.converter = new MappingMongoConverter(new DbRefResolver() {
converter = new MappingMongoConverter(new DbRefResolver() {
@Override
public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback, DbRefProxyHandler proxyHandler) {
public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
DbRefProxyHandler proxyHandler) {
return null;
}
@Override
public DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation, MongoPersistentEntity<?> entity, Object id) {
public DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation,
MongoPersistentEntity<?> entity, Object id) {
return null;
}
@ -125,12 +128,12 @@ public class ReactivePerformanceTests { @@ -125,12 +128,12 @@ public class ReactivePerformanceTests {
return null;
}
}, context);
this.operations = new ReactiveMongoTemplate(mongoDbFactory, converter);
operations = new ReactiveMongoTemplate(mongoDbFactory, converter);
ReactiveMongoRepositoryFactory factory = new ReactiveMongoRepositoryFactory(operations);
factory.setConversionService(new GenericConversionService());
this.repository = factory.getRepository(ReactivePersonRepository.class);
repository = factory.getRepository(ReactivePersonRepository.class);
}
@ -139,24 +142,23 @@ public class ReactivePerformanceTests { @@ -139,24 +142,23 @@ public class ReactivePerformanceTests {
*/
@Test
public void writeWithWriteConcerns() {
executeWithWriteConcerns(new WriteConcernCallback() {
public void doWithWriteConcern(String constantName, WriteConcern concern) {
writeHeadline("WriteConcern: " + constantName);
System.out.println(String.format("Writing %s objects using plain driver took %sms", NUMBER_OF_PERSONS,
writingObjectsUsingPlainDriver(NUMBER_OF_PERSONS, concern)));
System.out.println(String.format("Writing %s objects using template took %sms", NUMBER_OF_PERSONS,
writingObjectsUsingMongoTemplate(NUMBER_OF_PERSONS, concern)));
System.out.println(String.format("Writing %s objects using repository took %sms", NUMBER_OF_PERSONS,
writingObjectsUsingRepositories(NUMBER_OF_PERSONS, concern)));
System.out.println(String.format("Writing %s objects async using plain driver took %sms", NUMBER_OF_PERSONS,
writingAsyncObjectsUsingPlainDriver(NUMBER_OF_PERSONS, concern)));
System.out.println(String.format("Writing %s objects async using template took %sms", NUMBER_OF_PERSONS,
writingAsyncObjectsUsingMongoTemplate(NUMBER_OF_PERSONS, concern)));
System.out.println(String.format("Writing %s objects async using repository took %sms", NUMBER_OF_PERSONS,
writingAsyncObjectsUsingRepositories(NUMBER_OF_PERSONS, concern)));
writeFooter();
}
executeWithWriteConcerns((constantName, concern) -> {
writeHeadline("WriteConcern: " + constantName);
System.out.println(String.format("Writing %s objects using plain driver took %sms", NUMBER_OF_PERSONS,
writingObjectsUsingPlainDriver(NUMBER_OF_PERSONS, concern)));
System.out.println(String.format("Writing %s objects using template took %sms", NUMBER_OF_PERSONS,
writingObjectsUsingMongoTemplate(NUMBER_OF_PERSONS, concern)));
System.out.println(String.format("Writing %s objects using repository took %sms", NUMBER_OF_PERSONS,
writingObjectsUsingRepositories(NUMBER_OF_PERSONS, concern)));
System.out.println(String.format("Writing %s objects async using plain driver took %sms", NUMBER_OF_PERSONS,
writingAsyncObjectsUsingPlainDriver(NUMBER_OF_PERSONS, concern)));
System.out.println(String.format("Writing %s objects async using template took %sms", NUMBER_OF_PERSONS,
writingAsyncObjectsUsingMongoTemplate(NUMBER_OF_PERSONS, concern)));
System.out.println(String.format("Writing %s objects async using repository took %sms", NUMBER_OF_PERSONS,
writingAsyncObjectsUsingRepositories(NUMBER_OF_PERSONS, concern)));
writeFooter();
});
}
@ -178,19 +180,15 @@ public class ReactivePerformanceTests { @@ -178,19 +180,15 @@ public class ReactivePerformanceTests {
private long convertDirectly(final List<Document> dbObjects) {
executeWatched(new WatchCallback<List<Person>>() {
@Override
public List<Person> doInWatch() {
List<Person> persons = new ArrayList<ReactivePerformanceTests.Person>();
executeWatched(() -> {
for (Document dbObject : dbObjects) {
persons.add(Person.from(new Document(dbObject)));
}
List<Person> persons = new ArrayList<Person>();
return persons;
for (Document dbObject : dbObjects) {
persons.add(Person.from(new Document(dbObject)));
}
return persons;
});
return watch.getLastTaskTimeMillis();
@ -198,19 +196,15 @@ public class ReactivePerformanceTests { @@ -198,19 +196,15 @@ public class ReactivePerformanceTests {
private long convertUsingConverter(final List<Document> dbObjects) {
executeWatched(new WatchCallback<List<Person>>() {
executeWatched(() -> {
@Override
public List<Person> doInWatch() {
List<Person> persons = new ArrayList<ReactivePerformanceTests.Person>();
for (Document dbObject : dbObjects) {
persons.add(converter.read(Person.class, dbObject));
}
List<Person> persons = new ArrayList<Person>();
return persons;
for (Document dbObject : dbObjects) {
persons.add(converter.read(Person.class, dbObject));
}
return persons;
});
return watch.getLastTaskTimeMillis();
@ -237,9 +231,12 @@ public class ReactivePerformanceTests { @@ -237,9 +231,12 @@ public class ReactivePerformanceTests {
statistics.registerTime(Api.TEMPLATE, Mode.WRITE, writingObjectsUsingMongoTemplate(numberOfPersons, concern));
statistics.registerTime(Api.REPOSITORY, Mode.WRITE, writingObjectsUsingRepositories(numberOfPersons, concern));
statistics.registerTime(Api.DRIVER, Mode.WRITE_ASYNC, writingAsyncObjectsUsingPlainDriver(numberOfPersons, concern));
statistics.registerTime(Api.TEMPLATE, Mode.WRITE_ASYNC, writingAsyncObjectsUsingMongoTemplate(numberOfPersons, concern));
statistics.registerTime(Api.REPOSITORY, Mode.WRITE_ASYNC, writingAsyncObjectsUsingRepositories(numberOfPersons, concern));
statistics.registerTime(Api.DRIVER, Mode.WRITE_ASYNC,
writingAsyncObjectsUsingPlainDriver(numberOfPersons, concern));
statistics.registerTime(Api.TEMPLATE, Mode.WRITE_ASYNC,
writingAsyncObjectsUsingMongoTemplate(numberOfPersons, concern));
statistics.registerTime(Api.REPOSITORY, Mode.WRITE_ASYNC,
writingAsyncObjectsUsingRepositories(numberOfPersons, concern));
statistics.registerTime(Api.DRIVER, Mode.READ, readingUsingPlainDriver());
statistics.registerTime(Api.TEMPLATE, Mode.READ, readingUsingTemplate());
@ -267,22 +264,16 @@ public class ReactivePerformanceTests { @@ -267,22 +264,16 @@ public class ReactivePerformanceTests {
}
private long queryUsingTemplate() {
executeWatched(new WatchCallback<List<Person>>() {
public List<Person> doInWatch() {
Query query = query(where("addresses.zipCode").regex(".*1.*"));
return operations.find(query, Person.class, "template").collectList().block();
}
executeWatched(() -> {
Query query = query(where("addresses.zipCode").regex(".*1.*"));
return operations.find(query, Person.class, "template").collectList().block();
});
return watch.getLastTaskTimeMillis();
}
private long queryUsingRepository() {
executeWatched(new WatchCallback<List<Person>>() {
public List<Person> doInWatch() {
return repository.findByAddressesZipCodeContaining("1").collectList().block();
}
});
executeWatched(() -> repository.findByAddressesZipCodeContaining("1").collectList().block());
return watch.getLastTaskTimeMillis();
}
@ -325,7 +316,8 @@ public class ReactivePerformanceTests { @@ -325,7 +316,8 @@ public class ReactivePerformanceTests {
private long writingObjectsUsingPlainDriver(int numberOfPersons, WriteConcern concern) {
final MongoCollection<Document> collection = mongo.getDatabase(DATABASE_NAME).getCollection("driver").withWriteConcern(concern);
final MongoCollection<Document> collection = mongo.getDatabase(DATABASE_NAME).getCollection("driver")
.withWriteConcern(concern);
final List<Person> persons = getPersonObjects(numberOfPersons);
executeWatched(new WatchCallback<Void>() {
@ -373,16 +365,18 @@ public class ReactivePerformanceTests { @@ -373,16 +365,18 @@ public class ReactivePerformanceTests {
return watch.getLastTaskTimeMillis();
}
private long writingAsyncObjectsUsingPlainDriver(int numberOfPersons, WriteConcern concern) {
final MongoCollection<Document> collection = mongo.getDatabase(DATABASE_NAME).getCollection("driver").withWriteConcern(concern);
final MongoCollection<Document> collection = mongo.getDatabase(DATABASE_NAME).getCollection("driver")
.withWriteConcern(concern);
final List<Person> persons = getPersonObjects(numberOfPersons);
executeWatched(new WatchCallback<Void>() {
public Void doInWatch() {
Flux.from(collection.insertMany(persons.stream().map(person -> new Document(person.toDocument())).collect(Collectors.toList()))).then().block();
Flux.from(collection
.insertMany(persons.stream().map(person -> new Document(person.toDocument())).collect(Collectors.toList())))
.then().block();
return null;
}
});
@ -408,7 +402,6 @@ public class ReactivePerformanceTests { @@ -408,7 +402,6 @@ public class ReactivePerformanceTests {
final List<Person> persons = getPersonObjects(numberOfPersons);
executeWatched(new WatchCallback<Void>() {
public Void doInWatch() {
operations.setWriteConcern(concern);
@ -417,53 +410,38 @@ public class ReactivePerformanceTests { @@ -417,53 +410,38 @@ public class ReactivePerformanceTests {
}
});
return watch.getLastTaskTimeMillis();
}
private long readingUsingPlainDriver() {
executeWatched(new WatchCallback<List<Person>>() {
public List<Person> doInWatch() {
return Flux.from(mongo.getDatabase(DATABASE_NAME).getCollection("driver").find()).map(Person::from).collectList().block();
}
});
executeWatched(() -> Flux.from(mongo.getDatabase(DATABASE_NAME).getCollection("driver").find()).map(Person::from)
.collectList().block());
return watch.getLastTaskTimeMillis();
}
private long readingUsingTemplate() {
executeWatched(new WatchCallback<List<Person>>() {
public List<Person> doInWatch() {
return operations.findAll(Person.class, "template").collectList().block();
}
});
executeWatched(() -> operations.findAll(Person.class, "template").collectList().block());
return watch.getLastTaskTimeMillis();
}
private long readingUsingRepository() {
executeWatched(new WatchCallback<List<Person>>() {
public List<Person> doInWatch() {
return repository.findAll().collectList().block();
}
});
executeWatched(() -> repository.findAll().collectList().block());
return watch.getLastTaskTimeMillis();
}
private long queryUsingPlainDriver() {
executeWatched(new WatchCallback<List<Person>>() {
public List<Person> doInWatch() {
executeWatched(() -> {
MongoCollection<Document> collection = mongo.getDatabase(DATABASE_NAME).getCollection("driver");
MongoCollection<Document> collection = mongo.getDatabase(DATABASE_NAME).getCollection("driver");
Document regex = new Document("$regex", Pattern.compile(".*1.*"));
Document query = new Document("addresses.zipCode", regex);
return Flux.from(collection.find(query)).map(Person::from).collectList().block();
}
Document regex = new Document("$regex", Pattern.compile(".*1.*"));
Document query = new Document("addresses.zipCode", regex);
return Flux.from(collection.find(query)).map(Person::from).collectList().block();
});
return watch.getLastTaskTimeMillis();
@ -755,8 +733,7 @@ public class ReactivePerformanceTests { @@ -755,8 +733,7 @@ public class ReactivePerformanceTests {
}
enum Mode {
WRITE, READ, QUERY,
WRITE_ASYNC
WRITE, READ, QUERY, WRITE_ASYNC
}
private static class Statistics {

3
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java

@ -57,6 +57,7 @@ import org.springframework.test.context.ContextConfiguration; @@ -57,6 +57,7 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import lombok.NoArgsConstructor;
import org.springframework.util.ClassUtils;
import reactor.core.Cancellation;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -83,7 +84,7 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF @@ -83,7 +84,7 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader == null ? org.springframework.util.ClassUtils.getDefaultClassLoader() : classLoader;
this.classLoader = classLoader == null ? ClassUtils.getDefaultClassLoader() : classLoader;
}
@Override

3
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/SimpleReactiveMongoRepositoryTests.java

@ -43,6 +43,7 @@ import org.springframework.data.mongodb.repository.support.SimpleReactiveMongoRe @@ -43,6 +43,7 @@ import org.springframework.data.mongodb.repository.support.SimpleReactiveMongoRe
import org.springframework.data.repository.query.DefaultEvaluationContextProvider;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.ClassUtils;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -70,7 +71,7 @@ public class SimpleReactiveMongoRepositoryTests implements BeanClassLoaderAware, @@ -70,7 +71,7 @@ public class SimpleReactiveMongoRepositoryTests implements BeanClassLoaderAware,
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader == null ? org.springframework.util.ClassUtils.getDefaultClassLoader() : classLoader;
this.classLoader = classLoader == null ? ClassUtils.getDefaultClassLoader() : classLoader;
}
@Override

3
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/ReactiveStringBasedMongoQueryUnitTests.java

@ -138,7 +138,8 @@ public class ReactiveStringBasedMongoQueryUnitTests { @@ -138,7 +138,8 @@ public class ReactiveStringBasedMongoQueryUnitTests {
@Test
public void shouldSupportFindByParameterizedCriteriaAndFields() throws Exception {
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, new Document("firstname", "first").append("lastname", "last"), Collections.singletonMap("lastname", 1));
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter,
new Document("firstname", "first").append("lastname", "last"), Collections.singletonMap("lastname", 1));
ReactiveStringBasedMongoQuery mongoQuery = createQueryForMethod("findByParameterizedCriteriaAndFields",
Document.class, Map.class);

4
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/ReactivePageImplUnitTests.java

@ -21,7 +21,6 @@ import static org.junit.Assert.*; @@ -21,7 +21,6 @@ import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.mongodb.repository.support.ReactivePageImpl;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -64,7 +63,8 @@ public class ReactivePageImplUnitTests { @@ -64,7 +63,8 @@ public class ReactivePageImplUnitTests {
@Test
public void returnsContentBoundedByPageSize() {
Page<Object> page = new ReactivePageImpl<>(Flux.just(new Object(), new Object()), new PageRequest(0, 1), Mono.just(10L));
Page<Object> page = new ReactivePageImpl<>(Flux.just(new Object(), new Object()), new PageRequest(0, 1),
Mono.just(10L));
assertThat(page.getContent(), hasSize(1));
assertThat(page.hasNext(), is(true));

8
src/main/asciidoc/reference/reactive-mongo-repositories.adoc

@ -11,7 +11,7 @@ This chapter will point out the specialties for reactive repository support for @@ -11,7 +11,7 @@ This chapter will point out the specialties for reactive repository support for
The reactive space offers various reactive composition libraries. The most common libraries are https://github.com/ReactiveX/RxJava[RxJava] and https://projectreactor.io/[Project Reactor].
Spring Data MongoDB is built on top of the MongoDB Reactive Streams driver to provide maximal interoperability relying on the http://www.reactive-streams.org/[Reactive Streams] initiative. Static APIs such as `ReactiveMongoOperations` are provided by using Project Reactor's `Flux` and `Mono` types. Project Reactor offers various adapters to convert reactive wrapper types (`Flux` to `Observable` and vice versa) but conversion can easily clutter your code.
Spring Data MongoDB is built on top of the https://mongodb.github.io/mongo-java-driver-reactivestreams/[MongoDB Reactive Streams] driver to provide maximal interoperability relying on the http://www.reactive-streams.org/[Reactive Streams] initiative. Static APIs such as `ReactiveMongoOperations` are provided by using Project Reactor's `Flux` and `Mono` types. Project Reactor offers various adapters to convert reactive wrapper types (`Flux` to `Observable` and vice versa) but conversion can easily clutter your code.
Spring Data's Repository abstraction is a dynamic API, mostly defined by you and your requirements, as you're declaring query methods. Reactive MongoDB repositories can be either implemented using RxJava or Project Reactor wrapper types by simply extending from one of the library-specific repository interfaces:
@ -99,21 +99,17 @@ As our domain repository extends `ReactivePagingAndSortingRepository` it provide @@ -99,21 +99,17 @@ As our domain repository extends `ReactivePagingAndSortingRepository` it provide
====
[source,java]
----
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class PersonRepositoryTests {
@Autowired ReactivePersonRepository repository;
@Test
public void readsFirstPageCorrectly() {
Mono<Page<Person>> persons = repository.findAll(new PageRequest(0, 10));
}
@Test
public void readsFirstPageAsStream() {
Flux<Person> persons = repository.findAll(new PageRequest(0, 10));
}
}
@ -136,7 +132,7 @@ Following features are supported: @@ -136,7 +132,7 @@ Following features are supported:
* <<mongodb.repositories.queries.full-text>>
* <<projections>>
Reactive Repositories do not support Type-safe Query methods using QueryDSL.
WARNING: Reactive Repositories do not support Type-safe Query methods using Querydsl.
[[mongodb.reactive.repositories.queries.geo-spatial]]
=== Geo-spatial repository queries

96
src/main/asciidoc/reference/reactive-mongodb.adoc

@ -3,13 +3,13 @@ @@ -3,13 +3,13 @@
The reactive MongoDB support contains a basic set of features which are summarized below.
* Spring configuration support using Java based @Configuration classes a Mongo client instance and replica sets
* `ReactiveMongoTemplate` helper class that increases productivity using Mongo operations in a reactive manner. Includes integrated object mapping between documents and POJOs.
* Exception translation into Spring's portable Data Access Exception hierarchy
* Feature Rich Object Mapping integrated with Spring's Conversion Service
* Annotation based mapping metadata but extensible to support other metadata formats
* Persistence and mapping lifecycle events
* Java based Query, Criteria, and Update DSLs
* Spring configuration support using Java based `@Configuration` classes a `MongoClient` instance and replica sets.
* `ReactiveMongoTemplate` helper class that increases productivity using `MongoOperations in a reactive manner. Includes integrated object mapping between `Documents and POJOs.
* Exception translation into Spring's portable Data Access Exception hierarchy.
* Feature Rich Object Mapping integrated with Spring's `ConversionService`.
* Annotation based mapping metadata but extensible to support other metadata formats.
* Persistence and mapping lifecycle events.
* Java based `Query`, `Criteria`, and `Update` DSLs.
* Automatic implementation of reactive Repository interfaces including support for custom finder methods.
For most tasks you will find yourself using `ReactiveMongoTemplate` or the Repository support that both leverage the rich mapping functionality. `ReactiveMongoTemplate` is the place to look for accessing functionality such as incrementing counters or ad-hoc CRUD operations. `ReactiveMongoTemplate` also provides callback methods so that it is easy for you to get a hold of the low level API artifacts such as `MongoDatabase` to communicate directly with MongoDB. The goal with naming conventions on various API artifacts is to copy those in the base MongoDB Java driver so you can easily map your existing knowledge onto the Spring APIs.
@ -54,12 +54,11 @@ Then add the following to pom.xml dependencies section. @@ -54,12 +54,11 @@ Then add the following to pom.xml dependencies section.
NOTE: MongoDB uses two different drivers for blocking and reactive (non-blocking) data access. While blocking operations are provided by default, you're have to opt-in for reactive usage.
Create a simple Person class to persist:
Create a simple `Person` class to persist:
[source,java]
----
package org.spring.mongodb.example;
@Document
public class Person {
private String id;
@ -92,17 +91,6 @@ And a main application to run @@ -92,17 +91,6 @@ And a main application to run
[source,java]
----
package org.spring.mongodb.example;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import com.mongodb.reactivestreams.client.MongoClients;
public class ReactiveMongoApp {
private static final Logger log = LoggerFactory.getLogger(ReactiveMongoApp.class);
@ -114,15 +102,10 @@ public class ReactiveMongoApp { @@ -114,15 +102,10 @@ public class ReactiveMongoApp {
ReactiveMongoTemplate mongoOps = new ReactiveMongoTemplate(MongoClients.create(), "database");
mongoOps.insert(new Person("Joe", 34))
.flatMap(p -> mongoOps.findOne(new Query(where("name").is("Joe")), Person.class))
.doOnNext(person -> log.info(person.toString()))
.flatMap(person -> mongoOps.dropCollection("person"))
.doOnComplete(latch::countDown)
.subscribe();
latch.await();
@ -181,7 +164,7 @@ public class AppConfig { @@ -181,7 +164,7 @@ public class AppConfig {
This approach allows you to use the standard `com.mongodb.reactivestreams.client.MongoClient` API that you may already be used to using.
An alternative is to register an instance of `com.mongodb.reactivestreams.client.MongoClient` instance with the container using Spring's `ReactiveMongoClientFactoryBean`. As compared to instantiating a `com.mongodb.reactivestreams.client.MongoClient` instance directly, the FactoryBean approach has the added advantage of also providing the container with an ExceptionTranslator implementation that translates MongoDB exceptions to exceptions in Spring's portable `DataAccessException` hierarchy for data access classes annotated with the `@Repository` annotation. This hierarchy and use of `@Repository` is described in http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/dao.html[Spring's DAO support features].
An alternative is to register an instance of `com.mongodb.reactivestreams.client.MongoClient` instance with the container using Spring's `ReactiveMongoClientFactoryBean`. As compared to instantiating a `com.mongodb.reactivestreams.client.MongoClient` instance directly, the FactoryBean approach has the added advantage of also providing the container with an `ExceptionTranslator` implementation that translates MongoDB exceptions to exceptions in Spring's portable `DataAccessException` hierarchy for data access classes annotated with the `@Repository` annotation. This hierarchy and use of `@Repository` is described in http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/dao.html[Spring's DAO support features].
An example of a Java based bean metadata that supports exception translation on `@Repository` annotated classes is shown below:
@ -197,16 +180,16 @@ public class AppConfig { @@ -197,16 +180,16 @@ public class AppConfig {
*/
public @Bean ReactiveMongoClientFactoryBean mongoClient() {
ReactiveMongoClientFactoryBean mongoClient = new ReactiveMongoClientFactoryBean();
mongoClient.setHost("localhost");
ReactiveMongoClientFactoryBean clientFactory = new ReactiveMongoClientFactoryBean();
clientFactory.setHost("localhost");
return mongoClient;
return clientFactory;
}
}
----
====
To access the `com.mongodb.reactivestreams.client.MongoClient` object created by the `ReactiveMongoClientFactoryBean` in other `@Configuration` or your own classes, use a `private @Autowired MongoClient mongoClient;` field.
To access the `com.mongodb.reactivestreams.client.MongoClient` object created by the `ReactiveMongoClientFactoryBean` in other `@Configuration` or your own classes, just obtain the `MongoClient` from the context.
[[mongo.mongo-db-factory]]
@ -246,7 +229,7 @@ public interface ReactiveMongoDatabaseFactory { @@ -246,7 +229,7 @@ public interface ReactiveMongoDatabaseFactory {
The class `org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory` provides implements the ReactiveMongoDatabaseFactory interface and is created with a standard `com.mongodb.reactivestreams.client.MongoClient` instance and the database name.
Instead of using the IoC container to create an instance of ReactiveMongoTemplate, you can just use them in standard Java code as shown below.
Instead of using the IoC container to create an instance of `ReactiveMongoTemplate`, you can just use them in standard Java code as shown below.
[source,java]
----
@ -256,27 +239,23 @@ public class MongoApp { @@ -256,27 +239,23 @@ public class MongoApp {
public static void main(String[] args) throws Exception {
ReactiveMongoOperations mongoOps = new ReactiveMongoOperations(*new SimpleReactiveMongoDatabaseFactory(MongoClient.create(), "database")*);
ReactiveMongoOperations mongoOps = new ReactiveMongoOperations(new SimpleReactiveMongoDatabaseFactory(MongoClient.create(), "database"));
mongoOps.insert(new Person("Joe", 34))
.flatMap(p -> mongoOps.findOne(new Query(where("name").is("Joe")), Person.class))
.doOnNext(person -> log.info(person.toString()))
.flatMap(person -> mongoOps.dropCollection("person"))
.subscribe();
}
}
----
The code in bold highlights the use of SimpleMongoDbFactory and is the only difference between the listing shown in the <<mongodb-reactive-getting-started,getting started section>>.
The use of `SimpleMongoDbFactory` is the only difference between the listing shown in the <<mongodb-reactive-getting-started,getting started section>>.
[[mongo.mongo-db-factory-java]]
=== Registering a ReactiveMongoDatabaseFactory instance using Java based metadata
To register a ReactiveMongoDatabaseFactory instance with the container, you write code much like what was highlighted in the previous code listing. A simple example is shown below
To register a `ReactiveMongoDatabaseFactory` instance with the container, you write code much like what was highlighted in the previous code listing. A simple example is shown below
[source,java]
----
@ -315,7 +294,7 @@ NOTE: Once configured, `ReactiveMongoTemplate` is thread-safe and can be reused @@ -315,7 +294,7 @@ NOTE: Once configured, `ReactiveMongoTemplate` is thread-safe and can be reused
The mapping between MongoDB documents and domain classes is done by delegating to an implementation of the interface `MongoConverter`. Spring provides a default implementation with `MongoMappingConverter`, but you can also write your own converter. Please refer to the section on MongoConverters for more detailed information.
The `ReactiveMongoTemplate` class implements the interface `ReactiveMongoOperations`. In as much as possible, the methods on `ReactiveMongoOperations` are named after methods available on the MongoDB driver `Collection` object as as to make the API familiar to existing MongoDB developers who are used to the driver API. For example, you will find methods such as "find", "findAndModify", "findOne", "insert", "remove", "save", "update" and "updateMulti". The design goal was to make it as easy as possible to transition between the use of the base MongoDB driver and `ReactiveMongoOperations`. A major difference in between the two APIs is that ReactiveMongoOperations can be passed domain objects instead of `Document` and there are fluent APIs for `Query`, `Criteria`, and `Update` operations instead of populating a `Document` to specify the parameters for those operations.
The `ReactiveMongoTemplate` class implements the interface `ReactiveMongoOperations`. In as much as possible, the methods on `ReactiveMongoOperations` are named after methods available on the MongoDB driver `Collection` object as as to make the API familiar to existing MongoDB developers who are used to the driver API. For example, you will find methods such as "find", "findAndModify", "findOne", "insert", "remove", "save", "update" and "updateMulti". The design goal was to make it as easy as possible to transition between the use of the base MongoDB driver and `ReactiveMongoOperations`. A major difference in between the two APIs is that `ReactiveMongoOperations` can be passed domain objects instead of `Document` and there are fluent APIs for `Query`, `Criteria`, and `Update` operations instead of populating a `Document` to specify the parameters for those operations.
NOTE: The preferred way to reference the operations on `ReactiveMongoTemplate` instance is via its interface `ReactiveMongoOperations`.
@ -350,7 +329,7 @@ public class AppConfig { @@ -350,7 +329,7 @@ public class AppConfig {
----
====
There are several overloaded constructors of ReactiveMongoTemplate. These are
There are several overloaded constructors of `ReactiveMongoTemplate`. These are
* `ReactiveMongoTemplate(MongoClient mongo, String databaseName)` - takes the `com.mongodb.Mongo` object and the default database name to operate against.
* `ReactiveMongoTemplate(ReactiveMongoDatabaseFactory mongoDatabaseFactory)` - takes a ReactiveMongoDatabaseFactory object that encapsulated the `com.mongodb.reactivestreams.client.MongoClient` object and database name.
@ -364,13 +343,13 @@ NOTE: The preferred way to reference the operations on `ReactiveMongoTemplate` i @@ -364,13 +343,13 @@ NOTE: The preferred way to reference the operations on `ReactiveMongoTemplate` i
[[mongo.reactive.template.writeresultchecking]]
=== WriteResultChecking Policy
When in development it is very handy to either log or throw an exception if the `com.mongodb.WriteResult` returned from any MongoDB operation contains an error. It is quite common to forget to do this during development and then end up with an application that looks like it runs successfully but in fact the database was not modified according to your expectations. Set MongoTemplate's property to an enum with the following values, `LOG`, `EXCEPTION`, or `NONE` to either log the error, throw and exception or do nothing. The default is to use a `WriteResultChecking` value of `NONE`.
When in development it is very handy to either log or throw an `Exception` if the `com.mongodb.WriteResult` returned from any MongoDB operation contains an error. It is quite common to forget to do this during development and then end up with an application that looks like it runs successfully but in fact the database was not modified according to your expectations. Set MongoTemplate's property to an enum with the following values, `LOG`, `EXCEPTION`, or `NONE` to either log the error, throw and exception or do nothing. The default is to use a `WriteResultChecking` value of `NONE`.
[[mongo.reactive.template.writeconcern]]
=== WriteConcern
You can set the `com.mongodb.WriteConcern` property that the `ReactiveMongoTemplate` will use for write operations if it has not yet been specified via the driver at a higher level such as `MongoDatabase`. If ReactiveMongoTemplate's `WriteConcern` property is not set it will default to the one set in the MongoDB driver's DB or Collection setting.
You can set the `com.mongodb.WriteConcern` property that the `ReactiveMongoTemplate` will use for write operations if it has not yet been specified via the driver at a higher level such as `MongoDatabase`. If ReactiveMongoTemplate's `WriteConcern` property is not set it will default to the one set in the MongoDB driver's `MongoDatabase` or `MongoCollection` setting.
[[mongo.reactive.template.writeconcernresolver]]
@ -445,17 +424,6 @@ You can save, update and delete the object as shown below. @@ -445,17 +424,6 @@ You can save, update and delete the object as shown below.
[source,java]
----
package org.spring.mongodb.example;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import com.mongodb.reactivestreams.client.MongoClients;
public class ReactiveMongoApp {
private static final Logger log = LoggerFactory.getLogger(ReactiveMongoApp.class);
@ -467,15 +435,10 @@ public class ReactiveMongoApp { @@ -467,15 +435,10 @@ public class ReactiveMongoApp {
ReactiveMongoTemplate mongoOps = new ReactiveMongoTemplate(MongoClients.create(), "database");
mongoOps.insert(new Person("Joe", 34)).doOnNext(person -> log.info("Insert: " + person))
.flatMap(person -> mongoOps.findById(person.getId(), Person.class))
.doOnNext(person -> log.info("Found: " + person))
.zipWith(person -> mongoOps.updateFirst(query(where("name").is("Joe")), update("age", 35), Person.class))
.flatMap(tuple -> mongoOps.remove(tuple.getT1())).flatMap(deleteResult -> mongoOps.findAll(Person.class))
.count().doOnSuccess(count -> {
log.info("Number of people: " + count);
latch.countDown();
@ -529,14 +492,9 @@ Here is an example that uses the `ReactiveCollectionCallback` to return informat @@ -529,14 +492,9 @@ Here is an example that uses the `ReactiveCollectionCallback` to return informat
[source,java]
----
Flux<Boolean> hasIndex = template.execute("geolocation", collection -> {
List<IndexInfo> indexes = template.indexOps(collection.getNamespace().getCollectionName()).getIndexInfo();
for (IndexInfo dbo : indexes) {
if ("location_2d".equals(dbo.getName())) {
return Mono.just(true);
}
}
return Mono.just(false);
});
Flux<Boolean> hasIndex = operations.execute("geolocation",
collection -> Flux.from(collection.listIndexes(Document.class))
.filter(document -> document.get("name").equals("fancy-index-name"))
.flatMap(document -> Mono.just(true))
.defaultIfEmpty(false));
----

Loading…
Cancel
Save