Browse Source

DATAMONGO-1176 - Polishing.

- Remove dropDups assertion as the MongoDB 3 driver does no longer provide dropDups even if running agains a MongoDB v2.6.7.
- Remove mongo-next build profile as we're based on the Mongo 3 driver now.
- Map update object and merge set operations.
pull/411/merge
Mark Paluch 10 years ago committed by Oliver Gierke
parent
commit
2d3efdc0b4
  1. 1
      .travis.yml
  2. 16
      pom.xml
  3. 98
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
  4. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  5. 66
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java
  6. 16
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java
  7. 124
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java

1
.travis.yml

@ -9,7 +9,6 @@ before_script:
env: env:
matrix: matrix:
- PROFILE=ci - PROFILE=ci
- PROFILE=mongo-next
- PROFILE=mongo3 - PROFILE=mongo3
- PROFILE=mongo3-next - PROFILE=mongo3-next
- PROFILE=mongo31 - PROFILE=mongo31

16
pom.xml

@ -113,22 +113,6 @@
</developers> </developers>
<profiles> <profiles>
<profile>
<id>mongo-next</id>
<properties>
<mongo>2.15.0-SNAPSHOT</mongo>
</properties>
<repositories>
<repository>
<id>mongo-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
</profile>
<profile> <profile>
<id>mongo3</id> <id>mongo3</id>

98
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java

