Compare commits
14 Commits
2.1.2.RELE
...
2.1.3.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd8bd4f568 | ||
|
|
c75f29dc42 | ||
|
|
e493af7266 | ||
|
|
8d892e5924 | ||
|
|
053299f243 | ||
|
|
872659cc00 | ||
|
|
96978a6194 | ||
|
|
2253d3e301 | ||
|
|
5982ee84f7 | ||
|
|
dd2af6462d | ||
|
|
622643bf24 | ||
|
|
51cc55baac | ||
|
|
0b106e5649 | ||
|
|
8975d93ab3 |
6
pom.xml
6
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
<version>2.1.3.RELEASE</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
@@ -15,7 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
<version>2.1.3.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
@@ -27,7 +27,7 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>2.1.2.RELEASE</springdata.commons>
|
||||
<springdata.commons>2.1.3.RELEASE</springdata.commons>
|
||||
<mongo>3.8.2</mongo>
|
||||
<mongo.reactivestreams>1.9.2</mongo.reactivestreams>
|
||||
<jmh.version>1.19</jmh.version>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
<version>2.1.3.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
<version>2.1.3.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
<version>2.1.3.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<!-- reactive -->
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
<version>2.1.3.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
<version>2.1.3.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ public class MongoDatabaseUtils {
|
||||
|
||||
ClientSession session = doGetSession(factory, sessionSynchronization);
|
||||
|
||||
if(session == null) {
|
||||
if (session == null) {
|
||||
return StringUtils.hasText(dbName) ? factory.getDb(dbName) : factory.getDb();
|
||||
}
|
||||
|
||||
@@ -118,6 +118,25 @@ public class MongoDatabaseUtils {
|
||||
return StringUtils.hasText(dbName) ? factoryToUse.getDb(dbName) : factoryToUse.getDb();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the {@link MongoDbFactory} is actually bound to a {@link ClientSession} that has an active transaction, or
|
||||
* if a {@link TransactionSynchronization} has been registered for the {@link MongoDbFactory resource} and if the
|
||||
* associated {@link ClientSession} has an {@link ClientSession#hasActiveTransaction() active transaction}.
|
||||
*
|
||||
* @param dbFactory the resource to check transactions for. Must not be {@literal null}.
|
||||
* @return {@literal true} if the factory has an ongoing transaction.
|
||||
* @since 2.1.3
|
||||
*/
|
||||
public static boolean isTransactionActive(MongoDbFactory dbFactory) {
|
||||
|
||||
if (dbFactory.isTransactionActive()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MongoResourceHolder resourceHolder = (MongoResourceHolder) TransactionSynchronizationManager.getResource(dbFactory);
|
||||
return resourceHolder != null && resourceHolder.hasActiveTransaction();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ClientSession doGetSession(MongoDbFactory dbFactory, SessionSynchronization sessionSynchronization) {
|
||||
|
||||
@@ -140,7 +159,7 @@ public class MongoDatabaseUtils {
|
||||
// init a non native MongoDB transaction by registering a MongoSessionSynchronization
|
||||
|
||||
resourceHolder = new MongoResourceHolder(createClientSession(dbFactory), dbFactory);
|
||||
resourceHolder.getSession().startTransaction();
|
||||
resourceHolder.getRequiredSession().startTransaction();
|
||||
|
||||
TransactionSynchronizationManager
|
||||
.registerSynchronization(new MongoSessionSynchronization(resourceHolder, dbFactory));
|
||||
@@ -187,8 +206,8 @@ public class MongoDatabaseUtils {
|
||||
@Override
|
||||
protected void processResourceAfterCommit(MongoResourceHolder resourceHolder) {
|
||||
|
||||
if (isTransactionActive(resourceHolder)) {
|
||||
resourceHolder.getSession().commitTransaction();
|
||||
if (resourceHolder.hasActiveTransaction()) {
|
||||
resourceHolder.getRequiredSession().commitTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,8 +218,8 @@ public class MongoDatabaseUtils {
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
|
||||
if (status == TransactionSynchronization.STATUS_ROLLED_BACK && isTransactionActive(this.resourceHolder)) {
|
||||
resourceHolder.getSession().abortTransaction();
|
||||
if (status == TransactionSynchronization.STATUS_ROLLED_BACK && this.resourceHolder.hasActiveTransaction()) {
|
||||
resourceHolder.getRequiredSession().abortTransaction();
|
||||
}
|
||||
|
||||
super.afterCompletion(status);
|
||||
@@ -214,17 +233,8 @@ public class MongoDatabaseUtils {
|
||||
protected void releaseResource(MongoResourceHolder resourceHolder, Object resourceKey) {
|
||||
|
||||
if (resourceHolder.hasActiveSession()) {
|
||||
resourceHolder.getSession().close();
|
||||
resourceHolder.getRequiredSession().close();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTransactionActive(MongoResourceHolder resourceHolder) {
|
||||
|
||||
if (!resourceHolder.hasSession()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return resourceHolder.getSession().hasActiveTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,4 +108,15 @@ public interface MongoDbFactory extends CodecRegistryProvider, MongoSessionProvi
|
||||
* @since 2.1
|
||||
*/
|
||||
MongoDbFactory withSession(ClientSession session);
|
||||
|
||||
/**
|
||||
* Returns if the given {@link MongoDbFactory} is bound to a {@link ClientSession} that has an
|
||||
* {@link ClientSession#hasActiveTransaction() active transaction}.
|
||||
*
|
||||
* @return {@literal true} if there's an active transaction, {@literal false} otherwise.
|
||||
* @since 2.1.3
|
||||
*/
|
||||
default boolean isTransactionActive() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.mongodb.client.ClientSession;
|
||||
* <strong>Note:</strong> Intended for internal usage only.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 2.1
|
||||
* @see MongoTransactionManager
|
||||
* @see org.springframework.data.mongodb.core.MongoTemplate
|
||||
@@ -57,6 +58,22 @@ class MongoResourceHolder extends ResourceHolderSupport {
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the required associated {@link ClientSession}.
|
||||
* @throws IllegalStateException if no {@link ClientSession} is associated with this {@link MongoResourceHolder}.
|
||||
* @since 2.1.3
|
||||
*/
|
||||
ClientSession getRequiredSession() {
|
||||
|
||||
ClientSession session = getSession();
|
||||
|
||||
if (session == null) {
|
||||
throw new IllegalStateException("No session available!");
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the associated {@link MongoDbFactory}.
|
||||
*/
|
||||
@@ -101,7 +118,21 @@ class MongoResourceHolder extends ResourceHolderSupport {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasServerSession() && !getSession().getServerSession().isClosed();
|
||||
return hasServerSession() && !getRequiredSession().getServerSession().isClosed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} if the session has an active transaction.
|
||||
* @since 2.1.3
|
||||
* @see #hasActiveSession()
|
||||
*/
|
||||
boolean hasActiveTransaction() {
|
||||
|
||||
if (!hasActiveSession()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return getRequiredSession().hasActiveTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +142,7 @@ class MongoResourceHolder extends ResourceHolderSupport {
|
||||
boolean hasServerSession() {
|
||||
|
||||
try {
|
||||
return getSession().getServerSession() != null;
|
||||
return getRequiredSession().getServerSession() != null;
|
||||
} catch (IllegalStateException serverSessionClosed) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@@ -242,6 +242,14 @@ class EntityOperations {
|
||||
* @return
|
||||
*/
|
||||
T getBean();
|
||||
|
||||
/**
|
||||
* Returns whether the entity is considered to be new.
|
||||
*
|
||||
* @return
|
||||
* @since 2.1.2
|
||||
*/
|
||||
boolean isNew();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,6 +395,15 @@ class EntityOperations {
|
||||
public T getBean() {
|
||||
return map;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.EntityOperations.Entity#isNew()
|
||||
*/
|
||||
@Override
|
||||
public boolean isNew() {
|
||||
return map.get(ID_FIELD) != null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SimpleMappedEntity<T extends Map<String, Object>> extends UnmappedEntity<T> {
|
||||
@@ -549,6 +566,15 @@ class EntityOperations {
|
||||
public T getBean() {
|
||||
return propertyAccessor.getBean();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.EntityOperations.Entity#isNew()
|
||||
*/
|
||||
@Override
|
||||
public boolean isNew() {
|
||||
return entity.isNew(propertyAccessor.getBean());
|
||||
}
|
||||
}
|
||||
|
||||
private static class AdaptibleMappedEntity<T> extends MappedEntity<T> implements AdaptibleEntity<T> {
|
||||
@@ -631,7 +657,9 @@ class EntityOperations {
|
||||
return propertyAccessor.getBean();
|
||||
}
|
||||
|
||||
propertyAccessor.setProperty(entity.getRequiredVersionProperty(), 0);
|
||||
MongoPersistentProperty versionProperty = entity.getRequiredVersionProperty();
|
||||
|
||||
propertyAccessor.setProperty(versionProperty, versionProperty.getType().isPrimitive() ? 1 : 0);
|
||||
|
||||
return propertyAccessor.getBean();
|
||||
}
|
||||
|
||||
@@ -233,6 +233,15 @@ public abstract class MongoDbFactorySupport<C> implements MongoDbFactory {
|
||||
return delegate.withSession(session);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.MongoDbFactory#isTransactionActive()
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransactionActive() {
|
||||
return session != null && session.hasActiveTransaction();
|
||||
}
|
||||
|
||||
private MongoDatabase proxyMongoDatabase(MongoDatabase database) {
|
||||
return createProxyInstance(session, database, MongoDatabase.class);
|
||||
}
|
||||
@@ -241,7 +250,8 @@ public abstract class MongoDbFactorySupport<C> implements MongoDbFactory {
|
||||
return createProxyInstance(session, database, MongoDatabase.class);
|
||||
}
|
||||
|
||||
private MongoCollection<?> proxyCollection(com.mongodb.session.ClientSession session, MongoCollection<?> collection) {
|
||||
private MongoCollection<?> proxyCollection(com.mongodb.session.ClientSession session,
|
||||
MongoCollection<?> collection) {
|
||||
return createProxyInstance(session, collection, MongoCollection.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -1119,7 +1119,16 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
Document document = queryMapper.getMappedObject(query.getQueryObject(),
|
||||
Optional.ofNullable(entityClass).map(it -> mappingContext.getPersistentEntity(entityClass)));
|
||||
|
||||
return execute(collectionName, collection -> collection.count(document, options));
|
||||
return doCount(collectionName, document, options);
|
||||
}
|
||||
|
||||
protected long doCount(String collectionName, Document filter, CountOptions options) {
|
||||
|
||||
if (MongoDatabaseUtils.isTransactionActive(getMongoDbFactory())) {
|
||||
return execute(collectionName, collection -> collection.countDocuments(filter, options));
|
||||
}
|
||||
|
||||
return execute(collectionName, collection -> collection.count(filter, options));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1203,20 +1212,19 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
|
||||
protected <T> T doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {
|
||||
|
||||
AdaptibleEntity<T> entity = operations.forEntity(objectToSave, mongoConverter.getConversionService());
|
||||
T toSave = entity.initializeVersionProperty();
|
||||
|
||||
BeforeConvertEvent<T> event = new BeforeConvertEvent<>(toSave, collectionName);
|
||||
toSave = maybeEmitEvent(event).getSource();
|
||||
BeforeConvertEvent<T> event = new BeforeConvertEvent<>(objectToSave, collectionName);
|
||||
T toConvert = maybeEmitEvent(event).getSource();
|
||||
|
||||
AdaptibleEntity<T> entity = operations.forEntity(toConvert, mongoConverter.getConversionService());
|
||||
entity.assertUpdateableIdIfNotSet();
|
||||
|
||||
T initialized = entity.initializeVersionProperty();
|
||||
Document dbDoc = entity.toMappedDocument(writer).getDocument();
|
||||
|
||||
maybeEmitEvent(new BeforeSaveEvent<>(toSave, dbDoc, collectionName));
|
||||
Object id = insertDocument(collectionName, dbDoc, toSave.getClass());
|
||||
maybeEmitEvent(new BeforeSaveEvent<>(initialized, dbDoc, collectionName));
|
||||
Object id = insertDocument(collectionName, dbDoc, initialized.getClass());
|
||||
|
||||
T saved = populateIdIfNecessary(toSave, id);
|
||||
T saved = populateIdIfNecessary(initialized, id);
|
||||
maybeEmitEvent(new AfterSaveEvent<>(saved, dbDoc, collectionName));
|
||||
|
||||
return saved;
|
||||
@@ -1348,38 +1356,36 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T doSaveVersioned(AdaptibleEntity<T> source, String collectionName) {
|
||||
|
||||
Number number = source.getVersion();
|
||||
|
||||
if (number != null) {
|
||||
|
||||
// Create query for entity with the id and old version
|
||||
Query query = source.getQueryForVersion();
|
||||
|
||||
// Bump version number
|
||||
T toSave = source.incrementVersion();
|
||||
|
||||
toSave = maybeEmitEvent(new BeforeConvertEvent<T>(toSave, collectionName)).getSource();
|
||||
|
||||
source.assertUpdateableIdIfNotSet();
|
||||
|
||||
MappedDocument mapped = source.toMappedDocument(mongoConverter);
|
||||
|
||||
maybeEmitEvent(new BeforeSaveEvent<>(toSave, mapped.getDocument(), collectionName));
|
||||
Update update = mapped.updateWithoutId();
|
||||
|
||||
UpdateResult result = doUpdate(collectionName, query, update, toSave.getClass(), false, false);
|
||||
|
||||
if (result.getModifiedCount() == 0) {
|
||||
throw new OptimisticLockingFailureException(
|
||||
String.format("Cannot save entity %s with version %s to collection %s. Has it been modified meanwhile?",
|
||||
source.getId(), number, collectionName));
|
||||
}
|
||||
maybeEmitEvent(new AfterSaveEvent<>(toSave, mapped.getDocument(), collectionName));
|
||||
|
||||
return toSave;
|
||||
if (source.isNew()) {
|
||||
return (T) doInsert(collectionName, source.getBean(), this.mongoConverter);
|
||||
}
|
||||
|
||||
return (T) doInsert(collectionName, source.getBean(), this.mongoConverter);
|
||||
// Create query for entity with the id and old version
|
||||
Query query = source.getQueryForVersion();
|
||||
|
||||
// Bump version number
|
||||
T toSave = source.incrementVersion();
|
||||
|
||||
toSave = maybeEmitEvent(new BeforeConvertEvent<T>(toSave, collectionName)).getSource();
|
||||
|
||||
source.assertUpdateableIdIfNotSet();
|
||||
|
||||
MappedDocument mapped = source.toMappedDocument(mongoConverter);
|
||||
|
||||
maybeEmitEvent(new BeforeSaveEvent<>(toSave, mapped.getDocument(), collectionName));
|
||||
Update update = mapped.updateWithoutId();
|
||||
|
||||
UpdateResult result = doUpdate(collectionName, query, update, toSave.getClass(), false, false);
|
||||
|
||||
if (result.getModifiedCount() == 0) {
|
||||
|
||||
throw new OptimisticLockingFailureException(
|
||||
String.format("Cannot save entity %s with version %s to collection %s. Has it been modified meanwhile?",
|
||||
source.getId(), source.getVersion(), collectionName));
|
||||
}
|
||||
maybeEmitEvent(new AfterSaveEvent<>(toSave, mapped.getDocument(), collectionName));
|
||||
|
||||
return toSave;
|
||||
}
|
||||
|
||||
protected <T> T doSave(String collectionName, T objectToSave, MongoWriter<T> writer) {
|
||||
@@ -2820,21 +2826,23 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimized {@link CollectionCallback} that takes an already mappend query and a nullable
|
||||
* Optimized {@link CollectionCallback} that takes an already mapped query and a nullable
|
||||
* {@link com.mongodb.client.model.Collation} to execute a count query limited to one element.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
private static class ExistsCallback implements CollectionCallback<Boolean> {
|
||||
private class ExistsCallback implements CollectionCallback<Boolean> {
|
||||
|
||||
private final Document mappedQuery;
|
||||
private final com.mongodb.client.model.Collation collation;
|
||||
|
||||
@Override
|
||||
public Boolean doInCollection(MongoCollection<Document> collection) throws MongoException, DataAccessException {
|
||||
return collection.count(mappedQuery, new CountOptions().limit(1).collation(collation)) > 0;
|
||||
|
||||
return doCount(collection.getNamespace().getCollectionName(), mappedQuery,
|
||||
new CountOptions().limit(1).collation(collation)) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3343,23 +3351,16 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.MongoTemplate#count(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
||||
* @see org.springframework.data.mongodb.core.MongoTemplate#doCount(java.lang.String, org.bson.Document, com.mongodb.client.model.CountOptions)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public long count(Query query, @Nullable Class<?> entityClass, String collectionName) {
|
||||
protected long doCount(String collectionName, Document filter, CountOptions options) {
|
||||
|
||||
if (!session.hasActiveTransaction()) {
|
||||
return super.count(query, entityClass, collectionName);
|
||||
return super.doCount(collectionName, filter, options);
|
||||
}
|
||||
|
||||
CountOptions options = new CountOptions();
|
||||
query.getCollation().map(Collation::toMongoCollation).ifPresent(options::collation);
|
||||
|
||||
Document document = delegate.queryMapper.getMappedObject(query.getQueryObject(),
|
||||
Optional.ofNullable(entityClass).map(it -> delegate.mappingContext.getPersistentEntity(entityClass)));
|
||||
|
||||
return execute(collectionName, collection -> collection.countDocuments(document, options));
|
||||
return execute(collectionName, collection -> collection.countDocuments(filter, options));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
private ParameterValueProvider<MongoPersistentProperty> getParameterProvider(MongoPersistentEntity<?> entity,
|
||||
DocumentAccessor source, SpELExpressionEvaluator evaluator, ObjectPath path) {
|
||||
|
||||
|
||||
AssociationAwareMongoDbPropertyValueProvider provider = new AssociationAwareMongoDbPropertyValueProvider(source,
|
||||
evaluator, path);
|
||||
PersistentEntityParameterValueProvider<MongoPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<>(
|
||||
@@ -287,8 +286,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
// Make sure id property is set before all other properties
|
||||
|
||||
Object rawId = readAndPopulateIdentifier(accessor, documentAccessor, entity,
|
||||
path, evaluator);
|
||||
Object rawId = readAndPopulateIdentifier(accessor, documentAccessor, entity, path, evaluator);
|
||||
ObjectPath currentPath = path.push(accessor.getBean(), entity, rawId);
|
||||
|
||||
MongoDbPropertyValueProvider valueProvider = new MongoDbPropertyValueProvider(documentAccessor, evaluator,
|
||||
@@ -620,7 +618,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return;
|
||||
}
|
||||
|
||||
MongoPersistentEntity<?> entity = isSubtype(prop.getType(), obj.getClass())
|
||||
MongoPersistentEntity<?> entity = isSubTypeOf(obj.getClass(), prop.getType())
|
||||
? mappingContext.getRequiredPersistentEntity(obj.getClass())
|
||||
: mappingContext.getRequiredPersistentEntity(type);
|
||||
|
||||
@@ -632,10 +630,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
accessor.put(prop, document);
|
||||
}
|
||||
|
||||
private boolean isSubtype(Class<?> left, Class<?> right) {
|
||||
return left.isAssignableFrom(right) && !left.equals(right);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns given object as {@link Collection}. Will return the {@link Collection} as is if the source is a
|
||||
* {@link Collection} already, will convert an array into a {@link Collection} or simply create a single element
|
||||
@@ -1012,7 +1006,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
Assert.notNull(path, "Object path must not be null!");
|
||||
|
||||
Class<?> collectionType = targetType.getType();
|
||||
collectionType = Collection.class.isAssignableFrom(collectionType) //
|
||||
collectionType = isSubTypeOf(collectionType, Collection.class) //
|
||||
? collectionType //
|
||||
: List.class;
|
||||
|
||||
@@ -1630,6 +1624,17 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given type is a sub type of the given reference, i.e. assignable but not the exact same type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param reference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static boolean isSubTypeOf(Class<?> type, Class<?> reference) {
|
||||
return !type.equals(reference) && reference.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marker class used to indicate we have a non root document object here that might be used within an update - so we
|
||||
* need to preserve type hints for potential nested elements but need to remove it on top level.
|
||||
|
||||
@@ -20,7 +20,9 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.bson.BSON;
|
||||
import org.bson.Document;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -37,6 +39,7 @@ import org.springframework.util.StringUtils;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.DBRef;
|
||||
import com.mongodb.util.JSON;
|
||||
import com.mongodb.util.JSONCallback;
|
||||
|
||||
/**
|
||||
* Query to use a plain JSON String to create the {@link Query} to actually execute.
|
||||
@@ -225,7 +228,8 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
String transformedInput = transformQueryAndCollectExpressionParametersIntoBindings(input, bindings);
|
||||
String parseableInput = makeParameterReferencesParseable(transformedInput);
|
||||
|
||||
collectParameterReferencesIntoBindings(bindings, JSON.parse(parseableInput));
|
||||
collectParameterReferencesIntoBindings(bindings,
|
||||
JSON.parse(parseableInput, new LenientPatternDecodingCallback()));
|
||||
|
||||
return transformedInput;
|
||||
}
|
||||
@@ -360,6 +364,43 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JSONCallback} with lenient handling for {@link PatternSyntaxException} falling back to a placeholder
|
||||
* {@link Pattern} for intermediate query document rendering.
|
||||
*/
|
||||
private static class LenientPatternDecodingCallback extends JSONCallback {
|
||||
|
||||
private static final Pattern EMPTY_MARKER = Pattern.compile("__Spring_Data_MongoDB_Bind_Marker__");
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.mongodb.util.JSONCallback#objectDone()
|
||||
*/
|
||||
@Override
|
||||
public Object objectDone() {
|
||||
return exceptionSwallowingStackReducingObjectDone();
|
||||
}
|
||||
|
||||
private Object exceptionSwallowingStackReducingObjectDone/*CauseWeJustNeedTheStructureNotTheActualValue*/() {
|
||||
|
||||
Object value;
|
||||
|
||||
try {
|
||||
return super.objectDone();
|
||||
} catch (PatternSyntaxException e) {
|
||||
value = EMPTY_MARKER;
|
||||
}
|
||||
|
||||
if (!isStackEmpty()) {
|
||||
_put(curName(), value);
|
||||
} else {
|
||||
value = !BSON.hasDecodeHooks() ? value : BSON.applyDecodingHooks(value);
|
||||
setRoot(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic parameter binding with name or position information.
|
||||
*
|
||||
|
||||
@@ -137,7 +137,7 @@ public class SimpleMongoRepository<T, ID> implements MongoRepository<T, ID> {
|
||||
*/
|
||||
@Override
|
||||
public long count() {
|
||||
return mongoOperations.getCollection(entityInformation.getCollectionName()).count();
|
||||
return mongoOperations.count(new Query(), entityInformation.getCollectionName());
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -78,6 +78,39 @@ public class MongoDatabaseUtilsUnitTests {
|
||||
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2130
|
||||
public void isTransactionActiveShouldDetectTxViaFactory() {
|
||||
|
||||
when(dbFactory.isTransactionActive()).thenReturn(true);
|
||||
|
||||
assertThat(MongoDatabaseUtils.isTransactionActive(dbFactory)).isTrue();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2130
|
||||
public void isTransactionActiveShouldReturnFalseIfNoTxActive() {
|
||||
|
||||
when(dbFactory.isTransactionActive()).thenReturn(false);
|
||||
|
||||
assertThat(MongoDatabaseUtils.isTransactionActive(dbFactory)).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2130
|
||||
public void isTransactionActiveShouldLookupTxForActiveTransactionSynchronizationViaTxManager() {
|
||||
|
||||
when(dbFactory.isTransactionActive()).thenReturn(false);
|
||||
|
||||
MongoTransactionManager txManager = new MongoTransactionManager(dbFactory);
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(txManager);
|
||||
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
|
||||
assertThat(MongoDatabaseUtils.isTransactionActive(dbFactory)).isTrue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1920
|
||||
public void shouldNotStartSessionWhenNoTransactionOngoing() {
|
||||
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.config;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -28,15 +30,18 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
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.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
@@ -51,6 +56,9 @@ public class AuditingViaJavaConfigRepositoriesTests {
|
||||
|
||||
@Autowired AuditablePersonRepository auditablePersonRepository;
|
||||
@Autowired AuditorAware<AuditablePerson> auditorAware;
|
||||
@Autowired MongoMappingContext context;
|
||||
@Autowired MongoOperations operations;
|
||||
|
||||
AuditablePerson auditor;
|
||||
|
||||
@Configuration
|
||||
@@ -107,6 +115,61 @@ public class AuditingViaJavaConfigRepositoriesTests {
|
||||
new AnnotationConfigApplicationContext(SimpleConfig.class);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2139
|
||||
public void auditingWorksForVersionedEntityWithWrapperVersion() {
|
||||
|
||||
verifyAuditingViaVersionProperty(new VersionedAuditablePerson(), //
|
||||
it -> it.version, //
|
||||
auditablePersonRepository::save, //
|
||||
null, 0L, 1L);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2139
|
||||
public void auditingWorksForVersionedEntityWithSimpleVersion() {
|
||||
|
||||
verifyAuditingViaVersionProperty(new SimpleVersionedAuditablePerson(), //
|
||||
it -> it.version, //
|
||||
auditablePersonRepository::save, //
|
||||
0L, 1L, 2L);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2139
|
||||
public void auditingWorksForVersionedEntityWithWrapperVersionOnTemplate() {
|
||||
|
||||
verifyAuditingViaVersionProperty(new VersionedAuditablePerson(), //
|
||||
it -> it.version, //
|
||||
operations::save, //
|
||||
null, 0L, 1L);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2139
|
||||
public void auditingWorksForVersionedEntityWithSimpleVersionOnTemplate() {
|
||||
|
||||
verifyAuditingViaVersionProperty(new SimpleVersionedAuditablePerson(), //
|
||||
it -> it.version, //
|
||||
operations::save, //
|
||||
0L, 1L, 2L);
|
||||
}
|
||||
|
||||
private <T extends AuditablePerson> void verifyAuditingViaVersionProperty(T instance,
|
||||
Function<T, Object> versionExtractor, Function<T, T> persister, Object... expectedValues) {
|
||||
|
||||
MongoPersistentEntity<?> entity = context.getRequiredPersistentEntity(instance.getClass());
|
||||
|
||||
assertThat(versionExtractor.apply(instance)).isEqualTo(expectedValues[0]);
|
||||
assertThat(entity.isNew(instance)).isTrue();
|
||||
|
||||
instance = auditablePersonRepository.save(instance);
|
||||
|
||||
assertThat(versionExtractor.apply(instance)).isEqualTo(expectedValues[1]);
|
||||
assertThat(entity.isNew(instance)).isFalse();
|
||||
|
||||
instance = auditablePersonRepository.save(instance);
|
||||
|
||||
assertThat(versionExtractor.apply(instance)).isEqualTo(expectedValues[2]);
|
||||
assertThat(entity.isNew(instance)).isFalse();
|
||||
}
|
||||
|
||||
@Repository
|
||||
static interface AuditablePersonRepository extends MongoRepository<AuditablePerson, String> {}
|
||||
|
||||
@@ -128,4 +191,12 @@ public class AuditingViaJavaConfigRepositoriesTests {
|
||||
return "database";
|
||||
}
|
||||
}
|
||||
|
||||
static class VersionedAuditablePerson extends AuditablePerson {
|
||||
@Version Long version;
|
||||
}
|
||||
|
||||
static class SimpleVersionedAuditablePerson extends AuditablePerson {
|
||||
@Version long version;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.mongodb.config;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
@@ -124,7 +125,8 @@ public class ServerAddressPropertyEditorUnitTests {
|
||||
* We can't tell whether the last part of the hostAddress represents a port or not.
|
||||
*/
|
||||
@Test // DATAMONGO-808
|
||||
public void shouldFailToHandleAmbiguousIPv6HostaddressLongWithoutPortAndWithoutBrackets() throws UnknownHostException {
|
||||
public void shouldFailToHandleAmbiguousIPv6HostaddressLongWithoutPortAndWithoutBrackets()
|
||||
throws UnknownHostException {
|
||||
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
|
||||
@@ -173,9 +175,9 @@ public class ServerAddressPropertyEditorUnitTests {
|
||||
|
||||
for (String hostname : hostnames) {
|
||||
try {
|
||||
InetAddress.getByName(hostname);
|
||||
InetAddress.getByName(hostname).isReachable(1500);
|
||||
Assert.fail("Supposedly unresolveable hostname '" + hostname + "' can be resolved.");
|
||||
} catch (UnknownHostException expected) {
|
||||
} catch (IOException expected) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.any;
|
||||
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
|
||||
import static org.springframework.data.mongodb.test.util.IsBsonObject.*;
|
||||
|
||||
import com.mongodb.MongoNamespace;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigInteger;
|
||||
@@ -135,6 +136,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
|
||||
when(collection.find(any(org.bson.Document.class), any(Class.class))).thenReturn(findIterable);
|
||||
when(collection.mapReduce(any(), any(), eq(Document.class))).thenReturn(mapReduceIterable);
|
||||
when(collection.count(any(Bson.class), any(CountOptions.class))).thenReturn(1L);
|
||||
when(collection.getNamespace()).thenReturn(new MongoNamespace("db.mock-collection"));
|
||||
when(collection.aggregate(any(List.class), any())).thenReturn(aggregateIterable);
|
||||
when(collection.withReadPreference(any())).thenReturn(collection);
|
||||
when(findIterable.projection(any())).thenReturn(findIterable);
|
||||
|
||||
@@ -26,6 +26,7 @@ import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.mongodb.core.DocumentTestUtils.*;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -1913,6 +1914,18 @@ public class MappingMongoConverterUnitTests {
|
||||
assertThat(target).doesNotContainKeys("_class");
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2135
|
||||
public void addsEqualObjectsToCollection() {
|
||||
|
||||
org.bson.Document itemDocument = new org.bson.Document("itemKey", "123");
|
||||
org.bson.Document orderDocument = new org.bson.Document("items",
|
||||
Arrays.asList(itemDocument, itemDocument, itemDocument));
|
||||
|
||||
Order order = converter.read(Order.class, orderDocument);
|
||||
|
||||
assertThat(order.items).hasSize(3);
|
||||
}
|
||||
|
||||
static class GenericType<T> {
|
||||
T content;
|
||||
}
|
||||
@@ -2341,4 +2354,15 @@ public class MappingMongoConverterUnitTests {
|
||||
final @Id String id;
|
||||
String value;
|
||||
}
|
||||
|
||||
// DATAMONGO-2135
|
||||
|
||||
@EqualsAndHashCode // equality check by fields
|
||||
static class SomeItem {
|
||||
String itemKey;
|
||||
}
|
||||
|
||||
static class Order {
|
||||
Collection<SomeItem> items = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,6 +590,19 @@ public class StringBasedMongoQueryUnitTests {
|
||||
assertThat(query.getQueryObject(), is(new Document("arg0", null)));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2119
|
||||
public void spelShouldIgnoreJsonParseErrorsForRegex() {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByPersonLastnameRegex", Person.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter,
|
||||
new Person("Molly", "Chandler"));
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
|
||||
assertThat(query.getQueryObject().toJson(),
|
||||
is(new BasicQuery("{lastname: {$regex: 'Chandler'}}").getQueryObject().toJson()));
|
||||
}
|
||||
|
||||
private StringBasedMongoQuery createQueryForMethod(String name, Class<?>... parameters) {
|
||||
|
||||
try {
|
||||
@@ -697,10 +710,14 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Query("{ 'arg0' : '?0', 'arg1' : '?1s' }")
|
||||
List<Person> findByWhenQuotedAndSomeStuffAppended(String arg0, String arg1);
|
||||
|
||||
@Query("{ 'lastname' : { '$regex' : '^(?0|John ?1|?1)'} }") // use spel or some regex string this is fucking bad
|
||||
@Query("{ 'lastname' : { '$regex' : '^(?0|John ?1|?1)'} }") // use spel or some regex string this is bad
|
||||
Person findByLastnameRegex(String lastname, String alternative);
|
||||
|
||||
@Query("{ arg0 : ?#{[0]} }")
|
||||
List<Person> findByUsingSpel(Object arg0);
|
||||
|
||||
@Query("{ 'lastname' : { '$regex' : ?#{[0].lastname} } }")
|
||||
Person findByPersonLastnameRegex(Person key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.mongodb.repository.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.Assumptions.*;
|
||||
import static org.springframework.data.domain.ExampleMatcher.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -28,14 +29,16 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.ExampleMatcher.StringMatcher;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.ExampleMatcher.*;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.MongoTransactionManager;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
@@ -44,9 +47,13 @@ import org.springframework.data.mongodb.repository.Person;
|
||||
import org.springframework.data.mongodb.repository.Person.Sex;
|
||||
import org.springframework.data.mongodb.repository.User;
|
||||
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
|
||||
import org.springframework.data.mongodb.test.util.MongoVersion;
|
||||
import org.springframework.data.mongodb.test.util.MongoVersionRule;
|
||||
import org.springframework.data.mongodb.test.util.ReplicaSet;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
/**
|
||||
* @author A. B. M. Kowser
|
||||
@@ -59,6 +66,7 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
public class SimpleMongoRepositoryTests {
|
||||
|
||||
@Autowired private MongoTemplate template;
|
||||
public @Rule MongoVersionRule mongoVersion = MongoVersionRule.any();
|
||||
|
||||
private Person oliver, dave, carter, boyd, stefan, leroi, alicia;
|
||||
private List<Person> all;
|
||||
@@ -383,6 +391,54 @@ public class SimpleMongoRepositoryTests {
|
||||
assertThat(repository.findAll()).containsExactlyInAnyOrder(first, second);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2130
|
||||
@MongoVersion(asOf = "4.0")
|
||||
public void countShouldBePossibleInTransaction() {
|
||||
|
||||
assumeThat(ReplicaSet.required().runsAsReplicaSet()).isTrue();
|
||||
|
||||
MongoTransactionManager txmgr = new MongoTransactionManager(template.getMongoDbFactory());
|
||||
TransactionTemplate tt = new TransactionTemplate(txmgr);
|
||||
tt.afterPropertiesSet();
|
||||
|
||||
long countPreTx = repository.count();
|
||||
|
||||
long count = tt.execute(status -> {
|
||||
|
||||
Person sample = new Person();
|
||||
sample.setLastname("Matthews");
|
||||
|
||||
repository.save(sample);
|
||||
|
||||
return repository.count();
|
||||
});
|
||||
|
||||
assertThat(count).isEqualTo(countPreTx + 1);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2130
|
||||
@MongoVersion(asOf = "4.0")
|
||||
public void existsShouldBePossibleInTransaction() {
|
||||
|
||||
assumeThat(ReplicaSet.required().runsAsReplicaSet()).isTrue();
|
||||
|
||||
MongoTransactionManager txmgr = new MongoTransactionManager(template.getMongoDbFactory());
|
||||
TransactionTemplate tt = new TransactionTemplate(txmgr);
|
||||
tt.afterPropertiesSet();
|
||||
|
||||
boolean exists = tt.execute(status -> {
|
||||
|
||||
Person sample = new Person();
|
||||
sample.setLastname("Matthews");
|
||||
|
||||
repository.save(sample);
|
||||
|
||||
return repository.existsById(sample.getId());
|
||||
});
|
||||
|
||||
assertThat(exists).isTrue();
|
||||
}
|
||||
|
||||
private void assertThatAllReferencePersonsWereStoredCorrectly(Map<String, Person> references, List<Person> saved) {
|
||||
|
||||
for (Person person : saved) {
|
||||
|
||||
@@ -1,6 +1,31 @@
|
||||
Spring Data MongoDB Changelog
|
||||
=============================
|
||||
|
||||
Changes in version 2.1.3.RELEASE (2018-11-27)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-2139 - Auditing broken for entities using optimistic locking via version properties.
|
||||
* DATAMONGO-2135 - Use List instead of Collection when reading data with MappingMongoConverter.
|
||||
* DATAMONGO-2130 - Repository count errors in ClientSession / Transaction.
|
||||
* DATAMONGO-2121 - Release 2.1.3 (Lovelace SR3).
|
||||
* DATAMONGO-2119 - Combining a SpEL expression and a $regex filter triggers a PatternSyntaxException.
|
||||
|
||||
|
||||
Changes in version 2.0.12.RELEASE (2018-11-27)
|
||||
----------------------------------------------
|
||||
* DATAMONGO-2135 - Use List instead of Collection when reading data with MappingMongoConverter.
|
||||
* DATAMONGO-2119 - Combining a SpEL expression and a $regex filter triggers a PatternSyntaxException.
|
||||
* DATAMONGO-2118 - Fix typo in repositories reference documentation.
|
||||
* DATAMONGO-2109 - Release 2.0.12 (Kay SR12).
|
||||
* DATAMONGO-2098 - Typo in MappingMongoConverterParser.
|
||||
|
||||
|
||||
Changes in version 1.10.17.RELEASE (2018-11-27)
|
||||
-----------------------------------------------
|
||||
* DATAMONGO-2135 - Use List instead of Collection when reading data with MappingMongoConverter.
|
||||
* DATAMONGO-2118 - Fix typo in repositories reference documentation.
|
||||
* DATAMONGO-2110 - Release 1.10.17 (Ingalls SR17).
|
||||
|
||||
|
||||
Changes in version 2.1.2.RELEASE (2018-10-29)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-2118 - Fix typo in repositories reference documentation.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data MongoDB 2.1.2
|
||||
Spring Data MongoDB 2.1.3
|
||||
Copyright (c) [2010-2015] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
Reference in New Issue
Block a user