diff --git a/pom.xml b/pom.xml index 28dc5c96c1..559135fc86 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2150-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml index c2ff37b35c..0d41356f05 100644 --- a/spring-data-mongodb-benchmarks/pom.xml +++ b/spring-data-mongodb-benchmarks/pom.xml @@ -7,7 +7,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2150-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index fd36f227c0..515ae238e6 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -6,7 +6,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2150-SNAPSHOT ../pom.xml @@ -50,7 +50,7 @@ org.springframework.data spring-data-mongodb - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2150-SNAPSHOT diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index cb441dd8ef..ce6db1514a 100644 --- a/spring-data-mongodb-distribution/pom.xml +++ b/spring-data-mongodb-distribution/pom.xml @@ -13,7 +13,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2150-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index f3c85a046a..fde95d0c26 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -11,7 +11,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2150-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java index 0ea20fbf82..470bf84d96 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java @@ -395,7 +395,7 @@ public Mono executeCommand(String jsonCommand) { * (non-Javadoc) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#executeCommand(org.bson.Document) */ - public Mono executeCommand(final Document command) { + public Mono executeCommand(Document command) { return executeCommand(command, null); } @@ -403,7 +403,7 @@ public Mono executeCommand(final Document command) { * (non-Javadoc) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#executeCommand(org.bson.Document, com.mongodb.ReadPreference) */ - public Mono executeCommand(final Document command, @Nullable ReadPreference readPreference) { + public Mono executeCommand(Document command, @Nullable ReadPreference readPreference) { Assert.notNull(command, "Command must not be null!"); @@ -552,7 +552,7 @@ public Flux createFlux(ReactiveDatabaseCallback callback) { * @param callback must not be {@literal null} * @return a {@link Mono} wrapping the {@link ReactiveDatabaseCallback}. */ - public Mono createMono(final ReactiveDatabaseCallback callback) { + public Mono createMono(ReactiveDatabaseCallback callback) { Assert.notNull(callback, "ReactiveDatabaseCallback must not be null!"); @@ -637,7 +637,7 @@ public Mono> createCollection(String collectionName, * (non-Javadoc) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#getCollection(java.lang.String) */ - public MongoCollection getCollection(final String collectionName) { + public MongoCollection getCollection(String collectionName) { return execute((MongoDatabaseCallback>) db -> db.getCollection(collectionName)); } @@ -653,7 +653,7 @@ public Mono collectionExists(Class entityClass) { * (non-Javadoc) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#collectionExists(java.lang.String) */ - public Mono collectionExists(final String collectionName) { + public Mono collectionExists(String collectionName) { return createMono(db -> Flux.from(db.listCollectionNames()) // .filter(s -> s.equals(collectionName)) // .map(s -> true) // @@ -672,7 +672,7 @@ public Mono dropCollection(Class entityClass) { * (non-Javadoc) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#dropCollection(java.lang.String) */ - public Mono dropCollection(final String collectionName) { + public Mono dropCollection(String collectionName) { return createMono(collectionName, MongoCollection::drop).doOnSuccess(success -> { if (LOGGER.isDebugEnabled()) { @@ -1005,15 +1005,15 @@ protected Flux> geoNear(NearQuery near, Class entityClass, S } String collection = StringUtils.hasText(collectionName) ? collectionName : determineCollectionName(entityClass); - Document nearDbObject = near.toDocument(); + Document nearDocument = near.toDocument(); Document command = new Document("geoNear", collection); - command.putAll(nearDbObject); + command.putAll(nearDocument); return Flux.defer(() -> { - if (nearDbObject.containsKey("query")) { - Document query = (Document) nearDbObject.get("query"); + if (nearDocument.containsKey("query")) { + Document query = (Document) nearDocument.get("query"); command.put("query", queryMapper.getMappedObject(query, getPersistentEntity(entityClass))); } @@ -1022,7 +1022,7 @@ protected Flux> geoNear(NearQuery near, Class entityClass, S entityClass, collectionName); } - GeoNearResultDbObjectCallback callback = new GeoNearResultDbObjectCallback<>( + GeoNearResultDocumentCallback callback = new GeoNearResultDocumentCallback<>( new ProjectingReadCallback<>(mongoConverter, entityClass, returnType, collectionName), near.getMetric()); return executeCommand(command, this.readPreference).flatMapMany(document -> { @@ -1143,7 +1143,7 @@ public Mono count(Query query, Class entityClass) { * (non-Javadoc) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#count(org.springframework.data.mongodb.core.query.Query, java.lang.String) */ - public Mono count(final Query query, String collectionName) { + public Mono count(Query query, String collectionName) { return count(query, null, collectionName); } @@ -1234,23 +1234,22 @@ public Mono insert(T objectToSave, String collectionName) { protected Mono doInsert(String collectionName, T objectToSave, MongoWriter writer) { - assertUpdateableIdIfNotSet(objectToSave); - return Mono.defer(() -> { - AdaptibleEntity entity = operations.forEntity(objectToSave, mongoConverter.getConversionService()); - T toSave = entity.initializeVersionProperty(); - - maybeEmitEvent(new BeforeConvertEvent<>(toSave, collectionName)); + BeforeConvertEvent event = new BeforeConvertEvent<>(objectToSave, collectionName); + T toConvert = maybeEmitEvent(event).getSource(); + AdaptibleEntity entity = operations.forEntity(toConvert, mongoConverter.getConversionService()); + entity.assertUpdateableIdIfNotSet(); + T initialized = entity.initializeVersionProperty(); Document dbDoc = entity.toMappedDocument(writer).getDocument(); - maybeEmitEvent(new BeforeSaveEvent<>(toSave, dbDoc, collectionName)); + maybeEmitEvent(new BeforeSaveEvent<>(initialized, dbDoc, collectionName)); - Mono afterInsert = insertDBObject(collectionName, dbDoc, toSave.getClass()).map(id -> { + Mono afterInsert = insertDocument(collectionName, dbDoc, initialized.getClass()).map(id -> { T saved = entity.populateIdIfNecessary(id); - maybeEmitEvent(new AfterSaveEvent<>(saved, dbDoc, collectionName)); + maybeEmitEvent(new AfterSaveEvent<>(initialized, dbDoc, collectionName)); return saved; }); @@ -1293,7 +1292,7 @@ public Flux insertAll(Mono> objectsToSa protected Flux doInsertAll(Collection listToSave, MongoWriter writer) { - final Map> elementsByCollection = new HashMap<>(); + Map> elementsByCollection = new HashMap<>(); listToSave.forEach(element -> { @@ -1309,8 +1308,8 @@ protected Flux doInsertAll(Collection listToSave, MongoWrite .flatMap(collectionName -> doInsertBatch(collectionName, elementsByCollection.get(collectionName), writer)); } - protected Flux doInsertBatch(final String collectionName, final Collection batchToSave, - final MongoWriter writer) { + protected Flux doInsertBatch(String collectionName, Collection batchToSave, + MongoWriter writer) { Assert.notNull(writer, "MongoWriter must not be null!"); @@ -1330,9 +1329,9 @@ protected Flux doInsertBatch(final String collectionName, final Collectio Flux, Document>> insertDocuments = prepareDocuments.flatMapMany(tuples -> { - List dbObjects = tuples.stream().map(Tuple2::getT2).collect(Collectors.toList()); + List documents = tuples.stream().map(Tuple2::getT2).collect(Collectors.toList()); - return insertDocumentList(collectionName, dbObjects).thenMany(Flux.fromIterable(tuples)); + return insertDocumentList(collectionName, documents).thenMany(Flux.fromIterable(tuples)); }); return insertDocuments.map(tuple -> { @@ -1388,34 +1387,27 @@ public Mono save(T objectToSave, String collectionName) { Assert.notNull(objectToSave, "Object to save must not be null!"); Assert.hasText(collectionName, "Collection name must not be null or empty!"); - MongoPersistentEntity mongoPersistentEntity = getPersistentEntity(objectToSave.getClass()); - - // No optimistic locking -> simple save - if (mongoPersistentEntity == null || !mongoPersistentEntity.hasVersionProperty()) { - return doSave(collectionName, objectToSave, this.mongoConverter); - } + AdaptibleEntity source = operations.forEntity(objectToSave, mongoConverter.getConversionService()); - return doSaveVersioned(objectToSave, mongoPersistentEntity, collectionName); + return source.isVersionedEntity() ? doSaveVersioned(source, collectionName) + : doSave(collectionName, objectToSave, this.mongoConverter); } - private Mono doSaveVersioned(T objectToSave, MongoPersistentEntity entity, String collectionName) { + private Mono doSaveVersioned(AdaptibleEntity source, String collectionName) { - AdaptibleEntity forEntity = operations.forEntity(objectToSave, mongoConverter.getConversionService()); + if (source.isNew()) { + return doInsert(collectionName, source.getBean(), this.mongoConverter); + } return createMono(collectionName, collection -> { - Number versionNumber = forEntity.getVersion(); + // Create query for entity with the id and old version + Query query = source.getQueryForVersion(); - // Fresh instance -> initialize version property - if (versionNumber == null) { - return doInsert(collectionName, objectToSave, mongoConverter); - } - - forEntity.assertUpdateableIdIfNotSet(); + // Bump version number + T toSave = source.incrementVersion(); - Query query = forEntity.getQueryForVersion(); - - T toSave = forEntity.incrementVersion(); + source.assertUpdateableIdIfNotSet(); BeforeConvertEvent event = new BeforeConvertEvent<>(toSave, collectionName); T afterEvent = ReactiveMongoTemplate.this.maybeEmitEvent(event).getSource(); @@ -1426,7 +1418,9 @@ private Mono doSaveVersioned(T objectToSave, MongoPersistentEntity ent ReactiveMongoTemplate.this.maybeEmitEvent(new BeforeSaveEvent<>(afterEvent, document, collectionName)); return doUpdate(collectionName, query, mapped.updateWithoutId(), afterEvent.getClass(), false, false) - .map(updateResult -> maybeEmitEvent(new AfterSaveEvent(afterEvent, document, collectionName)).getSource()); + .map(result -> { + return maybeEmitEvent(new AfterSaveEvent(afterEvent, document, collectionName)).getSource(); + }); }); } @@ -1450,7 +1444,7 @@ protected Mono doSave(String collectionName, T objectToSave, MongoWriter< }); } - protected Mono insertDBObject(final String collectionName, final Document dbDoc, final Class entityClass) { + protected Mono insertDocument(String collectionName, Document dbDoc, Class entityClass) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Inserting Document containing fields: " + dbDoc.keySet() + " in collection: " + collectionName); @@ -1472,17 +1466,17 @@ protected Mono insertDBObject(final String collectionName, final Documen return Flux.from(execute).last().map(success -> MappedDocument.of(document).getId()); } - protected Flux insertDocumentList(final String collectionName, final List dbDocList) { + protected Flux insertDocumentList(String collectionName, List dbDocList) { if (dbDocList.isEmpty()) { return Flux.empty(); } if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Inserting list of DBObjects containing " + dbDocList.size() + " items"); + LOGGER.debug("Inserting list of Documents containing " + dbDocList.size() + " items"); } - final List documents = new ArrayList<>(); + List documents = new ArrayList<>(); return execute(collectionName, collection -> { @@ -1514,8 +1508,7 @@ private MongoCollection prepareCollection(MongoCollection co return collectionToUse; } - protected Mono saveDocument(final String collectionName, final Document document, - final Class entityClass) { + protected Mono saveDocument(String collectionName, Document document, Class entityClass) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Saving Document containing fields: " + document.keySet()); @@ -1577,7 +1570,7 @@ public Mono updateFirst(Query query, Update update, Class entit * (non-Javadoc) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#updateFirst(org.springframework.data.mongodb.core.query.Query, org.springframework.data.mongodb.core.query.Update, java.lang.String) */ - public Mono updateFirst(final Query query, final Update update, final String collectionName) { + public Mono updateFirst(Query query, Update update, String collectionName) { return doUpdate(collectionName, query, update, null, false, false); } @@ -1601,7 +1594,7 @@ public Mono updateMulti(Query query, Update update, Class entit * (non-Javadoc) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#updateMulti(org.springframework.data.mongodb.core.query.Query, org.springframework.data.mongodb.core.query.Update, java.lang.String) */ - public Mono updateMulti(final Query query, final Update update, String collectionName) { + public Mono updateMulti(Query query, Update update, String collectionName) { return doUpdate(collectionName, query, update, null, false, true); } @@ -1609,13 +1602,12 @@ public Mono updateMulti(final Query query, final Update update, St * (non-Javadoc) * @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 updateMulti(final Query query, final Update update, Class entityClass, - String collectionName) { + public Mono updateMulti(Query query, Update update, Class entityClass, String collectionName) { return doUpdate(collectionName, query, update, entityClass, false, true); } - protected Mono doUpdate(final String collectionName, Query query, @Nullable Update update, - @Nullable Class entityClass, final boolean upsert, final boolean multi) { + protected Mono doUpdate(String collectionName, Query query, @Nullable Update update, + @Nullable Class entityClass, boolean upsert, boolean multi) { MongoPersistentEntity entity = entityClass == null ? null : getPersistentEntity(entityClass); @@ -1661,7 +1653,7 @@ protected Mono doUpdate(final String collectionName, Query query, : queryMapper.getMappedObject(query.getQueryObject(), entity); Document updateObj = update == null ? new Document() : updateMapper.getMappedObject(update.getUpdateObject(), entity); - if (dbObjectContainsVersionProperty(queryObj, entity)) + if (containsVersionProperty(queryObj, entity)) throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: " + updateObj.toString() + " to collection " + collectionName); } @@ -1681,8 +1673,7 @@ private void increaseVersionForUpdateIfNecessary(@Nullable MongoPersistentEntity } } - private boolean dbObjectContainsVersionProperty(Document document, - @Nullable MongoPersistentEntity persistentEntity) { + private boolean containsVersionProperty(Document document, @Nullable MongoPersistentEntity persistentEntity) { if (persistentEntity == null || !persistentEntity.hasVersionProperty()) { return false; @@ -1785,8 +1776,8 @@ protected Mono doRemove(String collectionName, Query query, @N Assert.hasText(collectionName, "Collection name must not be null or empty!"); - final Document queryObject = query.getQueryObject(); - final MongoPersistentEntity entity = getPersistentEntity(entityClass); + Document queryObject = query.getQueryObject(); + MongoPersistentEntity entity = getPersistentEntity(entityClass); return execute(collectionName, collection -> { @@ -1797,7 +1788,7 @@ protected Mono doRemove(String collectionName, Query query, @N MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.REMOVE, collectionName, entityClass, null, removeQuey); - final DeleteOptions deleteOptions = new DeleteOptions(); + DeleteOptions deleteOptions = new DeleteOptions(); query.getCollation().map(Collation::toMongoCollation).ifPresent(deleteOptions::collation); WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction); @@ -2152,8 +2143,8 @@ protected Flux doFindAndDelete(String collectionName, Query query, Class< * @param collectionOptions * @return the collection that was created */ - protected Mono> doCreateCollection(final String collectionName, - final CreateCollectionOptions collectionOptions) { + protected Mono> doCreateCollection(String collectionName, + CreateCollectionOptions collectionOptions) { return createMono(db -> db.createCollection(collectionName, collectionOptions)).map(success -> { @@ -2590,17 +2581,6 @@ private MongoPersistentEntity getPersistentEntity(@Nullable Class type) { return type == null ? null : mappingContext.getPersistentEntity(type); } - @Nullable - private MongoPersistentProperty getIdPropertyFor(@Nullable Class type) { - - if (type == null) { - return null; - } - - MongoPersistentEntity persistentEntity = mappingContext.getPersistentEntity(type); - return persistentEntity != null ? persistentEntity.getIdProperty() : null; - } - private String determineEntityCollectionName(@Nullable T obj) { if (null != obj) { @@ -2693,6 +2673,7 @@ public Publisher doInCollection(MongoCollection collection) * * @author Mark Paluch */ + @RequiredArgsConstructor private static class FindCallback implements ReactiveCollectionQueryCallback { private final @Nullable Document query; @@ -2702,11 +2683,6 @@ private static class FindCallback implements ReactiveCollectionQueryCallback doInCollection(MongoCollection collection) { @@ -2760,6 +2736,7 @@ public Publisher doInCollection(MongoCollection collection) /** * @author Mark Paluch */ + @RequiredArgsConstructor private static class FindAndModifyCallback implements ReactiveCollectionCallback { private final Document query; @@ -2768,16 +2745,6 @@ private static class FindAndModifyCallback implements ReactiveCollectionCallback private final Document update; private final FindAndModifyOptions options; - FindAndModifyCallback(Document query, Document fields, Document sort, Document update, - FindAndModifyOptions options) { - - this.query = query; - this.fields = fields; - this.sort = sort; - this.update = update; - this.options = options; - } - @Override public Publisher doInCollection(MongoCollection collection) throws MongoException, DataAccessException { @@ -2985,18 +2952,18 @@ public T doWith(@Nullable Document object) { * * @author Mark Paluch */ - static class GeoNearResultDbObjectCallback implements DocumentCallback> { + static class GeoNearResultDocumentCallback implements DocumentCallback> { private final DocumentCallback delegate; private final Metric metric; /** - * Creates a new {@link GeoNearResultDbObjectCallback} using the given {@link DocumentCallback} delegate for + * Creates a new {@link GeoNearResultDocumentCallback} using the given {@link DocumentCallback} delegate for * {@link GeoResult} content unmarshalling. * * @param delegate must not be {@literal null}. */ - GeoNearResultDbObjectCallback(DocumentCallback delegate, Metric metric) { + GeoNearResultDocumentCallback(DocumentCallback delegate, Metric metric) { Assert.notNull(delegate, "DocumentCallback must not be null!"); @@ -3109,7 +3076,7 @@ public FindPublisher prepare(FindPublisher findPublisher) { } } - private static List toDocuments(final Collection documents) { + private static List toDocuments(Collection documents) { return new ArrayList<>(documents); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingViaJavaConfigRepositoriesTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingViaJavaConfigRepositoriesTests.java index 41fff31365..6e9b5ecfae 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingViaJavaConfigRepositoriesTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingViaJavaConfigRepositoriesTests.java @@ -49,6 +49,7 @@ * * @author Thomas Darimont * @author Oliver Gierke + * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @@ -159,19 +160,19 @@ private void verifyAuditingViaVersionProperty(T inst assertThat(versionExtractor.apply(instance)).isEqualTo(expectedValues[0]); assertThat(entity.isNew(instance)).isTrue(); - instance = auditablePersonRepository.save(instance); + instance = persister.apply(instance); assertThat(versionExtractor.apply(instance)).isEqualTo(expectedValues[1]); assertThat(entity.isNew(instance)).isFalse(); - instance = auditablePersonRepository.save(instance); + instance = persister.apply(instance); assertThat(versionExtractor.apply(instance)).isEqualTo(expectedValues[2]); assertThat(entity.isNew(instance)).isFalse(); } @Repository - static interface AuditablePersonRepository extends MongoRepository {} + interface AuditablePersonRepository extends MongoRepository {} @Configuration @EnableMongoRepositories diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ReactiveAuditingTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ReactiveAuditingTests.java new file mode 100644 index 0000000000..c643f82f39 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ReactiveAuditingTests.java @@ -0,0 +1,154 @@ +/* + * Copyright 2018 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.config; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.annotation.Version; +import org.springframework.data.domain.AuditorAware; +import org.springframework.data.mongodb.core.AuditablePerson; +import org.springframework.data.mongodb.core.ReactiveMongoOperations; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; +import org.springframework.data.mongodb.repository.ReactiveMongoRepository; +import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import com.mongodb.reactivestreams.client.MongoClient; +import com.mongodb.reactivestreams.client.MongoClients; + +/** + * Integration test for the auditing support via {@link org.springframework.data.mongodb.core.ReactiveMongoTemplate}. + * + * @author Mark Paluch + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +public class ReactiveAuditingTests { + + @Autowired ReactiveAuditablePersonRepository auditablePersonRepository; + @Autowired AuditorAware auditorAware; + @Autowired MongoMappingContext context; + @Autowired ReactiveMongoOperations operations; + + @Configuration + @EnableMongoAuditing(auditorAwareRef = "auditorProvider") + @EnableReactiveMongoRepositories(basePackageClasses = ReactiveAuditingTests.class, considerNestedRepositories = true) + static class Config extends AbstractReactiveMongoConfiguration { + + @Override + protected String getDatabaseName() { + return "database"; + } + + @Override + public MongoClient reactiveMongoClient() { + return MongoClients.create(); + } + + @Bean + @SuppressWarnings("unchecked") + public AuditorAware auditorProvider() { + return mock(AuditorAware.class); + } + } + + @Test // DATAMONGO-2139, DATAMONGO-2150 + public void auditingWorksForVersionedEntityWithWrapperVersion() { + + verifyAuditingViaVersionProperty(new VersionedAuditablePerson(), // + it -> it.version, // + auditablePersonRepository::save, // + null, 0L, 1L); + } + + @Test // DATAMONGO-2139, DATAMONGO-2150 + public void auditingWorksForVersionedEntityWithSimpleVersion() { + + verifyAuditingViaVersionProperty(new SimpleVersionedAuditablePerson(), // + it -> it.version, // + auditablePersonRepository::save, // + 0L, 1L, 2L); + } + + @Test // DATAMONGO-2139, DATAMONGO-2150 + public void auditingWorksForVersionedEntityWithWrapperVersionOnTemplate() { + + verifyAuditingViaVersionProperty(new VersionedAuditablePerson(), // + it -> it.version, // + operations::save, // + null, 0L, 1L); + } + + @Test // DATAMONGO-2139, DATAMONGO-2150 + public void auditingWorksForVersionedEntityWithSimpleVersionOnTemplate() { + verifyAuditingViaVersionProperty(new SimpleVersionedAuditablePerson(), // + it -> it.version, // + operations::save, // + 0L, 1L, 2L); + } + + private void verifyAuditingViaVersionProperty(T instance, + Function versionExtractor, Function> persister, Object... expectedValues) { + + AtomicReference instanceHolder = new AtomicReference<>(instance); + MongoPersistentEntity entity = context.getRequiredPersistentEntity(instance.getClass()); + + assertThat(versionExtractor.apply(instance)).isEqualTo(expectedValues[0]); + assertThat(entity.isNew(instance)).isTrue(); + + persister.apply(instanceHolder.get()) // + .as(StepVerifier::create).consumeNextWith(actual -> { + + instanceHolder.set(actual); + + assertThat(versionExtractor.apply(actual)).isEqualTo(expectedValues[1]); + assertThat(entity.isNew(actual)).isFalse(); + }).verifyComplete(); + + persister.apply(instanceHolder.get()) // + .as(StepVerifier::create).consumeNextWith(actual -> { + + instanceHolder.set(actual); + + assertThat(versionExtractor.apply(actual)).isEqualTo(expectedValues[2]); + assertThat(entity.isNew(actual)).isFalse(); + }).verifyComplete(); + } + + interface ReactiveAuditablePersonRepository extends ReactiveMongoRepository {} + + static class VersionedAuditablePerson extends AuditablePerson { + @Version Long version; + } + + static class SimpleVersionedAuditablePerson extends AuditablePerson { + @Version long version; + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateTests.java index 5f88795684..4aaa18480b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateTests.java @@ -774,12 +774,9 @@ public void savesMapCorrectly() { StepVerifier.create(template.save(map, "maps")).expectNextCount(1).verifyComplete(); } - @Test // DATAMONGO-1444, DATAMONGO-1730 + @Test(expected = MappingException.class) // DATAMONGO-1444, DATAMONGO-1730, DATAMONGO-2150 public void savesMongoPrimitiveObjectCorrectly() { - - StepVerifier.create(template.save(new Object(), "collection")) // - .expectError(MappingException.class) // - .verify(); + template.save(new Object(), "collection"); } @Test // DATAMONGO-1444 @@ -852,12 +849,9 @@ public void writesPlainString() { .verifyComplete(); } - @Test // DATAMONGO-1444 + @Test(expected = MappingException.class) // DATAMONGO-1444, DATAMONGO-2150 public void rejectsNonJsonStringForSave() { - - StepVerifier.create(template.save("Foobar!", "collection")) // - .expectError(MappingException.class) // - .verify(); + template.save("Foobar!", "collection"); } @Test // DATAMONGO-1444