@ -128,7 +128,7 @@ import com.mongodb.util.JSONParseException;
/** /**
* Primary implementation of {@link MongoOperations}. * Primary implementation of {@link MongoOperations}.
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Graeme Rocher * @author Graeme Rocher
* @author Mark Pollack * @author Mark Pollack
@ -181,7 +181,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Constructor used for a basic template configuration * Constructor used for a basic template configuration
* *
* @param mongo must not be {@literal null}. * @param mongo must not be {@literal null}.
* @param databaseName must not be {@literal null} or empty. * @param databaseName must not be {@literal null} or empty.
*/ */
@ -192,7 +192,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Constructor used for a template configuration with user credentials in the form of * Constructor used for a template configuration with user credentials in the form of
* {@link org.springframework.data.authentication.UserCredentials} * {@link org.springframework.data.authentication.UserCredentials}
* *
* @param mongo must not be {@literal null}. * @param mongo must not be {@literal null}.
* @param databaseName must not be {@literal null} or empty. * @param databaseName must not be {@literal null} or empty.
* @param userCredentials * @param userCredentials
@ -203,7 +203,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Constructor used for a basic template configuration. * Constructor used for a basic template configuration.
* *
* @param mongoDbFactory must not be {@literal null}. * @param mongoDbFactory must not be {@literal null}.
*/ */
public MongoTemplate(MongoDbFactory mongoDbFactory) { public MongoTemplate(MongoDbFactory mongoDbFactory) {
@ -212,7 +212,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Constructor used for a basic template configuration. * Constructor used for a basic template configuration.
* *
* @param mongoDbFactory must not be {@literal null}. * @param mongoDbFactory must not be {@literal null}.
* @param mongoConverter * @param mongoConverter
*/ */
@ -241,7 +241,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Configures the {@link WriteResultChecking} to be used with the template. Setting {@literal null} will reset the * Configures the {@link WriteResultChecking} to be used with the template. Setting {@literal null} will reset the
* default of {@value #DEFAULT_WRITE_RESULT_CHECKING}. * default of {@value #DEFAULT_WRITE_RESULT_CHECKING}.
* *
* @param resultChecking * @param resultChecking
*/ */
public void setWriteResultChecking(WriteResultChecking resultChecking) { public void setWriteResultChecking(WriteResultChecking resultChecking) {
@ -252,7 +252,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* Configures the {@link WriteConcern} to be used with the template. If none is configured the {@link WriteConcern} * Configures the {@link WriteConcern} to be used with the template. If none is configured the {@link WriteConcern}
* configured on the {@link MongoDbFactory} will apply. If you configured a {@link Mongo} instance no * configured on the {@link MongoDbFactory} will apply. If you configured a {@link Mongo} instance no
* {@link WriteConcern} will be used. * {@link WriteConcern} will be used.
* *
* @param writeConcern * @param writeConcern
*/ */
public void setWriteConcern(WriteConcern writeConcern) { public void setWriteConcern(WriteConcern writeConcern) {
@ -261,7 +261,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Configures the {@link WriteConcernResolver} to be used with the template. * Configures the {@link WriteConcernResolver} to be used with the template.
* *
* @param writeConcernResolver * @param writeConcernResolver
*/ */
public void setWriteConcernResolver(WriteConcernResolver writeConcernResolver) { public void setWriteConcernResolver(WriteConcernResolver writeConcernResolver) {
@ -271,7 +271,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Used by @{link {@link #prepareCollection(DBCollection)} to set the {@link ReadPreference} before any operations are * Used by @{link {@link #prepareCollection(DBCollection)} to set the {@link ReadPreference} before any operations are
* performed. * performed.
* *
* @param readPreference * @param readPreference
*/ */
public void setReadPreference(ReadPreference readPreference) { public void setReadPreference(ReadPreference readPreference) {
@ -298,7 +298,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* they were registered for the current {@link MappingContext}. If no creator for the current {@link MappingContext} * they were registered for the current {@link MappingContext}. If no creator for the current {@link MappingContext}
* can be found we manually add the internally created one as {@link ApplicationListener} to make sure indexes get * can be found we manually add the internally created one as {@link ApplicationListener} to make sure indexes get
* created appropriately for entity types persisted through this {@link MongoTemplate} instance. * created appropriately for entity types persisted through this {@link MongoTemplate} instance.
* *
* @param context must not be {@literal null}. * @param context must not be {@literal null}.
*/ */
private void prepareIndexCreator(ApplicationContext context) { private void prepareIndexCreator(ApplicationContext context) {
@ -319,14 +319,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Returns the default {@link org.springframework.data.mongodb.core.core.convert.MongoConverter}. * Returns the default {@link org.springframework.data.mongodb.core.core.convert.MongoConverter}.
* *
* @return * @return
*/ */
public MongoConverter getConverter() { public MongoConverter getConverter() {
return this.mongoConverter; return this.mongoConverter;
} }
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.data.mongodb.core.MongoOperations#executeAsStream(org.springframework.data.mongodb.core.query.Query, java.lang.Class) * @see org.springframework.data.mongodb.core.MongoOperations#executeAsStream(org.springframework.data.mongodb.core.query.Query, java.lang.Class)
*/ */
@ -437,7 +437,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Execute a MongoDB query and iterate over the query results on a per-document basis with a * Execute a MongoDB query and iterate over the query results on a per-document basis with a
* {@link DocumentCallbackHandler} using the provided CursorPreparer. * {@link DocumentCallbackHandler} using the provided CursorPreparer.
* *
* @param query the query class that specifies the criteria used to find a record and also an optional fields * @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification, must not be {@literal null}. * specification, must not be {@literal null}.
* @param collectionName name of the collection to retrieve the objects from * @param collectionName name of the collection to retrieve the objects from
@ -709,7 +709,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/* /*
* As MongoDB currently (2.4.4) doesn't support the skipping of elements in near queries * As MongoDB currently (2.4.4) doesn't support the skipping of elements in near queries
* we skip the elements ourselves to avoid at least the document 2 object mapping overhead. * we skip the elements ourselves to avoid at least the document 2 object mapping overhead.
* *
* @see https://jira.mongodb.org/browse/SERVER-3925 * @see https://jira.mongodb.org/browse/SERVER-3925
*/ */
if (index >= elementsToSkip) { if (index >= elementsToSkip) {
@ -814,7 +814,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Prepare the collection before any processing is done using it. This allows a convenient way to apply settings like * Prepare the collection before any processing is done using it. This allows a convenient way to apply settings like
* slaveOk() etc. Can be overridden in sub-classes. * slaveOk() etc. Can be overridden in sub-classes.
* *
* @param collection * @param collection
*/ */
protected MongoCollection<Document> prepareCollection(MongoCollection<Document> collection) { protected MongoCollection<Document> prepareCollection(MongoCollection<Document> collection) {
@ -830,7 +830,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* settings in sub-classes. <br /> * settings in sub-classes. <br />
* In case of using MongoDB Java driver version 3 the returned {@link WriteConcern} will be defaulted to * In case of using MongoDB Java driver version 3 the returned {@link WriteConcern} will be defaulted to
* {@link WriteConcern#ACKNOWLEDGED} when {@link WriteResultChecking} is set to {@link WriteResultChecking#EXCEPTION}. * {@link WriteConcern#ACKNOWLEDGED} when {@link WriteResultChecking} is set to {@link WriteResultChecking#EXCEPTION}.
* *
* @param writeConcern any WriteConcern already configured or null * @param writeConcern any WriteConcern already configured or null
* @return The prepared WriteConcern or null * @return The prepared WriteConcern or null
*/ */
@ -1225,19 +1225,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
UpdateOptions opts = new UpdateOptions(); UpdateOptions opts = new UpdateOptions();
opts.upsert(upsert); opts.upsert(upsert);
// TODO hack - split up update and replaces
boolean useUpdate = false;
for (String s : updateObj.keySet()) {
if (s.startsWith("$")) {
useUpdate = true;
break;
}
}
collection = writeConcernToUse != null ? collection.withWriteConcern(writeConcernToUse) : collection; collection = writeConcernToUse != null ? collection.withWriteConcern(writeConcernToUse) : collection;
if (!useUpdate) { if (!UpdateMapper.isUpdateObject(updateObj)) {
return collection.replaceOne(queryObj, updateObj, opts); return collection.replaceOne(queryObj, updateObj, opts);
} else { } else {
if (multi) { if (multi) {
@ -1292,7 +1282,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Returns {@link Entry} containing the field name of the id property as {@link Entry#getKey()} and the {@link Id}s * Returns {@link Entry} containing the field name of the id property as {@link Entry#getKey()} and the {@link Id}s
* property value as its {@link Entry#getValue()}. * property value as its {@link Entry#getValue()}.
* *
* @param object * @param object
* @return * @return
*/ */
@ -1319,7 +1309,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Returns a {@link Query} for the given entity by its id. * Returns a {@link Query} for the given entity by its id.
* *
* @param object must not be {@literal null}. * @param object must not be {@literal null}.
* @return * @return
*/ */
@ -1331,7 +1321,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Returns a {@link Query} for the given entities by their ids. * Returns a {@link Query} for the given entities by their ids.
* *
* @param objects must not be {@literal null} or {@literal empty}. * @param objects must not be {@literal null} or {@literal empty}.
* @return * @return
*/ */
@ -1623,7 +1613,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* Retrieve and remove all documents matching the given {@code query} by calling {@link #find(Query, Class, String)} * Retrieve and remove all documents matching the given {@code query} by calling {@link #find(Query, Class, String)}
* and {@link #remove(Query, Class, String)}, whereas the {@link Query} for {@link #remove(Query, Class, String)} is * and {@link #remove(Query, Class, String)}, whereas the {@link Query} for {@link #remove(Query, Class, String)} is
* constructed out of the find result. * constructed out of the find result.
* *
* @param collectionName * @param collectionName
* @param query * @param query
* @param entityClass * @param entityClass
@ -1661,8 +1651,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} }
/** /**
* Returns the potentially mapped results of the given {@commandResult} contained some. * Returns the potentially mapped results of the given {@code commandResult}.
* *
* @param outputType * @param outputType
* @param commandResult * @param commandResult
* @return * @return
@ -1739,7 +1729,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Create the specified collection using the provided options * Create the specified collection using the provided options
* *
* @param collectionName * @param collectionName
* @param collectionOptions * @param collectionOptions
* @return the collection that was created * @return the collection that was created
@ -1776,7 +1766,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter. * Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter.
* The query document is specified as a standard {@link Document} and so is the fields specification. * The query document is specified as a standard {@link Document} and so is the fields specification.
* *
* @param collectionName name of the collection to retrieve the objects from. * @param collectionName name of the collection to retrieve the objects from.
* @param query the query document that specifies the criteria used to find a record. * @param query the query document that specifies the criteria used to find a record.
* @param fields the document that specifies the fields to be returned. * @param fields the document that specifies the fields to be returned.
@ -1801,7 +1791,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Map the results of an ad-hoc query on the default MongoDB collection to a List using the template's converter. The * Map the results of an ad-hoc query on the default MongoDB collection to a List using the template's converter. The
* query document is specified as a standard Document and so is the fields specification. * query document is specified as a standard Document and so is the fields specification.
* *
* @param collectionName name of the collection to retrieve the objects from * @param collectionName name of the collection to retrieve the objects from
* @param query the query document that specifies the criteria used to find a record * @param query the query document that specifies the criteria used to find a record
* @param fields the document that specifies the fields to be returned * @param fields the document that specifies the fields to be returned
@ -1817,7 +1807,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. The object is * Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. The object is
* converted from the MongoDB native representation using an instance of {@see MongoConverter}. The query document is * converted from the MongoDB native representation using an instance of {@see MongoConverter}. The query document is
* specified as a standard Document and so is the fields specification. * specified as a standard Document and so is the fields specification.
* *
* @param collectionName name of the collection to retrieve the objects from. * @param collectionName name of the collection to retrieve the objects from.
* @param query the query document that specifies the criteria used to find a record. * @param query the query document that specifies the criteria used to find a record.
* @param fields the document that specifies the fields to be returned. * @param fields the document that specifies the fields to be returned.
@ -1870,7 +1860,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* The first document that matches the query is returned and also removed from the collection in the database. * The first document that matches the query is returned and also removed from the collection in the database.
* <p/> * <p/>
* The query document is specified as a standard Document and so is the fields specification. * The query document is specified as a standard Document and so is the fields specification.
* *
* @param collectionName name of the collection to retrieve the objects from * @param collectionName name of the collection to retrieve the objects from
* @param query the query document that specifies the criteria used to find a record * @param query the query document that specifies the criteria used to find a record
* @param entityClass the parameterized type of the returned list. * @param entityClass the parameterized type of the returned list.
@ -1921,7 +1911,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Populates the id property of the saved object, if it's not set already. * Populates the id property of the saved object, if it's not set already.
* *
* @param savedObject * @param savedObject
* @param id * @param id
*/ */
@ -1971,7 +1961,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* <li>Execute the given {@link ConnectionCallback} for a {@link Document}.</li> * <li>Execute the given {@link ConnectionCallback} for a {@link Document}.</li>
* <li>Apply the given {@link DbObjectCallback} to each of the {@link Document}s to obtain the result.</li> * <li>Apply the given {@link DbObjectCallback} to each of the {@link Document}s to obtain the result.</li>
* <ol> * <ol>
* *
* @param <T> * @param <T>
* @param collectionCallback the callback to retrieve the {@link Document} with * @param collectionCallback the callback to retrieve the {@link Document} with
* @param objectCallback the {@link DbObjectCallback} to transform {@link Document}s into the actual domain type * @param objectCallback the {@link DbObjectCallback} to transform {@link Document}s into the actual domain type
@ -2000,7 +1990,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* <li>Iterate over the {@link DBCursor} and applies the given {@link DbObjectCallback} to each of the * <li>Iterate over the {@link DBCursor} and applies the given {@link DbObjectCallback} to each of the
* {@link Document}s collecting the actual result {@link List}.</li> * {@link Document}s collecting the actual result {@link List}.</li>
* <ol> * <ol>
* *
* @param <T> * @param <T>
* @param collectionCallback the callback to retrieve the {@link DBCursor} with * @param collectionCallback the callback to retrieve the {@link DBCursor} with
* @param preparer the {@link CursorPreparer} to potentially modify the {@link DBCursor} before ireating over it * @param preparer the {@link CursorPreparer} to potentially modify the {@link DBCursor} before ireating over it
@ -2113,7 +2103,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Handles {@link WriteResult} errors based on the configured {@link WriteResultChecking}. * Handles {@link WriteResult} errors based on the configured {@link WriteResultChecking}.
* *
* @param writeResult * @param writeResult
* @param query * @param query
* @param operation * @param operation
@ -2157,7 +2147,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Inspects the given {@link CommandResult} for erros and potentially throws an * Inspects the given {@link CommandResult} for erros and potentially throws an
* {@link InvalidDataAccessApiUsageException} for that error. * {@link InvalidDataAccessApiUsageException} for that error.
* *
* @param result must not be {@literal null}. * @param result must not be {@literal null}.
* @param source must not be {@literal null}. * @param source must not be {@literal null}.
*/ */
@ -2195,12 +2185,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Tries to convert the given {@link RuntimeException} into a {@link DataAccessException} but returns the original * Tries to convert the given {@link RuntimeException} into a {@link DataAccessException} but returns the original
* exception if the conversation failed. Thus allows safe re-throwing of the return value. * exception if the conversation failed. Thus allows safe re-throwing of the return value.
* *
* @param ex the exception to translate * @param ex the exception to translate
* @param exceptionTranslator the {@link PersistenceExceptionTranslator} to be used for translation * @param exceptionTranslator the {@link PersistenceExceptionTranslator} to be used for translation
* @return * @return
*/ */
private static RuntimeException potentiallyConvertRuntimeException(RuntimeException ex, static RuntimeException potentiallyConvertRuntimeException(RuntimeException ex,
PersistenceExceptionTranslator exceptionTranslator) { PersistenceExceptionTranslator exceptionTranslator) {
RuntimeException resolved = exceptionTranslator.translateExceptionIfPossible(ex); RuntimeException resolved = exceptionTranslator.translateExceptionIfPossible(ex);
return resolved == null ? ex : resolved; return resolved == null ? ex : resolved;
@ -2234,7 +2224,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Simple {@link CollectionCallback} that takes a query {@link Document} plus an optional fields specification * Simple {@link CollectionCallback} that takes a query {@link Document} plus an optional fields specification
* {@link Document} and executes that against the {@link DBCollection}. * {@link Document} and executes that against the {@link DBCollection}.
* *
* @author Oliver Gierke * @author Oliver Gierke
* @author Thomas Risberg * @author Thomas Risberg
*/ */
@ -2268,7 +2258,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Simple {@link CollectionCallback} that takes a query {@link Document} plus an optional fields specification * Simple {@link CollectionCallback} that takes a query {@link Document} plus an optional fields specification
* {@link Document} and executes that against the {@link DBCollection}. * {@link Document} and executes that against the {@link DBCollection}.
* *
* @author Oliver Gierke * @author Oliver Gierke
* @author Thomas Risberg * @author Thomas Risberg
*/ */
@ -2300,7 +2290,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Simple {@link CollectionCallback} that takes a query {@link Document} plus an optional fields specification * Simple {@link CollectionCallback} that takes a query {@link Document} plus an optional fields specification
* {@link Document} and executes that against the {@link DBCollection}. * {@link Document} and executes that against the {@link DBCollection}.
* *
* @author Thomas Risberg * @author Thomas Risberg
*/ */
private static class FindAndRemoveCallback implements CollectionCallback<Document> { private static class FindAndRemoveCallback implements CollectionCallback<Document> {
@ -2360,7 +2350,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Simple internal callback to allow operations on a {@link Document}. * Simple internal callback to allow operations on a {@link Document}.
* *
* @author Oliver Gierke * @author Oliver Gierke
* @author Thomas Darimont * @author Thomas Darimont
*/ */
@ -2373,7 +2363,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Simple {@link DbObjectCallback} that will transform {@link Document} into the given target type using the given * Simple {@link DbObjectCallback} that will transform {@link Document} into the given target type using the given
* {@link MongoReader}. * {@link MongoReader}.
* *
* @author Oliver Gierke * @author Oliver Gierke
* @author Christoph Strobl * @author Christoph Strobl
*/ */
@ -2513,7 +2503,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* {@link DbObjectCallback} that assumes a {@link GeoResult} to be created, delegates actual content unmarshalling to * {@link DbObjectCallback} that assumes a {@link GeoResult} to be created, delegates actual content unmarshalling to
* a delegate and creates a {@link GeoResult} from the result. * a delegate and creates a {@link GeoResult} from the result.
* *
* @author Oliver Gierke * @author Oliver Gierke
*/ */
static class GeoNearResultDbObjectCallback<T> implements DbObjectCallback<GeoResult<T>> { static class GeoNearResultDbObjectCallback<T> implements DbObjectCallback<GeoResult<T>> {
@ -2524,7 +2514,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Creates a new {@link GeoNearResultDbObjectCallback} using the given {@link DbObjectCallback} delegate for * Creates a new {@link GeoNearResultDbObjectCallback} using the given {@link DbObjectCallback} delegate for
* {@link GeoResult} content unmarshalling. * {@link GeoResult} content unmarshalling.
* *
* @param delegate must not be {@literal null}. * @param delegate must not be {@literal null}.
*/ */
public GeoNearResultDbObjectCallback(DbObjectCallback<T> delegate, Metric metric) { public GeoNearResultDbObjectCallback(DbObjectCallback<T> delegate, Metric metric) {
@ -2546,7 +2536,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* A {@link CloseableIterator} that is backed by a MongoDB {@link Cursor}. * A {@link CloseableIterator} that is backed by a MongoDB {@link Cursor}.
* *
* @since 1.7 * @since 1.7
* @author Thomas Darimont * @author Thomas Darimont
*/ */
@ -2565,7 +2555,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Creates a new {@link CloseableIterableCursorAdapter} backed by the given {@link Cursor}. * Creates a new {@link CloseableIterableCursorAdapter} backed by the given {@link Cursor}.
* *
* @param cursor * @param cursor
* @param exceptionTranslator * @param exceptionTranslator
* @param objectReadCallback * @param objectReadCallback

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

@ -1114,7 +1114,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
} }
if (obj instanceof Map) { if (obj instanceof Map) {
Document result = new Document(); Document result = new Document();
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) obj).entrySet()) { for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) obj).entrySet()) {
result.put(entry.getKey().toString(), convertToMongoType(entry.getValue(), typeHint)); result.put(entry.getKey().toString(), convertToMongoType(entry.getValue(), typeHint));

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

@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core.convert;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.bson.Document; import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mapping.Association; import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.context.MappingContext;
@ -35,6 +36,7 @@ import org.springframework.data.util.TypeInformation;
* @author Thomas Darimont * @author Thomas Darimont
* @author Oliver Gierke * @author Oliver Gierke
* @author Christoph Strobl * @author Christoph Strobl
* @author Mark Paluch
*/ */
public class UpdateMapper extends QueryMapper { public class UpdateMapper extends QueryMapper {
@ -51,6 +53,70 @@ public class UpdateMapper extends QueryMapper {
this.converter = converter; this.converter = converter;
} }
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.QueryMapper#getMappedObject(Bson, MongoPersistentEntity)
*/
@Override
public Document getMappedObject(Bson query, MongoPersistentEntity<?> entity) {
Document document = super.getMappedObject(query, entity);
boolean hasOperators = false;
boolean hasFields = false;
Document set = null;
for (String s : document.keySet()) {
if (s.startsWith("$")) {
if(s.equals("$set")){
set = document.get(s, Document.class);
}
hasOperators = true;
} else {
hasFields = true;
}
}
if (hasOperators && hasFields) {
Document updateObject = new Document();
Document fieldsToSet = set == null ? new Document() : set;
for (String s : document.keySet()) {
if (s.startsWith("$")) {
updateObject.put(s, document.get(s));
} else {
fieldsToSet.put(s, document.get(s));
}
}
updateObject.put("$set", fieldsToSet);
return updateObject;
}
return document;
}
/**
* Returns {@literal true} if the given {@link Document} is an update object that uses update operators.
* @param updateObj
* @return {@literal true} if the given {@link Document} is an update object.
*/
public static boolean isUpdateObject(Document updateObj) {
if (updateObj == null) {
return false;
}
for (String s : updateObj.keySet()) {
if (s.startsWith("$")) {
return true;
}
}
return false;
}
/** /**
* Converts the given source object to a mongo type retaining the original type information of the source type on the * Converts the given source object to a mongo type retaining the original type information of the source type on the
* mongo type. * mongo type.

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

@ -360,18 +360,12 @@ public class MongoTemplateTests {
assertThat(indexInfo.size(), is(2)); assertThat(indexInfo.size(), is(2));
Object indexKey = null; Object indexKey = null;
boolean unique = false; boolean unique = false;
boolean dropDupes = false;
for (org.bson.Document ix : indexInfo) { for (org.bson.Document ix : indexInfo) {
if ("age_-1".equals(ix.get("name"))) { if ("age_-1".equals(ix.get("name"))) {
indexKey = ix.get("key"); indexKey = ix.get("key");
unique = (Boolean) ix.get("unique"); unique = (Boolean) ix.get("unique");
if (mongoVersion.isLessThan(TWO_DOT_EIGHT)) { assertThat(ix.get("dropDups"), is(nullValue()));
dropDupes = (Boolean) ix.get("dropDups");
assertThat(dropDupes, is(true));
} else {
assertThat(ix.get("dropDups"), is(nullValue()));
}
} }
} }
assertThat(((org.bson.Document) indexKey), IsMapContaining.<String, Object> hasEntry("age", -1)); assertThat(((org.bson.Document) indexKey), IsMapContaining.<String, Object> hasEntry("age", -1));
@ -382,13 +376,7 @@ public class MongoTemplateTests {
assertThat(indexInfoList.size(), is(2)); assertThat(indexInfoList.size(), is(2));
IndexInfo ii = indexInfoList.get(1); IndexInfo ii = indexInfoList.get(1);
assertThat(ii.isUnique(), is(true)); assertThat(ii.isUnique(), is(true));
assertThat(ii.isDropDuplicates(), is(false));
if (mongoVersion.isLessThan(TWO_DOT_EIGHT)) {
assertThat(ii.isDropDuplicates(), is(true));
} else {
assertThat(ii.isDropDuplicates(), is(false));
}
assertThat(ii.isSparse(), is(false)); assertThat(ii.isSparse(), is(false));
List<IndexField> indexFields = ii.getIndexFields(); List<IndexField> indexFields = ii.getIndexFields();

124
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java

@ -44,9 +44,6 @@ import org.springframework.data.convert.WritingConverter;
import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.DBObjectTestUtils; import org.springframework.data.mongodb.core.DBObjectTestUtils;
import org.springframework.data.mongodb.core.convert.UpdateMapperUnitTests.ClassWithEnum.Allocation;
import org.springframework.data.mongodb.core.convert.UpdateMapperUnitTests.ClassWithEnum.AllocationToStringConverter;
import org.springframework.data.mongodb.core.convert.UpdateMapperUnitTests.ClassWithEnum.StringToAllocationConverter;
import org.springframework.data.mongodb.core.mapping.Field; import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Criteria;
@ -105,7 +102,7 @@ public class UpdateMapperUnitTests {
Document push = getAsDocument(mappedObject, "$push"); Document push = getAsDocument(mappedObject, "$push");
Document list = getAsDocument(push, "aliased"); Document list = getAsDocument(push, "aliased");
assertThat(list.get("_class"), is((Object) ConcreteChildClass.class.getName())); assertThat(list.get("_class"), is(ConcreteChildClass.class.getName()));
} }
/** /**
@ -171,7 +168,7 @@ public class UpdateMapperUnitTests {
Document set = getAsDocument(mappedObject, "$set"); Document set = getAsDocument(mappedObject, "$set");
Document modelDbObject = getAsDocument(set, "aliased.$"); Document modelDbObject = getAsDocument(set, "aliased.$");
assertThat(modelDbObject.get("_class"), is((Object) ConcreteChildClass.class.getName())); assertThat(modelDbObject.get("_class"), is(ConcreteChildClass.class.getName()));
} }
/** /**
@ -187,8 +184,8 @@ public class UpdateMapperUnitTests {
context.getPersistentEntity(ParentClass.class)); context.getPersistentEntity(ParentClass.class));
Document set = getAsDocument(mappedObject, "$set"); Document set = getAsDocument(mappedObject, "$set");
assertThat(set.get("aliased.$.value"), is((Object) "foo")); assertThat(set.get("aliased.$.value"), is("foo"));
assertThat(set.get("aliased.$.otherValue"), is((Object) "bar")); assertThat(set.get("aliased.$.otherValue"), is("bar"));
} }
/** /**
@ -204,12 +201,12 @@ public class UpdateMapperUnitTests {
context.getPersistentEntity(ParentClass.class)); context.getPersistentEntity(ParentClass.class));
Document dbo = getAsDocument(mappedObject, "$set"); Document dbo = getAsDocument(mappedObject, "$set");
assertThat(dbo.get("aliased.$.value"), is((Object) "foo")); assertThat(dbo.get("aliased.$.value"), is("foo"));
Document someObject = getAsDocument(dbo, "aliased.$.someObject"); Document someObject = getAsDocument(dbo, "aliased.$.someObject");
assertThat(someObject, is(notNullValue())); assertThat(someObject, is(notNullValue()));
assertThat(someObject.get("_class"), is((Object) ConcreteChildClass.class.getName())); assertThat(someObject.get("_class"), is(ConcreteChildClass.class.getName()));
assertThat(someObject.get("value"), is((Object) "bubu")); assertThat(someObject.get("value"), is("bubu"));
} }
/** /**
@ -229,7 +226,7 @@ public class UpdateMapperUnitTests {
assertThat(push.get("_class"), nullValue()); assertThat(push.get("_class"), nullValue());
assertThat(values.get("_class"), nullValue()); assertThat(values.get("_class"), nullValue());
assertThat(each, IsIterableContainingInOrder.<Object> contains("spring", "data", "mongodb")); assertThat(each, IsIterableContainingInOrder.contains("spring", "data", "mongodb"));
} }
/** /**
@ -264,7 +261,7 @@ public class UpdateMapperUnitTests {
List<Object> each = getAsDBList(model, "$each"); List<Object> each = getAsDBList(model, "$each");
List<Object> values = getAsDBList((Document) each.get(0), "values"); List<Object> values = getAsDBList((Document) each.get(0), "values");
assertThat(values, IsIterableContainingInOrder.<Object> contains("spring", "data", "mongodb")); assertThat(values, IsIterableContainingInOrder.contains("spring", "data", "mongodb"));
} }
/** /**
@ -312,7 +309,7 @@ public class UpdateMapperUnitTests {
Document key = getAsDocument(push, "key"); Document key = getAsDocument(push, "key");
assertThat(key.containsKey("$position"), is(true)); assertThat(key.containsKey("$position"), is(true));
assertThat((Integer) key.get("$position"), is(2)); assertThat(key.get("$position"), is(2));
assertThat(getAsDocument(push, "key").containsKey("$each"), is(true)); assertThat(getAsDocument(push, "key").containsKey("$each"), is(true));
} }
@ -330,7 +327,7 @@ public class UpdateMapperUnitTests {
Document key = getAsDocument(push, "key"); Document key = getAsDocument(push, "key");
assertThat(key.containsKey("$position"), is(true)); assertThat(key.containsKey("$position"), is(true));
assertThat((Integer) key.get("$position"), is(0)); assertThat(key.get("$position"), is(0));
assertThat(getAsDocument(push, "key").containsKey("$each"), is(true)); assertThat(getAsDocument(push, "key").containsKey("$each"), is(true));
} }
@ -382,7 +379,7 @@ public class UpdateMapperUnitTests {
Document key = getAsDocument(push, "key"); Document key = getAsDocument(push, "key");
assertThat(key.containsKey("$slice"), is(true)); assertThat(key.containsKey("$slice"), is(true));
assertThat((Integer) key.get("$slice"), is(5)); assertThat(key.get("$slice"), is(5));
assertThat(key.containsKey("$each"), is(true)); assertThat(key.containsKey("$each"), is(true));
} }
@ -401,13 +398,13 @@ public class UpdateMapperUnitTests {
Document key = getAsDocument(push, "key"); Document key = getAsDocument(push, "key");
assertThat(key.containsKey("$slice"), is(true)); assertThat(key.containsKey("$slice"), is(true));
assertThat((Integer) key.get("$slice"), is(5)); assertThat(key.get("$slice"), is(5));
assertThat(key.containsKey("$each"), is(true)); assertThat(key.containsKey("$each"), is(true));
Document key2 = getAsDocument(push, "key-2"); Document key2 = getAsDocument(push, "key-2");
assertThat(key2.containsKey("$slice"), is(true)); assertThat(key2.containsKey("$slice"), is(true));
assertThat((Integer) key2.get("$slice"), is(-2)); assertThat(key2.get("$slice"), is(-2));
assertThat(key2.containsKey("$each"), is(true)); assertThat(key2.containsKey("$each"), is(true));
} }
@ -439,7 +436,7 @@ public class UpdateMapperUnitTests {
context.getPersistentEntity(DocumentWithDBRefCollection.class)); context.getPersistentEntity(DocumentWithDBRefCollection.class));
Document pullClause = getAsDocument(mappedObject, "$pull"); Document pullClause = getAsDocument(mappedObject, "$pull");
assertThat(pullClause.get("dbRefAnnotatedList"), is((Object) new DBRef("entity", "2"))); assertThat(pullClause.get("dbRefAnnotatedList"), is(new DBRef("entity", "2")));
} }
/** /**
@ -456,7 +453,7 @@ public class UpdateMapperUnitTests {
context.getPersistentEntity(DocumentWithDBRefCollection.class)); context.getPersistentEntity(DocumentWithDBRefCollection.class));
Document pullClause = getAsDocument(mappedObject, "$pull"); Document pullClause = getAsDocument(mappedObject, "$pull");
assertThat(pullClause.get("dbRefAnnotatedList"), is((Object) new DBRef("entity", entity.id))); assertThat(pullClause.get("dbRefAnnotatedList"), is(new DBRef("entity", entity.id)));
} }
/** /**
@ -497,7 +494,7 @@ public class UpdateMapperUnitTests {
context.getPersistentEntity(DocumentWithDBRefCollection.class)); context.getPersistentEntity(DocumentWithDBRefCollection.class));
Document setClause = getAsDocument(mappedObject, "$set"); Document setClause = getAsDocument(mappedObject, "$set");
assertThat(setClause.get("dbRefProperty"), is((Object) new DBRef("entity", entity.id))); assertThat(setClause.get("dbRefProperty"), is(new DBRef("entity", entity.id)));
} }
/** /**
@ -532,7 +529,7 @@ public class UpdateMapperUnitTests {
Document idClause = getAsDocument(options, "_id"); Document idClause = getAsDocument(options, "_id");
List<Object> inClause = getAsDBList(idClause, "$in"); List<Object> inClause = getAsDBList(idClause, "$in");
assertThat(inClause, IsIterableContainingInOrder.<Object> contains(1L, 2L)); assertThat(inClause, IsIterableContainingInOrder.contains(1L, 2L));
} }
/** /**
@ -550,7 +547,7 @@ public class UpdateMapperUnitTests {
Document values = getAsDocument(addToSet, "values"); Document values = getAsDocument(addToSet, "values");
List<Object> each = getAsDBList(values, "$each"); List<Object> each = getAsDBList(values, "$each");
assertThat(each, IsIterableContainingInOrder.<Object> contains("spring", "data", "mongodb")); assertThat(each, IsIterableContainingInOrder.contains("spring", "data", "mongodb"));
} }
/** /**
@ -588,7 +585,7 @@ public class UpdateMapperUnitTests {
Object model = $set.get("referencedDocument"); Object model = $set.get("referencedDocument");
DBRef expectedDBRef = new DBRef("interfaceDocumentDefinitionImpl", "1"); DBRef expectedDBRef = new DBRef("interfaceDocumentDefinitionImpl", "1");
assertThat(model, allOf(instanceOf(DBRef.class), IsEqual.<Object> equalTo(expectedDBRef))); assertThat(model, allOf(instanceOf(DBRef.class), IsEqual.equalTo(expectedDBRef)));
} }
/** /**
@ -606,7 +603,7 @@ public class UpdateMapperUnitTests {
Document value = DBObjectTestUtils.getAsDocument(list, "value"); Document value = DBObjectTestUtils.getAsDocument(list, "value");
List<Object> $in = DBObjectTestUtils.getAsDBList(value, "$in"); List<Object> $in = DBObjectTestUtils.getAsDBList(value, "$in");
assertThat($in, IsIterableContainingInOrder.<Object> contains("foo", "bar")); assertThat($in, IsIterableContainingInOrder.contains("foo", "bar"));
} }
/** /**
@ -719,7 +716,7 @@ public class UpdateMapperUnitTests {
public void mappingShouldRetainTypeInformationOfNestedListWhenUpdatingConcreteyParentType() { public void mappingShouldRetainTypeInformationOfNestedListWhenUpdatingConcreteyParentType() {
ListModelWrapper lmw = new ListModelWrapper(); ListModelWrapper lmw = new ListModelWrapper();
lmw.models = Collections.<Model> singletonList(new ModelImpl(1)); lmw.models = Collections.singletonList(new ModelImpl(1));
Update update = new Update().set("concreteTypeWithListAttributeOfInterfaceType", lmw); Update update = new Update().set("concreteTypeWithListAttributeOfInterfaceType", lmw);
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
@ -778,7 +775,7 @@ public class UpdateMapperUnitTests {
@Test @Test
public void mappingShouldRetrainTypeInformationWhenValueTypeOfMapDoesNotMatchItsDeclaration() { public void mappingShouldRetrainTypeInformationWhenValueTypeOfMapDoesNotMatchItsDeclaration() {
Map<Object, Object> map = Collections.<Object, Object> singletonMap("szeth", new NestedDocument("son-son-vallano")); Map<Object, Object> map = Collections.singletonMap("szeth", new NestedDocument("son-son-vallano"));
Update update = new Update().set("map", map); Update update = new Update().set("map", map);
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
@ -794,7 +791,7 @@ public class UpdateMapperUnitTests {
@Test @Test
public void mappingShouldNotContainTypeInformationWhenValueTypeOfMapMatchesDeclaration() { public void mappingShouldNotContainTypeInformationWhenValueTypeOfMapMatchesDeclaration() {
Map<Object, NestedDocument> map = Collections.<Object, NestedDocument> singletonMap("jasnah", Map<Object, NestedDocument> map = Collections.singletonMap("jasnah",
new NestedDocument("kholin")); new NestedDocument("kholin"));
Update update = new Update().set("concreteMap", map); Update update = new Update().set("concreteMap", map);
@ -813,7 +810,7 @@ public class UpdateMapperUnitTests {
public void mapsUpdateWithBothReadingAndWritingConverterRegistered() { public void mapsUpdateWithBothReadingAndWritingConverterRegistered() {
CustomConversions conversions = new CustomConversions( CustomConversions conversions = new CustomConversions(
Arrays.asList(AllocationToStringConverter.INSTANCE, StringToAllocationConverter.INSTANCE)); Arrays.asList(ClassWithEnum.AllocationToStringConverter.INSTANCE, ClassWithEnum.StringToAllocationConverter.INSTANCE));
MongoMappingContext mappingContext = new MongoMappingContext(); MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder()); mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
@ -825,11 +822,11 @@ public class UpdateMapperUnitTests {
UpdateMapper mapper = new UpdateMapper(converter); UpdateMapper mapper = new UpdateMapper(converter);
Update update = new Update().set("allocation", Allocation.AVAILABLE); Update update = new Update().set("allocation", ClassWithEnum.Allocation.AVAILABLE);
Document result = mapper.getMappedObject(update.getUpdateObject(), Document result = mapper.getMappedObject(update.getUpdateObject(),
mappingContext.getPersistentEntity(ClassWithEnum.class)); mappingContext.getPersistentEntity(ClassWithEnum.class));
assertThat(result, isBsonObject().containing("$set.allocation", Allocation.AVAILABLE.code)); assertThat(result, isBsonObject().containing("$set.allocation", ClassWithEnum.Allocation.AVAILABLE.code));
} }
/** /**
@ -907,7 +904,7 @@ public class UpdateMapperUnitTests {
context.getPersistentEntity(SimpleValueHolder.class)); context.getPersistentEntity(SimpleValueHolder.class));
Document $set = DBObjectTestUtils.getAsDocument(mappedUpdate, "$set"); Document $set = DBObjectTestUtils.getAsDocument(mappedUpdate, "$set");
assertThat($set.get("intValue"), Is.<Object> is(10)); assertThat($set.get("intValue"), Is.is(10));
} }
/** /**
@ -921,7 +918,7 @@ public class UpdateMapperUnitTests {
context.getPersistentEntity(SimpleValueHolder.class)); context.getPersistentEntity(SimpleValueHolder.class));
Document $set = DBObjectTestUtils.getAsDocument(mappedUpdate, "$set"); Document $set = DBObjectTestUtils.getAsDocument(mappedUpdate, "$set");
assertThat($set.get("primIntValue"), Is.<Object> is(10)); assertThat($set.get("primIntValue"), Is.is(10));
} }
/** /**
@ -958,7 +955,7 @@ public class UpdateMapperUnitTests {
public void mappingShouldConsiderCustomConvertersForEnumMapKeys() { public void mappingShouldConsiderCustomConvertersForEnumMapKeys() {
CustomConversions conversions = new CustomConversions( CustomConversions conversions = new CustomConversions(
Arrays.asList(AllocationToStringConverter.INSTANCE, StringToAllocationConverter.INSTANCE)); Arrays.asList(ClassWithEnum.AllocationToStringConverter.INSTANCE, ClassWithEnum.StringToAllocationConverter.INSTANCE));
MongoMappingContext mappingContext = new MongoMappingContext(); MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder()); mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
@ -970,7 +967,7 @@ public class UpdateMapperUnitTests {
UpdateMapper mapper = new UpdateMapper(converter); UpdateMapper mapper = new UpdateMapper(converter);
Update update = new Update().set("enumAsMapKey", Collections.singletonMap(Allocation.AVAILABLE, 100)); Update update = new Update().set("enumAsMapKey", Collections.singletonMap(ClassWithEnum.Allocation.AVAILABLE, 100));
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
mappingContext.getPersistentEntity(ClassWithEnum.class)); mappingContext.getPersistentEntity(ClassWithEnum.class));
@ -981,6 +978,51 @@ public class UpdateMapperUnitTests {
assertThat(enumAsMapKey.get("AVAILABLE"), is(100)); assertThat(enumAsMapKey.get("AVAILABLE"), is(100));
} }
/**
* @see DATAMONGO-1176
*/
@Test
public void mappingShouldPrepareUpdateObjectForMixedOperatorsAndFields() {
Document document = new Document("key", "value").append("$set", new Document("a", "b").append("x", "y"));
Document mappedObject = mapper.getMappedObject(document, context.getPersistentEntity(SimpleValueHolder.class));
assertThat(mappedObject.get("$set"), is(equalTo(new Document("a", "b").append("x", "y").append("key", "value"))));
assertThat(mappedObject.size(), is(1));
}
/**
* @see DATAMONGO-1176
*/
@Test
public void mappingShouldReturnReplaceObject() {
Document document = new Document("key", "value").append("a", "b").append("x", "y");
Document mappedObject = mapper.getMappedObject(document, context.getPersistentEntity(SimpleValueHolder.class));
assertThat(mappedObject.get("key"), is(equalTo("value")));
assertThat(mappedObject.get("a"), is(equalTo("b")));
assertThat(mappedObject.get("x"), is(equalTo("y")));
assertThat(mappedObject.size(), is(3));
}
/**
* @see DATAMONGO-1176
*/
@Test
public void mappingShouldReturnUpdateObject() {
Document document = new Document("$push", new Document("x", "y")).append("$set", new Document("a", "b"));
Document mappedObject = mapper.getMappedObject(document, context.getPersistentEntity(SimpleValueHolder.class));
assertThat(mappedObject.get("$push"), is(equalTo(new Document("x", "y"))));
assertThat(mappedObject.get("$set"), is(equalTo(new Document("a", "b"))));
assertThat(mappedObject.size(), is(2));
}
/** /**
* @see DATAMONGO-1486 * @see DATAMONGO-1486
*/ */
@ -1011,7 +1053,7 @@ public class UpdateMapperUnitTests {
} }
@org.springframework.data.mongodb.core.mapping.Document(collection = "DocumentWithReferenceToInterface") @org.springframework.data.mongodb.core.mapping.Document(collection = "DocumentWithReferenceToInterface")
static interface DocumentWithReferenceToInterface { interface DocumentWithReferenceToInterface {
String getId(); String getId();
@ -1019,7 +1061,7 @@ public class UpdateMapperUnitTests {
} }
static interface InterfaceDocumentDefinitionWithoutId { interface InterfaceDocumentDefinitionWithoutId {
String getValue(); String getValue();
} }
@ -1068,7 +1110,7 @@ public class UpdateMapperUnitTests {
} }
static interface Model {} interface Model {}
static class ModelImpl implements Model { static class ModelImpl implements Model {
public int value; public int value;
@ -1226,13 +1268,13 @@ public class UpdateMapperUnitTests {
Allocation allocation; Allocation allocation;
Map<Allocation, String> enumAsMapKey; Map<Allocation, String> enumAsMapKey;
static enum Allocation { enum Allocation {
AVAILABLE("V"), ALLOCATED("A"); AVAILABLE("V"), ALLOCATED("A");
String code; String code;
private Allocation(String code) { Allocation(String code) {
this.code = code; this.code = code;
} }
@ -1248,7 +1290,7 @@ public class UpdateMapperUnitTests {
} }
} }
static enum AllocationToStringConverter implements Converter<Allocation, String> { enum AllocationToStringConverter implements Converter<Allocation, String> {
INSTANCE; INSTANCE;
@ -1258,7 +1300,7 @@ public class UpdateMapperUnitTests {
} }
} }
static enum StringToAllocationConverter implements Converter<String, Allocation> { enum StringToAllocationConverter implements Converter<String, Allocation> {
INSTANCE; INSTANCE;

Loading…
Cancel
Save