From eab3cd9fa73a4244872932516e174e8202e9246e Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 5 Dec 2018 16:05:09 +0100 Subject: [PATCH 1/3] DATAMONGO-2150 - Prepare issue branch. --- pom.xml | 2 +- spring-data-mongodb-benchmarks/pom.xml | 2 +- spring-data-mongodb-cross-store/pom.xml | 4 ++-- spring-data-mongodb-distribution/pom.xml | 2 +- spring-data-mongodb/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) 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 From a58bbef031ec2f1833203bcaf7d0d535f118e87c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 5 Dec 2018 16:12:28 +0100 Subject: [PATCH 2/3] DATAMONGO-2150 - Fixed broken auditing for entities using optimistic locking. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous implementation of ReactiveMongoTemplate.doSaveVersioned(…) prematurely initialized the version property so that the entity wasn't considered new by the auditing subsystem. Even worse, for primitive version properties, the initialization kept the property at a value of 0, so that the just persisted entity was still considered new. This mean that via the repository route, inserts are triggered even for subsequent attempts to save an entity which caused duplicate key exceptions. We now make sure we fire the BeforeConvertEvent before the version property is initialized or updated. Also, the initialization of the property now sets primitive properties to 1 initially. Added integration tests for the auditing via ReactiveMongoTemplate and repositories. Related ticket: DATAMONGO-2139. --- .../mongodb/core/ReactiveMongoTemplate.java | 52 +++--- .../mongodb/config/ReactiveAuditingTests.java | 154 ++++++++++++++++++ .../core/ReactiveMongoTemplateTests.java | 14 +- 3 files changed, 181 insertions(+), 39 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ReactiveAuditingTests.java 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..fb39c0f78a 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 @@ -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 = insertDBObject(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; }); @@ -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()); + AdaptibleEntity source = operations.forEntity(objectToSave, mongoConverter.getConversionService()); - // No optimistic locking -> simple save - if (mongoPersistentEntity == null || !mongoPersistentEntity.hasVersionProperty()) { - return doSave(collectionName, objectToSave, this.mongoConverter); - } - - 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(); - - // Fresh instance -> initialize version property - if (versionNumber == null) { - return doInsert(collectionName, objectToSave, mongoConverter); - } - - forEntity.assertUpdateableIdIfNotSet(); + // Create query for entity with the id and old version + Query query = source.getQueryForVersion(); - Query query = forEntity.getQueryForVersion(); + // Bump version number + T toSave = source.incrementVersion(); - 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(); + }); }); } 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 From 37d6c89750902f1046e020164614744540874ff6 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 5 Dec 2018 16:32:15 +0100 Subject: [PATCH 3/3] DATAMONGO-2150 - Polishing. Fix imperative auditing test to use intended persist mechanism. Remove final keywords from method args and local variables in ReactiveMongoTemplate. Rename DBObject to Document. --- .../mongodb/core/ReactiveMongoTemplate.java | 109 +++++++----------- ...uditingViaJavaConfigRepositoriesTests.java | 7 +- 2 files changed, 45 insertions(+), 71 deletions(-) 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 fb39c0f78a..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); } @@ -1246,7 +1246,7 @@ protected Mono doInsert(String collectionName, T objectToSave, MongoWrite maybeEmitEvent(new BeforeSaveEvent<>(initialized, dbDoc, collectionName)); - Mono afterInsert = insertDBObject(collectionName, dbDoc, initialized.getClass()).map(id -> { + Mono afterInsert = insertDocument(collectionName, dbDoc, initialized.getClass()).map(id -> { T saved = entity.populateIdIfNecessary(id); maybeEmitEvent(new AfterSaveEvent<>(initialized, dbDoc, collectionName)); @@ -1292,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 -> { @@ -1308,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!"); @@ -1329,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 -> { @@ -1444,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); @@ -1466,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 -> { @@ -1508,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()); @@ -1571,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); } @@ -1595,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); } @@ -1603,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); @@ -1655,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); } @@ -1675,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; @@ -1779,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 -> { @@ -1791,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); @@ -2146,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 -> { @@ -2584,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) { @@ -2687,6 +2673,7 @@ public Publisher doInCollection(MongoCollection collection) * * @author Mark Paluch */ + @RequiredArgsConstructor private static class FindCallback implements ReactiveCollectionQueryCallback { private final @Nullable Document query; @@ -2696,11 +2683,6 @@ private static class FindCallback implements ReactiveCollectionQueryCallback doInCollection(MongoCollection collection) { @@ -2754,6 +2736,7 @@ public Publisher doInCollection(MongoCollection collection) /** * @author Mark Paluch */ + @RequiredArgsConstructor private static class FindAndModifyCallback implements ReactiveCollectionCallback { private final Document query; @@ -2762,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 { @@ -2979,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!"); @@ -3103,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