From ec74185caa60f48cb563cb1db1f0270a9df7167f Mon Sep 17 00:00:00 2001 From: sohai Date: Wed, 4 Jul 2012 14:36:01 +0200 Subject: [PATCH 01/49] init version implementation --- .../data/mongodb/core/MongoOperations.java | 2 ++ .../data/mongodb/core/MongoTemplate.java | 19 +++++++++++ .../mapping/BasicMongoPersistentEntity.java | 32 ++++++++++++++++++- .../mapping/BasicMongoPersistentProperty.java | 8 +++++ .../core/mapping/MongoPersistentEntity.java | 4 +++ .../core/mapping/MongoPersistentProperty.java | 9 ++++++ .../mapping/SimpleMongoMappingContext.java | 21 +++++++++++- .../data/mongodb/core/mapping/Version.java | 18 +++++++++++ .../data/mongodb/core/query/Update.java | 14 ++++++++ .../query/MongoEntityInformation.java | 26 +++++++++++++++ .../MappingMongoEntityInformation.java | 31 ++++++++++++++++++ .../support/SimpleMongoRepository.java | 16 ++++++++++ .../data/mongodb/repository/Person.java | 12 ++++++- .../SimpleMongoRepositoryVersionTest.java | 11 +++++++ 14 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Version.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/SimpleMongoRepositoryVersionTest.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java index 0b2dea58e4..3cf7304ddb 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java @@ -657,6 +657,8 @@ T findAndModify(Query query, Update update, FindAndModifyOptions options, Cl * @return the WriteResult which lets you access the results of the previous write. */ WriteResult updateFirst(Query query, Update update, Class entityClass); + + WriteResult updateFirst(Query query, Object object, Class entityClass); /** * Updates the first object that is found in the specified collection that matches the query document criteria with diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index 7ff775bb44..625b8d21fb 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -809,6 +809,18 @@ public WriteResult updateFirst(Query query, Update update, Class entityClass) public WriteResult updateFirst(final Query query, final Update update, final String collectionName) { return doUpdate(collectionName, query, update, null, false, false); } + + public WriteResult updateFirst(final Query query, final Object object, + Class entityClass) { + + BasicDBObject dbObject = new BasicDBObject(); + this.mongoConverter.write(object, dbObject); + + return doUpdate(determineEntityCollectionName(entityClass), query, + Update.fromDBObject(dbObject, ID, + getPersistentEntity(entityClass).getVersionProperty() + .getName()), entityClass, false, false); + } public WriteResult updateMulti(Query query, Update update, Class entityClass) { return doUpdate(determineCollectionName(entityClass), query, update, entityClass, false, true); @@ -831,6 +843,10 @@ public WriteResult doInCollection(DBCollection collection) throws MongoException DBObject updateObj = update == null ? new BasicDBObject() : mapper.getMappedObject(update.getUpdateObject(), entity); + if(null != update && entity.hasVersion()) { + update.inc(entity.getVersionProperty().getName(), 1); + } + if (LOGGER.isDebugEnabled()) { LOGGER.debug("calling update using query: " + queryObj + " and update: " + updateObj + " in collection: " + collectionName); @@ -1485,6 +1501,9 @@ private MongoPersistentProperty getIdPropertyFor(Class type) { private String determineEntityCollectionName(T obj) { if (null != obj) { + if(obj instanceof Class) { + return determineEntityCollectionName((Class)obj); + } return determineCollectionName(obj.getClass()); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java index 443babed05..f2db622683 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java @@ -25,6 +25,7 @@ import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.model.BasicPersistentEntity; +import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mongodb.MongoCollectionUtils; import org.springframework.data.util.TypeInformation; import org.springframework.expression.Expression; @@ -46,6 +47,8 @@ public class BasicMongoPersistentEntity extends BasicPersistentEntity typeInformation) { this.collection = fallback; } } + + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.MutablePersistentEntity#addPersistentProperty(P) + */ + @Override + public void addPersistentProperty(MongoPersistentProperty property) { + if (property.isVersion()) { + if (this.versionProperty != null) { + throw new MappingException( + String.format( + "Attempt to add version property %s but already have property %s registered " + + "as version. Check your mapping configuration!", + property.getField(), versionProperty.getField())); + } + this.versionProperty = property; + } + super.addPersistentProperty(property); + } /* * (non-Javadoc) @@ -91,6 +113,14 @@ public String getCollection() { Expression expression = parser.parseExpression(collection, ParserContext.TEMPLATE_EXPRESSION); return expression.getValue(context, String.class); } + + public MongoPersistentProperty getVersionProperty() { + return versionProperty; + } + + public boolean hasVersion() { + return getVersionProperty() != null; + } /** * {@link Comparator} implementation inspecting the {@link MongoPersistentProperty}'s order. @@ -117,5 +147,5 @@ public int compare(MongoPersistentProperty o1, MongoPersistentProperty o2) { return o1.getFieldOrder() - o2.getFieldOrder(); } - } + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java index 5974dee0ce..a2264754aa 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java @@ -16,6 +16,7 @@ package org.springframework.data.mongodb.core.mapping; import java.beans.PropertyDescriptor; +import java.io.ObjectInputStream.GetField; import java.lang.reflect.Field; import java.math.BigInteger; import java.util.HashSet; @@ -142,4 +143,11 @@ public boolean isDbReference() { public DBRef getDBRef() { return getField().getAnnotation(DBRef.class); } + + /* (non-Javadoc) + * @see org.springframework.data.mongodb.core.core.mapping.MongoPersistentProperty#isVersion() + */ + public boolean isVersion() { + return getField().isAnnotationPresent(Version.class); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentEntity.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentEntity.java index 7965ea8520..5a7b16d1b4 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentEntity.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentEntity.java @@ -9,4 +9,8 @@ public interface MongoPersistentEntity extends PersistentEntity { String getCollection(); + + MongoPersistentProperty getVersionProperty(); + + boolean hasVersion(); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java index 0803bffe5d..965f34ae2f 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java @@ -54,6 +54,15 @@ public interface MongoPersistentProperty extends PersistentProperty extends BasicPersistentEntity implements MongoPersistentEntity { @@ -130,5 +138,16 @@ public SimpleMongoPersistentEntity(TypeInformation information) { public String getCollection() { return MongoCollectionUtils.getPreferredCollectionName(getType()); } + + /* (non-Javadoc) + * @see org.springframework.data.mongodb.core.core.mapping.MongoPersistentEntity#getVersionProperty() + */ + public MongoPersistentProperty getVersionProperty() { + return null; + } + + public boolean hasVersion() { + return false; + } } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Version.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Version.java new file mode 100644 index 0000000000..675f4fe7d1 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Version.java @@ -0,0 +1,18 @@ +package org.springframework.data.mongodb.core.mapping; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Specifies the version field that serves as its optimistic lock value. + * + */ +@Documented +@Target({ FIELD }) +@Retention(RUNTIME) +public @interface Version { + +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java index dd7c7fcc3d..c90c7bc664 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java @@ -15,8 +15,10 @@ */ package org.springframework.data.mongodb.core.query; +import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; @@ -39,6 +41,18 @@ public enum Position { public static Update update(String key, Object value) { return new Update().set(key, value); } + + public static Update fromDBObject(DBObject object, String... exclude) { + Update update = new Update(); + List excludeList = Arrays.asList(exclude); + for (String key : object.keySet()) { + if(excludeList.contains(key)) { + continue; + } + update.set(key, object.get(key)); + } + return update; + } /** * Update using the $set update modifier diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoEntityInformation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoEntityInformation.java index a68896c03d..3b214fbc3b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoEntityInformation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoEntityInformation.java @@ -39,4 +39,30 @@ public interface MongoEntityInformation extends Enti * @return */ String getIdAttribute(); + + + /** + * Returns the attribute that the version will be persisted to. + * + * @return + */ + String getVersionAttribute(); + + + /** + * Returns the entity version. + * + * @return + */ + Object getVersion(T entity); + + + + /** + * Returns whether entity has version. + * + * @param entity + * @return + */ + boolean hasVersion(T entity); } \ No newline at end of file diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MappingMongoEntityInformation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MappingMongoEntityInformation.java index 8795794641..38a1f08688 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MappingMongoEntityInformation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MappingMongoEntityInformation.java @@ -71,6 +71,30 @@ public ID getId(T entity) { throw new RuntimeException(e); } } + + /* (non-Javadoc) + * @see org.springframework.data.mongodb.repository.query.MongoEntityInformation#getVersion(T) + */ + public Object getVersion(T entity) { + MongoPersistentProperty versionProperty = entityMetadata.getVersionProperty(); + try { + return BeanWrapper.create(entity, null).getProperty(versionProperty); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /* (non-Javadoc) + * @see org.springframework.data.mongodb.repository.query.MongoEntityInformation#hasVersion(T) + */ + public boolean hasVersion(T entity) { + try { + getVersion(entity); + return true; + } catch (Exception e) { + return false; + } + } /* (non-Javadoc) * @see org.springframework.data.repository.support.EntityInformation#getIdType() @@ -93,4 +117,11 @@ public String getCollectionName() { public String getIdAttribute() { return entityMetadata.getIdProperty().getName(); } + + /* (non-Javadoc) + * @see org.springframework.data.mongodb.repository.MongoEntityInformation#getVersionAttribute() + */ + public String getVersionAttribute() { + return entityMetadata.getVersionProperty().getName(); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java index 757082bd1d..e1b81e13d3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java @@ -69,6 +69,13 @@ public S save(S entity) { Assert.notNull(entity, "Entity must not be null!"); + + if (entityInformation.isNew(entity) || !entityInformation.hasVersion(entity)) { + mongoOperations.save(entity, entityInformation.getCollectionName()); + } else { + mongoOperations.updateFirst( getUpdateQuery(entityInformation.getId(entity), + entityInformation.getVersion(entity)), entity, entity.getClass()); + } mongoOperations.save(entity, entityInformation.getCollectionName()); return entity; } @@ -107,6 +114,15 @@ private Query getIdQuery(Object id) { private Criteria getIdCriteria(Object id) { return where(entityInformation.getIdAttribute()).is(id); } + + private Query getUpdateQuery(Object id, Object version) { + return new Query(getIdCriteria(id).andOperator( + getVersionCriteria(version))); + } + + private Criteria getVersionCriteria(Object version) { + return where(entityInformation.getVersionAttribute()).is(version); + } /* * (non-Javadoc) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java index 34d6f2366f..ea3d0bb67b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java @@ -23,6 +23,7 @@ import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Version; /** * Sample domain class. @@ -54,8 +55,10 @@ public enum Sex { @DBRef User creator; + @Version + private Long version= 1L; + public Person() { - this(null, null); } @@ -190,6 +193,13 @@ public void setShippingAddresses(Set
addresses) { public String getName() { return String.format("%s %s", firstname, lastname); } + + /** + * @return the version + */ + public Long getVersion() { + return version; + } /* * (non-Javadoc) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/SimpleMongoRepositoryVersionTest.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/SimpleMongoRepositoryVersionTest.java new file mode 100644 index 0000000000..cd87d61bbe --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/SimpleMongoRepositoryVersionTest.java @@ -0,0 +1,11 @@ +package org.springframework.data.mongodb.repository; + +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class SimpleMongoRepositoryVersionTest { + +} From 116eda72f620401b891b613b0dcd7a41a5b327b7 Mon Sep 17 00:00:00 2001 From: Raman Gupta Date: Fri, 6 Jul 2012 11:34:06 -0400 Subject: [PATCH 02/49] DATAMONGO-477 - Change upper bound of Guava dependency to 14. --- spring-data-mongodb/template.mf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-data-mongodb/template.mf b/spring-data-mongodb/template.mf index a1e8257bd4..9d9222fa88 100644 --- a/spring-data-mongodb/template.mf +++ b/spring-data-mongodb/template.mf @@ -7,7 +7,7 @@ Import-Package: Export-Template: org.springframework.data.mongodb.*;version="${project.version}" Import-Template: - com.google.common.base.*;version="[11.0.0,12.0.0)";resolution:=optional, + com.google.common.base.*;version="[11.0.0,14.0.0)";resolution:=optional, com.mongodb.*;version="0", com.mysema.query.*;version="[2.1.1, 3.0.0)";resolution:=optional, javax.annotation.processing.*;version="0", From 69493b631fbc32d646d74f22c767206628b05545 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 16 Jul 2012 14:55:32 +0200 Subject: [PATCH 03/49] DATAMONGO-475 - Fixed debug output in map-reduce operations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using SerializationUtils.serializeToJsonSafely(…) instead of plain toString() as this might cause SerializationExceptions for complex objects. --- .../data/mongodb/core/MongoTemplate.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index 625b8d21fb..2302e7fec0 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -331,11 +331,12 @@ protected void executeQuery(Query query, String collectionName, DocumentCallback Assert.notNull(query); DBObject queryObject = query.getQueryObject(); + DBObject sortObject = query.getSortObject(); DBObject fieldsObject = query.getFieldsObject(); if (LOGGER.isDebugEnabled()) { - LOGGER.debug("find using query: " + queryObject + " fields: " + fieldsObject + " in collection: " - + collectionName); + LOGGER.debug(String.format("Executing query: %s sort: %s fields: %s in collection: $s", + SerializationUtils.serializeToJsonSafely(queryObject), sortObject, fieldsObject, collectionName)); } this.executeQueryInternal(new FindCallback(queryObject, fieldsObject), preparer, dch, collectionName); @@ -1025,8 +1026,10 @@ public MapReduceResults mapReduce(Query query, String inputCollectionName } if (LOGGER.isDebugEnabled()) { - LOGGER.debug("MapReduce command result = [" + commandResult + "]"); + LOGGER.debug(String.format("MapReduce command result = [%s]", + SerializationUtils.serializeToJsonSafely(commandObject))); } + MapReduceOutput mapReduceOutput = new MapReduceOutput(inputCollection, commandObject, commandResult); List mappedResults = new ArrayList(); DbObjectCallback callback = new ReadDbObjectCallback(mongoConverter, entityClass); @@ -1077,7 +1080,8 @@ public GroupByResults group(Criteria criteria, String inputCollectionName DBObject commandObject = new BasicDBObject("group", dbo); if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Executing Group with DBObject [" + commandObject.toString() + "]"); + LOGGER.debug(String.format("Executing Group with DBObject [%s]", + SerializationUtils.serializeToJsonSafely(commandObject))); } CommandResult commandResult = null; try { From 83d0396e165cdd016f74dd60aeb82f72de91be1b Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 16 Jul 2012 16:33:18 +0200 Subject: [PATCH 04/49] =?UTF-8?q?DATAMONGO-474=20-=20Fixed=20criteria=20ma?= =?UTF-8?q?pping=20for=20MongoTemplate.group(=E2=80=A6).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The criteria object handed to the group object needs to be mapped correctly to map complex values. Improved error handling on the way. --- .../data/mongodb/core/MongoTemplate.java | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index 2302e7fec0..d172fec261 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -1008,22 +1008,10 @@ public MapReduceResults mapReduce(Query query, String inputCollectionName LOGGER.debug("Executing MapReduce on collection [" + command.getInput() + "], mapFunction [" + mapFunc + "], reduceFunction [" + reduceFunc + "]"); } - CommandResult commandResult = null; - try { - if (command.getOutputType() == MapReduceCommand.OutputType.INLINE) { - commandResult = executeCommand(commandObject, getDb().getOptions()); - } else { - commandResult = executeCommand(commandObject); - } - commandResult.throwOnError(); - } catch (RuntimeException ex) { - this.potentiallyConvertRuntimeException(ex); - } - String error = commandResult.getErrorMessage(); - if (error != null) { - throw new InvalidDataAccessApiUsageException("Command execution failed: Error [" + error + "], Command = " - + commandObject); - } + + CommandResult commandResult = command.getOutputType() == MapReduceCommand.OutputType.INLINE ? executeCommand( + commandObject, getDb().getOptions()) : executeCommand(commandObject); + handleCommandError(commandResult, commandObject); if (LOGGER.isDebugEnabled()) { LOGGER.debug(String.format("MapReduce command result = [%s]", @@ -1054,7 +1042,7 @@ public GroupByResults group(Criteria criteria, String inputCollectionName if (criteria == null) { dbo.put("cond", null); } else { - dbo.put("cond", criteria.getCriteriaObject()); + dbo.put("cond", mapper.getMappedObject(criteria.getCriteriaObject(), null)); } // If initial document was a JavaScript string, potentially loaded by Spring's Resource abstraction, load it and // convert to DBObject @@ -1083,18 +1071,9 @@ public GroupByResults group(Criteria criteria, String inputCollectionName LOGGER.debug(String.format("Executing Group with DBObject [%s]", SerializationUtils.serializeToJsonSafely(commandObject))); } - CommandResult commandResult = null; - try { - commandResult = executeCommand(commandObject, getDb().getOptions()); - commandResult.throwOnError(); - } catch (RuntimeException ex) { - this.potentiallyConvertRuntimeException(ex); - } - String error = commandResult.getErrorMessage(); - if (error != null) { - throw new InvalidDataAccessApiUsageException("Command execution failed: Error [" + error + "], Command = " - + commandObject); - } + + CommandResult commandResult = executeCommand(commandObject, getDb().getOptions()); + handleCommandError(commandResult, commandObject); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Group command result = [" + commandResult + "]"); @@ -1569,6 +1548,27 @@ private RuntimeException potentiallyConvertRuntimeException(RuntimeException ex) return resolved == null ? ex : resolved; } + /** + * Inspects the given {@link CommandResult} for erros and potentially throws an + * {@link InvalidDataAccessApiUsageException} for that error. + * + * @param result must not be {@literal null}. + * @param source must not be {@literal null}. + */ + private void handleCommandError(CommandResult result, DBObject source) { + + try { + result.throwOnError(); + } catch (MongoException ex) { + + String error = result.getErrorMessage(); + error = error == null ? "NO MESSAGE" : error; + + throw new InvalidDataAccessApiUsageException("Command execution failed: Error [" + error + "], Command = " + + source, ex); + } + } + private static final MongoConverter getDefaultMongoConverter(MongoDbFactory factory) { MappingMongoConverter converter = new MappingMongoConverter(factory, new MongoMappingContext()); converter.afterPropertiesSet(); From 5e8140045f7d86f01eef824e997b7a593bafdd1f Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 16 Jul 2012 17:42:37 +0200 Subject: [PATCH 05/49] DATAMONGO-482 - Fixed typo in reference documentation. --- src/docbkx/reference/mongodb.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docbkx/reference/mongodb.xml b/src/docbkx/reference/mongodb.xml index e0285d037d..3228426c7e 100644 --- a/src/docbkx/reference/mongodb.xml +++ b/src/docbkx/reference/mongodb.xml @@ -2135,7 +2135,7 @@ MapReduceResults<ValueObject> results = mongoOperations.mapReduce(query, "
Group Operations - As an alternative to usiing Map-Reduce to perform data aggregation, + As an alternative to using Map-Reduce to perform data aggregation, you can use the group operation which feels similar to using SQL's group by query style, From 3a3fefb09c2f0652ebe66fd677de7231a3884eb6 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 16 Jul 2012 18:22:11 +0200 Subject: [PATCH 06/49] DATAMONGO-483 - Indexes now use the field name even if index name is defined. --- .../mongodb/core/index/CompoundIndex.java | 35 ++++++-- .../MongoPersistentEntityIndexCreator.java | 52 ++++++------ ...PersistentEntityIndexCreatorUnitTests.java | 82 +++++++++++++++++++ 3 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java index 19fdbd1716..b8acbf5c7d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java @@ -1,11 +1,11 @@ /* - * Copyright (c) 2011 by the original author(s). + * Copyright 2011-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mongodb.core.index; +import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -24,14 +24,29 @@ /** * Mark a class to use compound indexes. * - * @author Jon Brisbin + * @author Jon Brisbin + * @author Oliver Gierke */ @Target({ ElementType.TYPE }) +@Documented @Retention(RetentionPolicy.RUNTIME) public @interface CompoundIndex { + /** + * The actual index definition in JSON format. The keys of the JSON document are the fields to be indexed, the values + * define the index direction (1 for ascending, -1 for descending). + * + * @return + */ String def(); + /** + * It does not actually make sense to use that attribute as the direction has to be defined in the {@link #def()} + * attribute actually. + * + * @return + */ + @Deprecated IndexDirection direction() default IndexDirection.ASCENDING; boolean unique() default false; @@ -40,8 +55,18 @@ boolean dropDups() default false; + /** + * The name of the index to be created. + * + * @return + */ String name() default ""; + /** + * The collection the index will be created in. Will default to the collection the annotated domain class will be + * stored in. + * + * @return + */ String collection() default ""; - } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java index 547a74dde0..ed644a7feb 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java @@ -1,11 +1,11 @@ /* - * Copyright (c) 2011 by the original author(s). + * Copyright 2011-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mongodb.core.index; import java.lang.reflect.Field; @@ -27,7 +26,6 @@ import org.springframework.data.mapping.PropertyHandler; import org.springframework.data.mapping.event.MappingContextEvent; import org.springframework.data.mongodb.MongoDbFactory; -import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; @@ -39,10 +37,10 @@ import com.mongodb.util.JSON; /** - * Component that inspects {@link BasicMongoPersistentEntity} instances contained in the given - * {@link MongoMappingContext} for indexing metadata and ensures the indexes to be available. + * Component that inspects {@link MongoPersistentEntity} instances contained in the given {@link MongoMappingContext} + * for indexing metadata and ensures the indexes to be available. * - * @author Jon Brisbin + * @author Jon Brisbin * @author Oliver Gierke */ public class MongoPersistentEntityIndexCreator implements @@ -97,12 +95,12 @@ protected void checkForIndexes(final MongoPersistentEntity entity) { if (type.isAnnotationPresent(CompoundIndexes.class)) { CompoundIndexes indexes = type.getAnnotation(CompoundIndexes.class); for (CompoundIndex index : indexes.value()) { - String indexColl = index.collection(); - if ("".equals(indexColl)) { - indexColl = entity.getCollection(); - } - ensureIndex(indexColl, index.name(), index.def(), index.direction(), index.unique(), index.dropDups(), - index.sparse()); + + String indexColl = StringUtils.hasText(index.collection()) ? index.collection() : entity.getCollection(); + DBObject definition = (DBObject) JSON.parse(index.def()); + + ensureIndex(indexColl, index.name(), definition, index.unique(), index.dropDups(), index.sparse()); + if (log.isDebugEnabled()) { log.debug("Created compound index " + index); } @@ -111,10 +109,14 @@ protected void checkForIndexes(final MongoPersistentEntity entity) { entity.doWithProperties(new PropertyHandler() { public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) { + Field field = persistentProperty.getField(); + if (field.isAnnotationPresent(Indexed.class)) { + Indexed index = field.getAnnotation(Indexed.class); String name = index.name(); + if (!StringUtils.hasText(name)) { name = persistentProperty.getFieldName(); } else { @@ -126,11 +128,17 @@ public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) } } } + String collection = StringUtils.hasText(index.collection()) ? index.collection() : entity.getCollection(); - ensureIndex(collection, name, null, index.direction(), index.unique(), index.dropDups(), index.sparse()); + int direction = index.direction() == IndexDirection.ASCENDING ? 1 : -1; + DBObject definition = new BasicDBObject(persistentProperty.getFieldName(), direction); + + ensureIndex(collection, name, definition, index.unique(), index.dropDups(), index.sparse()); + if (log.isDebugEnabled()) { log.debug("Created property index " + index); } + } else if (field.isAnnotationPresent(GeoSpatialIndexed.class)) { GeoSpatialIndexed index = field.getAnnotation(GeoSpatialIndexed.class); @@ -155,21 +163,15 @@ public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) } } - protected void ensureIndex(String collection, final String name, final String def, final IndexDirection direction, - final boolean unique, final boolean dropDups, final boolean sparse) { - DBObject defObj; - if (null != def) { - defObj = (DBObject) JSON.parse(def); - } else { - defObj = new BasicDBObject(); - defObj.put(name, (direction == IndexDirection.ASCENDING ? 1 : -1)); - } + protected void ensureIndex(String collection, String name, DBObject indexDefinition, boolean unique, + boolean dropDups, boolean sparse) { + DBObject opts = new BasicDBObject(); opts.put("name", name); opts.put("dropDups", dropDups); opts.put("sparse", sparse); opts.put("unique", unique); - mongoDbFactory.getDb().getCollection(collection).ensureIndex(defObj, opts); - } + mongoDbFactory.getDb().getCollection(collection).ensureIndex(indexDefinition, opts); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java new file mode 100644 index 0000000000..f99469b7cf --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.core.index; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import java.util.Collections; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.mapping.Field; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; + +import com.mongodb.DBObject; + +/** + * Unit tests for {@link MongoPersistentEntityIndexCreator}. + * + * @author Oliver Gierke + */ +@RunWith(MockitoJUnitRunner.class) +public class MongoPersistentEntityIndexCreatorUnitTests { + + @Mock + MongoDbFactory factory; + + @Test + public void buildsIndexDefinitionUsingFieldName() { + + MongoMappingContext mappingContext = new MongoMappingContext(); + mappingContext.setInitialEntitySet(Collections.singleton(Person.class)); + mappingContext.initialize(); + + DummyMongoPersistentEntityIndexCreator creator = new DummyMongoPersistentEntityIndexCreator(mappingContext, factory); + + assertThat(creator.indexDefinition, is(notNullValue())); + assertThat(creator.indexDefinition.keySet(), hasItem("fieldname")); + assertThat(creator.name, is("indexName")); + } + + static class Person { + + @Indexed(name = "indexName") + @Field("fieldname") + String field; + } + + static class DummyMongoPersistentEntityIndexCreator extends MongoPersistentEntityIndexCreator { + + DBObject indexDefinition; + String name; + + public DummyMongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, MongoDbFactory mongoDbFactory) { + super(mappingContext, mongoDbFactory); + } + + @Override + protected void ensureIndex(String collection, String name, DBObject indexDefinition, boolean unique, + boolean dropDups, boolean sparse) { + + this.name = name; + this.indexDefinition = indexDefinition; + } + } +} From 0dcec2dda7c82c68c14e9a1c8e90a88ad9e7c27c Mon Sep 17 00:00:00 2001 From: Amol Nayak Date: Wed, 11 Jul 2012 00:18:12 +0530 Subject: [PATCH 07/49] =?UTF-8?q?DATAMONGO-480=20-=20Consider=20WriteResul?= =?UTF-8?q?t=20for=20insert(=E2=80=A6)=20and=20save(=E2=80=A6)=20methods.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/mongodb/core/MongoTemplate.java | 48 ++++--- .../data/mongodb/core/MongoTemplateTests.java | 117 +++++++++++++++++- 2 files changed, 143 insertions(+), 22 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index d172fec261..ed7e95aa75 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -106,6 +106,7 @@ * @author Graeme Rocher * @author Mark Pollack * @author Oliver Gierke + * @author Amol Nayak */ public class MongoTemplate implements MongoOperations, ApplicationContextAware { @@ -731,11 +732,13 @@ public Object doInCollection(DBCollection collection) throws MongoException, Dat MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT, collectionName, entityClass, dbDoc, null); WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction); + WriteResult wr; if (writeConcernToUse == null) { - collection.insert(dbDoc); + wr = collection.insert(dbDoc); } else { - collection.insert(dbDoc, writeConcernToUse); + wr = collection.insert(dbDoc, writeConcernToUse); } + handleAnyWriteResultErrors(wr, dbDoc, "insert"); return dbDoc.get(ID); } }); @@ -754,11 +757,13 @@ public Void doInCollection(DBCollection collection) throws MongoException, DataA MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT_LIST, collectionName, null, null, null); WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction); + WriteResult wr; if (writeConcernToUse == null) { - collection.insert(dbDocList); + wr = collection.insert(dbDocList); } else { - collection.insert(dbDocList.toArray((DBObject[]) new BasicDBObject[dbDocList.size()]), writeConcernToUse); + wr = collection.insert(dbDocList.toArray((DBObject[]) new BasicDBObject[dbDocList.size()]), writeConcernToUse); } + handleAnyWriteResultErrors(wr, null, "insert_list"); return null; } }); @@ -785,11 +790,13 @@ public Object doInCollection(DBCollection collection) throws MongoException, Dat MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.SAVE, collectionName, entityClass, dbDoc, null); WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction); + WriteResult wr; if (writeConcernToUse == null) { - collection.save(dbDoc); + wr = collection.save(dbDoc); } else { - collection.save(dbDoc, writeConcernToUse); + wr = collection.save(dbDoc, writeConcernToUse); } + handleAnyWriteResultErrors(wr, dbDoc, "save"); return dbDoc.get(ID); } }); @@ -890,7 +897,7 @@ public void remove(Object object, String collection) { /** * Returns a {@link Query} for the given entity by its id. - * + * * @param object must not be {@literal null}. * @return */ @@ -1181,7 +1188,7 @@ protected void maybeEmitEvent(MongoMappingEvent event) { /** * Create the specified collection using the provided options - * + * * @param collectionName * @param collectionOptions * @return the collection that was created @@ -1203,7 +1210,7 @@ public DBCollection doInDB(DB db) throws MongoException, DataAccessException { * 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 DBObject and so is the fields specification. - * + * * @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 fields the document that specifies the fields to be returned @@ -1228,7 +1235,7 @@ protected T doFindOne(String collectionName, DBObject query, DBObject fields * The query document is specified as a standard DBObject and so is the fields specification. *

* Can be overridden by subclasses. - * + * * @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 fields the document that specifies the fields to be returned @@ -1258,7 +1265,7 @@ protected List doFind(String collectionName, DBObject query, DBObject * 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 DBObject and so is the fields specification. - * + * * @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 fields the document that specifies the fields to be returned @@ -1297,7 +1304,7 @@ protected DBObject convertToDbObject(CollectionOptions collectionOptions) { * The first document that matches the query is returned and also removed from the collection in the database. *

* The query document is specified as a standard DBObject and so is the fields specification. - * + * * @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 entityClass the parameterized type of the returned list. @@ -1344,7 +1351,7 @@ protected T doFindAndModify(String collectionName, DBObject query, DBObject /** * Populates the id property of the saved object, if it's not set already. - * + * * @param savedObject * @param id */ @@ -1397,7 +1404,7 @@ private DBCollection getAndPrepareCollection(DB db, String collectionName) { *

  • Execute the given {@link ConnectionCallback} for a {@link DBObject}.
  • *
  • Apply the given {@link DbObjectCallback} to each of the {@link DBObject}s to obtain the result.
  • *
      - * + * * @param * @param collectionCallback the callback to retrieve the {@link DBObject} with * @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type @@ -1523,9 +1530,16 @@ protected void handleAnyWriteResultErrors(WriteResult wr, DBObject query, String String error = wr.getError(); if (error != null) { - - String message = String.format("Execution of %s%s failed: %s", operation, query == null ? "" : "' using '" - + query.toString() + "' query", error); + String message; + if (operation.equals("insert") || operation.equals("save")) { + // assuming the insert operations will begin with insert string + message = String.format("Insert/Save for %s failed: %s", query, error); + } else if (operation.equals("insert_list")) { + message = String.format("Insert list failed: %s", error); + } else { + message = String.format("Execution of %s%s failed: %s", operation, + query == null ? "" : "' using '" + query.toString() + "' query", error); + } if (WriteResultChecking.EXCEPTION == this.writeResultChecking) { throw new DataIntegrityViolationException(message); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java index 92fd4847a8..eeaaa3460e 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 the original author or authors. + * Copyright 2011-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,9 +37,9 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.mongodb.InvalidMongoDbApiUsageException; @@ -73,6 +73,7 @@ * * @author Oliver Gierke * @author Thomas Risberg + * @author Amol Nayak */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:infrastructure.xml") @@ -163,6 +164,112 @@ public void bogusUpdateDoesNotTriggerException() throws Exception { mongoTemplate.updateFirst(q, u, Person.class); } + /** + * @see DATAMONGO-480 + */ + @Test + public void throwsExceptionForDuplicateIds() { + + MongoTemplate template = new MongoTemplate(factory); + template.setWriteResultChecking(WriteResultChecking.EXCEPTION); + + Person person = new Person(new ObjectId(), "Amol"); + person.setAge(28); + + template.insert(person); + + try { + template.insert(person); + fail("Expected DataIntegrityViolationException!"); + } catch (DataIntegrityViolationException e) { + assertThat(e.getMessage(), containsString("E11000 duplicate key error index: database.person.$_id_ dup key:")); + } + } + + /** + * @see DATAMONGO-480 + */ + @Test + public void throwsExceptionForUpdateWithInvalidPushOperator() { + + MongoTemplate template = new MongoTemplate(factory); + template.setWriteResultChecking(WriteResultChecking.EXCEPTION); + + ObjectId id = new ObjectId(); + Person person = new Person(id, "Amol"); + person.setAge(28); + + template.insert(person); + + try { + + Query query = new Query(Criteria.where("firstName").is("Amol")); + Update upd = new Update().push("age", 29); + template.updateFirst(query, upd, Person.class); + fail("Expected DataIntegrityViolationException!"); + + } catch (DataIntegrityViolationException e) { + + assertThat(e.getMessage(), + is("Execution of update with '{ \"$push\" : { \"age\" : 29}}'' using '{ \"firstName\" : \"Amol\"}' " + + "query failed: Cannot apply $push/$pushAll modifier to non-array")); + } + } + + /** + * @see DATAMONGO-480 + */ + @Test + public void throwsExceptionForIndexViolationIfConfigured() { + + MongoTemplate template = new MongoTemplate(factory); + template.setWriteResultChecking(WriteResultChecking.EXCEPTION); + template.indexOps(Person.class).ensureIndex(new Index().on("firstName", Order.DESCENDING).unique()); + + Person person = new Person(new ObjectId(), "Amol"); + person.setAge(28); + + template.save(person); + + person = new Person(new ObjectId(), "Amol"); + person.setAge(28); + + try { + template.save(person); + fail("Expected DataIntegrityViolationException!"); + } catch (DataIntegrityViolationException e) { + assertThat(e.getMessage(), + containsString("E11000 duplicate key error index: database.person.$firstName_-1 dup key:")); + } + } + + /** + * @see DATAMONGO-480 + */ + @Test + public void rejectsDuplicateIdInInsertAll() { + + MongoTemplate template = new MongoTemplate(factory); + template.setWriteResultChecking(WriteResultChecking.EXCEPTION); + + ObjectId id = new ObjectId(); + Person person = new Person(id, "Amol"); + person.setAge(28); + + List records = new ArrayList(); + records.add(person); + records.add(person); + + try { + template.insertAll(records); + fail("Expected DataIntegrityViolationException!"); + } catch (DataIntegrityViolationException e) { + assertThat( + e.getMessage(), + startsWith("Insert list failed: E11000 duplicate key error index: database.person.$_id_ dup key: { : ObjectId")); + } + } + @Test public void testEnsureIndex() throws Exception { @@ -193,7 +300,7 @@ public void testEnsureIndex() throws Exception { assertThat(dropDupes, is(true)); List indexInfoList = template.indexOps(Person.class).getIndexInfo(); - System.out.println(indexInfoList); + assertThat(indexInfoList.size(), is(2)); IndexInfo ii = indexInfoList.get(1); assertThat(ii.isUnique(), is(true)); @@ -939,7 +1046,7 @@ public void updatesDBRefsCorrectly() { DBRef first = new DBRef(factory.getDb(), "foo", new ObjectId()); DBRef second = new DBRef(factory.getDb(), "bar", new ObjectId()); - template.updateFirst(null, Update.update("dbRefs", Arrays.asList(first, second)), ClassWithDBRefs.class); + template.updateFirst(null, update("dbRefs", Arrays.asList(first, second)), ClassWithDBRefs.class); } class ClassWithDBRefs { @@ -1102,7 +1209,7 @@ public void executesQueryWithNegatedRegexCorrectly() { template.save(second); Query query = query(where("field").not().regex("Matthews")); - System.out.println(query.getQueryObject()); + List result = template.find(query, Sample.class); assertThat(result.size(), is(1)); assertThat(result.get(0).field, is("Beauford")); From fa7c1eaefe8977fe29c2f89d92b54422a368b92f Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 6 Jul 2012 15:44:16 +0200 Subject: [PATCH 08/49] DATAMONGO-476 - JavaConfig support for repositories. --- spring-data-mongodb-parent/pom.xml | 2 +- .../mongodb/config/MongoNamespaceHandler.java | 9 +- .../config/EnableMongoRepositories.java | 120 +++++++++++ .../config/MongoRepositoriesRegistrar.java | 48 +++++ .../config/MongoRepositoryConfigParser.java | 54 ----- ...MongoRepositoryConfigurationExtension.java | 82 ++++++++ .../SimpleMongoRepositoryConfiguration.java | 196 ------------------ .../data/mongodb/config/spring-mongo-1.1.xsd | 12 -- .../cdi/CdiExtensionIntegrationTests.java | 8 +- ...pository.java => CdiPersonRepository.java} | 2 +- .../repository/cdi/RepositoryClient.java | 5 +- ...RepositoriesRegistrarIntegrationTests.java | 58 ++++++ .../src/test/resources/geospatial.xml | 2 +- .../src/test/resources/mapping.xml | 2 +- .../db-factory-bean-custom-write-concern.xml | 2 +- .../resources/namespace/db-factory-bean.xml | 2 +- .../MongoNamespaceReplicaSetTests-context.xml | 2 +- .../config/MongoNamespaceTests-context.xml | 2 +- ...rsonRepositoryIntegrationTests-context.xml | 6 +- ...yIndexCreationIntegrationTests-context.xml | 9 +- ...MongoNamespaceIntegrationTests-context.xml | 2 +- .../src/test/resources/server-jmx.xml | 2 +- .../src/test/resources/template-mapping.xml | 4 +- src/docbkx/reference/mongo-repositories.xml | 44 +++- 24 files changed, 380 insertions(+), 295 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/EnableMongoRepositories.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoriesRegistrar.java delete mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigParser.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java delete mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/SimpleMongoRepositoryConfiguration.java rename spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/{PersonRepository.java => CdiPersonRepository.java} (92%) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/config/MongoRepositoriesRegistrarIntegrationTests.java diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index 2386a000fb..7d08da5ee3 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -18,7 +18,7 @@ 3.0.7.RELEASE 4.0.0.RELEASE [${org.springframework.version.30}, ${org.springframework.version.40}) - 1.3.2.BUILD-SNAPSHOT + 1.4.0.BUILD-SNAPSHOT 1.6.11.RELEASE true diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java index 4eb27dee57..a01de78780 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java @@ -16,7 +16,9 @@ package org.springframework.data.mongodb.config; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -import org.springframework.data.mongodb.repository.config.MongoRepositoryConfigParser; +import org.springframework.data.mongodb.repository.config.MongoRepositoryConfigurationExtension; +import org.springframework.data.repository.config.RepositoryBeanDefinitionParser; +import org.springframework.data.repository.config.RepositoryConfigurationExtension; /** * {@link org.springframework.beans.factory.xml.NamespaceHandler} for Mongo DB based repositories. @@ -32,7 +34,10 @@ public class MongoNamespaceHandler extends NamespaceHandlerSupport { */ public void init() { - registerBeanDefinitionParser("repositories", new MongoRepositoryConfigParser()); + RepositoryConfigurationExtension extension = new MongoRepositoryConfigurationExtension(); + RepositoryBeanDefinitionParser repositoryBeanDefinitionParser = new RepositoryBeanDefinitionParser(extension); + + registerBeanDefinitionParser("repositories", repositoryBeanDefinitionParser); registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser()); registerBeanDefinitionParser("mongo", new MongoParser()); registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser()); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/EnableMongoRepositories.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/EnableMongoRepositories.java new file mode 100644 index 0000000000..b2ba8f6486 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/EnableMongoRepositories.java @@ -0,0 +1,120 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository.config; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Import; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean; +import org.springframework.data.repository.query.QueryLookupStrategy; +import org.springframework.data.repository.query.QueryLookupStrategy.Key; + +/** + * Annotation to activate MongoDB repositories. If no base package is configured through either {@link #value()}, + * {@link #basePackages()} or {@link #basePackageClasses()} it will trigger scanning of the package of annotated class. + * + * @author Oliver Gierke + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Import(MongoRepositoriesRegistrar.class) +public @interface EnableMongoRepositories { + + /** + * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.: + * {@code @EnableJpaRepositories("org.my.pkg")} instead of {@code @EnableJpaRepositories(basePackages="org.my.pkg")}. + */ + String[] value() default {}; + + /** + * Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this + * attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names. + */ + String[] basePackages() default {}; + + /** + * Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The + * package of each class specified will be scanned. Consider creating a special no-op marker class or interface in + * each package that serves no purpose other than being referenced by this attribute. + */ + Class[] basePackageClasses() default {}; + + /** + * Specifies which types are eligible for component scanning. Further narrows the set of candidate components from + * everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters. + */ + Filter[] includeFilters() default {}; + + /** + * Specifies which types are not eligible for component scanning. + */ + Filter[] excludeFilters() default {}; + + /** + * Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So + * for a repository named {@code PersonRepository} the corresponding implementation class will be looked up scanning + * for {@code PersonRepositoryImpl}. + * + * @return + */ + String repositoryImplementationPostfix() default ""; + + /** + * Configures the location of where to find the Spring Data named queries properties file. Will default to + * {@code META-INFO/mongo-named-queries.properties}. + * + * @return + */ + String namedQueriesLocation() default ""; + + /** + * Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to + * {@link Key#CREATE_IF_NOT_FOUND}. + * + * @return + */ + Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND; + + /** + * Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to + * {@link MongoRepositoryFactoryBean}. + * + * @return + */ + Class repositoryFactoryBeanClass() default MongoRepositoryFactoryBean.class; + + /** + * Configures the name of the {@link MongoTemplate} bean to be used with the repositories detected. + * + * @return + */ + String mongoTemplateRef() default "mongoTemplate"; + + /** + * Whether to automatically create indexes for query methods defined in the repository interface. + * + * @return + */ + boolean createIndexesForQueryMethods() default false; +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoriesRegistrar.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoriesRegistrar.java new file mode 100644 index 0000000000..96b8c317ab --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoriesRegistrar.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository.config; + +import java.lang.annotation.Annotation; + +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport; +import org.springframework.data.repository.config.RepositoryConfigurationExtension; + +/** + * Mongo-specific {@link ImportBeanDefinitionRegistrar}. + * + * @author Oliver Gierke + */ +class MongoRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport { + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getAnnotation() + */ + @Override + protected Class getAnnotation() { + return EnableMongoRepositories.class; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getExtension() + */ + @Override + protected RepositoryConfigurationExtension getExtension() { + return new MongoRepositoryConfigurationExtension(); + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigParser.java deleted file mode 100644 index 5c4841f03a..0000000000 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigParser.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.mongodb.repository.config; - -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.data.mongodb.repository.config.SimpleMongoRepositoryConfiguration.MongoRepositoryConfiguration; -import org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser; -import org.w3c.dom.Element; - -/** - * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} to create Mongo DB repositories from classpath - * scanning or manual definition. - * - * @author Oliver Gierke - */ -public class MongoRepositoryConfigParser extends - AbstractRepositoryConfigDefinitionParser { - - /* - * (non-Javadoc) - * @see org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser#getGlobalRepositoryConfigInformation(org.w3c.dom.Element) - */ - @Override - protected SimpleMongoRepositoryConfiguration getGlobalRepositoryConfigInformation(Element element) { - - return new SimpleMongoRepositoryConfiguration(element); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser#postProcessBeanDefinition(org.springframework.data.repository.config.SingleRepositoryConfigInformation, org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) - */ - @Override - protected void postProcessBeanDefinition(MongoRepositoryConfiguration context, BeanDefinitionBuilder builder, - BeanDefinitionRegistry registry, Object beanSource) { - - builder.addPropertyReference("mongoOperations", context.getMongoTemplateRef()); - builder.addPropertyValue("createIndexesForQueryMethods", context.getCreateQueryIndexes()); - } -} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java new file mode 100644 index 0000000000..27395d8cb8 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository.config; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean; +import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource; +import org.springframework.data.repository.config.RepositoryConfigurationExtension; +import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport; +import org.springframework.data.repository.config.XmlRepositoryConfigurationSource; +import org.w3c.dom.Element; + +/** + * {@link RepositoryConfigurationExtension} for MongoDB. + * + * @author Oliver Gierke + */ +public class MongoRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport { + + private static final String MONGO_TEMPLATE_REF = "mongo-template-ref"; + private static final String CREATE_QUERY_INDEXES = "create-query-indexes"; + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getModulePrefix() + */ + @Override + protected String getModulePrefix() { + return "mongo"; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.config.RepositoryConfigurationExtension#getRepositoryFactoryClassName() + */ + public String getRepositoryFactoryClassName() { + return MongoRepositoryFactoryBean.class.getName(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.XmlRepositoryConfigurationSource) + */ + @Override + public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfigurationSource config) { + + Element element = config.getElement(); + + String attribute = element.getAttribute(MONGO_TEMPLATE_REF); + builder.addPropertyReference("mongoOperations", attribute); + + attribute = element.getAttribute(CREATE_QUERY_INDEXES); + builder.addPropertyValue("createIndexesForQueryMethods", attribute); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource) + */ + @Override + public void postProcess(BeanDefinitionBuilder builder, AnnotationRepositoryConfigurationSource config) { + + AnnotationAttributes attributes = config.getAttributes(); + + builder.addPropertyReference("mongoOperations", attributes.getString("mongoTemplateRef")); + builder.addPropertyValue("createIndexesForQueryMethods", attributes.getBoolean("createIndexesForQueryMethods")); + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/SimpleMongoRepositoryConfiguration.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/SimpleMongoRepositoryConfiguration.java deleted file mode 100644 index 7fe5af2cea..0000000000 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/SimpleMongoRepositoryConfiguration.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.mongodb.repository.config; - -import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean; -import org.springframework.data.repository.config.AutomaticRepositoryConfigInformation; -import org.springframework.data.repository.config.ManualRepositoryConfigInformation; -import org.springframework.data.repository.config.RepositoryConfig; -import org.springframework.data.repository.config.SingleRepositoryConfigInformation; -import org.springframework.util.StringUtils; -import org.w3c.dom.Element; - -/** - * {@link RepositoryConfig} implementation to create {@link MongoRepositoryConfiguration} instances for both automatic - * and manual configuration. - * - * @author Oliver Gierke - */ -public class SimpleMongoRepositoryConfiguration - extends - RepositoryConfig { - - private static final String MONGO_TEMPLATE_REF = "mongo-template-ref"; - private static final String CREATE_QUERY_INDEXES = "create-query-indexes"; - private static final String DEFAULT_MONGO_TEMPLATE_REF = "mongoTemplate"; - - /** - * Creates a new {@link SimpleMongoRepositoryConfiguration} for the given {@link Element}. - * - * @param repositoriesElement - */ - protected SimpleMongoRepositoryConfiguration(Element repositoriesElement) { - - super(repositoriesElement, MongoRepositoryFactoryBean.class.getName()); - } - - /** - * Returns the bean name of the {@link org.springframework.data.mongodb.core.core.MongoTemplate} to be referenced. - * - * @return - */ - public String getMongoTemplateRef() { - - String templateRef = getSource().getAttribute(MONGO_TEMPLATE_REF); - return StringUtils.hasText(templateRef) ? templateRef : DEFAULT_MONGO_TEMPLATE_REF; - } - - /** - * Returns whether to create indexes for query methods. - * - * @return - */ - public boolean getCreateQueryIndexes() { - - String createQueryIndexes = getSource().getAttribute(CREATE_QUERY_INDEXES); - return StringUtils.hasText(createQueryIndexes) ? Boolean.parseBoolean(createQueryIndexes) : false; - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.data.repository.config.GlobalRepositoryConfigInformation - * #getAutoconfigRepositoryInformation(java.lang.String) - */ - public MongoRepositoryConfiguration getAutoconfigRepositoryInformation(String interfaceName) { - - return new AutomaticMongoRepositoryConfiguration(interfaceName, this); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.repository.config.RepositoryConfig#getNamedQueriesLocation() - */ - public String getNamedQueriesLocation() { - return "classpath*:META-INF/mongo-named-queries.properties"; - } - - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.config.RepositoryConfig# - * createSingleRepositoryConfigInformationFor(org.w3c.dom.Element) - */ - @Override - protected MongoRepositoryConfiguration createSingleRepositoryConfigInformationFor(Element element) { - - return new ManualMongoRepositoryConfiguration(element, this); - } - - /** - * Simple interface for configuration values specific to Mongo repositories. - * - * @author Oliver Gierke - */ - public interface MongoRepositoryConfiguration extends - SingleRepositoryConfigInformation { - - String getMongoTemplateRef(); - - boolean getCreateQueryIndexes(); - } - - /** - * Implements manual lookup of the additional attributes. - * - * @author Oliver Gierke - */ - private static class ManualMongoRepositoryConfiguration extends - ManualRepositoryConfigInformation implements MongoRepositoryConfiguration { - - /** - * Creates a new {@link ManualMongoRepositoryConfiguration} for the given {@link Element} and parent. - * - * @param element - * @param parent - */ - public ManualMongoRepositoryConfiguration(Element element, SimpleMongoRepositoryConfiguration parent) { - - super(element, parent); - } - - /* - * (non-Javadoc) - * - * @see org.springframework.data.mongodb.repository.config. - * SimpleMongoRepositoryConfiguration - * .MongoRepositoryConfiguration#getMongoTemplateRef() - */ - public String getMongoTemplateRef() { - - return getAttribute(MONGO_TEMPLATE_REF); - } - - /* (non-Javadoc) - * @see org.springframework.data.mongodb.config.SimpleMongoRepositoryConfiguration.MongoRepositoryConfiguration#getCreateQueryIndexes() - */ - public boolean getCreateQueryIndexes() { - - String attribute = getAttribute(CREATE_QUERY_INDEXES); - return attribute == null ? false : Boolean.parseBoolean(attribute); - } - } - - /** - * Implements the lookup of the additional attributes during automatic configuration. - * - * @author Oliver Gierke - */ - private static class AutomaticMongoRepositoryConfiguration extends - AutomaticRepositoryConfigInformation implements MongoRepositoryConfiguration { - - /** - * Creates a new {@link AutomaticMongoRepositoryConfiguration} for the given interface and parent. - * - * @param interfaceName - * @param parent - */ - public AutomaticMongoRepositoryConfiguration(String interfaceName, SimpleMongoRepositoryConfiguration parent) { - - super(interfaceName, parent); - } - - /* - * (non-Javadoc) - * - * @see org.springframework.data.mongodb.repository.config. - * SimpleMongoRepositoryConfiguration - * .MongoRepositoryConfiguration#getMongoTemplateRef() - */ - public String getMongoTemplateRef() { - - return getParent().getMongoTemplateRef(); - } - - /* (non-Javadoc) - * @see org.springframework.data.mongodb.config.SimpleMongoRepositoryConfiguration.MongoRepositoryConfiguration#getCreateQueryIndexes() - */ - public boolean getCreateQueryIndexes() { - return getParent().getCreateQueryIndexes(); - } - } -} diff --git a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.1.xsd b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.1.xsd index feae5468bc..9bfbb8799f 100644 --- a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.1.xsd +++ b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.1.xsd @@ -103,15 +103,6 @@ The Mongo URI string.]]> - - - - - - - - - @@ -134,9 +125,6 @@ The Mongo URI string.]]> - - - diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/CdiExtensionIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/CdiExtensionIntegrationTests.java index fd72704646..5f05ccac60 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/CdiExtensionIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/CdiExtensionIntegrationTests.java @@ -20,6 +20,7 @@ import org.apache.webbeans.cditest.CdiTestContainer; import org.apache.webbeans.cditest.CdiTestContainerLoader; +import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.data.mongodb.repository.Person; @@ -39,11 +40,16 @@ public static void setUp() throws Exception { container.bootContainer(); } + @AfterClass + public static void tearDown() throws Exception { + container.shutdownContainer(); + } + @Test public void bootstrapsRepositoryCorrectly() { RepositoryClient client = container.getInstance(RepositoryClient.class); - PersonRepository repository = client.getRepository(); + CdiPersonRepository repository = client.getRepository(); assertThat(repository, is(notNullValue())); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/PersonRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/CdiPersonRepository.java similarity index 92% rename from spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/PersonRepository.java rename to spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/CdiPersonRepository.java index f86c063975..48b1cebb11 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/PersonRepository.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/CdiPersonRepository.java @@ -18,7 +18,7 @@ import org.springframework.data.mongodb.repository.Person; import org.springframework.data.repository.Repository; -public interface PersonRepository extends Repository { +public interface CdiPersonRepository extends Repository { void deleteAll(); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/RepositoryClient.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/RepositoryClient.java index 34d681bcbd..f8fd1755c9 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/RepositoryClient.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/RepositoryClient.java @@ -18,18 +18,17 @@ import javax.inject.Inject; /** - * * @author Oliver Gierke */ class RepositoryClient { @Inject - PersonRepository repository; + CdiPersonRepository repository; /** * @return the repository */ - public PersonRepository getRepository() { + public CdiPersonRepository getRepository() { return repository; } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/config/MongoRepositoriesRegistrarIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/config/MongoRepositoriesRegistrarIntegrationTests.java new file mode 100644 index 0000000000..26989e144d --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/config/MongoRepositoriesRegistrarIntegrationTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository.config; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.SimpleMongoDbFactory; +import org.springframework.data.mongodb.repository.PersonRepository; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.mongodb.Mongo; + +/** + * Integration tests for {@link MongoRepositoriesRegistrar}. + * + * @author Oliver Gierke + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class MongoRepositoriesRegistrarIntegrationTests { + + @Configuration + @EnableMongoRepositories(basePackages = "org.springframework.data.mongodb.repository") + static class Config { + + @Bean + public MongoOperations mongoTemplate() throws Exception { + return new MongoTemplate(new SimpleMongoDbFactory(new Mongo(), "database")); + } + } + + @Autowired + PersonRepository personRepository; + + @Test + public void testConfiguration() { + + } +} diff --git a/spring-data-mongodb/src/test/resources/geospatial.xml b/spring-data-mongodb/src/test/resources/geospatial.xml index dcb331dc9f..13a01ac350 100644 --- a/spring-data-mongodb/src/test/resources/geospatial.xml +++ b/spring-data-mongodb/src/test/resources/geospatial.xml @@ -3,7 +3,7 @@ xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd - http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd"> + http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd"> diff --git a/spring-data-mongodb/src/test/resources/mapping.xml b/spring-data-mongodb/src/test/resources/mapping.xml index 6b45093c28..42c4c6799f 100644 --- a/spring-data-mongodb/src/test/resources/mapping.xml +++ b/spring-data-mongodb/src/test/resources/mapping.xml @@ -3,7 +3,7 @@ xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd - http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd"> + http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd"> diff --git a/spring-data-mongodb/src/test/resources/namespace/db-factory-bean-custom-write-concern.xml b/spring-data-mongodb/src/test/resources/namespace/db-factory-bean-custom-write-concern.xml index c42ab81a09..ef7b48fbea 100644 --- a/spring-data-mongodb/src/test/resources/namespace/db-factory-bean-custom-write-concern.xml +++ b/spring-data-mongodb/src/test/resources/namespace/db-factory-bean-custom-write-concern.xml @@ -2,7 +2,7 @@ diff --git a/spring-data-mongodb/src/test/resources/namespace/db-factory-bean.xml b/spring-data-mongodb/src/test/resources/namespace/db-factory-bean.xml index ea91e67f7a..bce7b0aaff 100644 --- a/spring-data-mongodb/src/test/resources/namespace/db-factory-bean.xml +++ b/spring-data-mongodb/src/test/resources/namespace/db-factory-bean.xml @@ -2,7 +2,7 @@ diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests-context.xml index dd1890419e..28003d77bd 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests-context.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:context="http://www.springframework.org/schema/context" - xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd + xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceTests-context.xml index 339d06f504..7a855c5956 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceTests-context.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:context="http://www.springframework.org/schema/context" - xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd + xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests-context.xml index a1bffb752c..06032c18d1 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests-context.xml @@ -3,9 +3,9 @@ xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" - xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd - http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd - http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> + xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests-context.xml index be635304fe..d994229bac 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests-context.xml @@ -3,9 +3,9 @@ xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" - xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd - http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd - http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> + xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> @@ -15,7 +15,6 @@ - + diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml index 2496a94302..b80e84c56e 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml @@ -4,7 +4,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:repository="http://www.springframework.org/schema/data/repository" xmlns:util="http://www.springframework.org/schema/util" - xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd + xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository-1.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> diff --git a/spring-data-mongodb/src/test/resources/server-jmx.xml b/spring-data-mongodb/src/test/resources/server-jmx.xml index 2456cf7e39..7b24ed7aba 100644 --- a/spring-data-mongodb/src/test/resources/server-jmx.xml +++ b/spring-data-mongodb/src/test/resources/server-jmx.xml @@ -4,7 +4,7 @@ xmlns:p="http://www.springframework.org/schema/p" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:context="http://www.springframework.org/schema/context" - xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd + xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> diff --git a/spring-data-mongodb/src/test/resources/template-mapping.xml b/spring-data-mongodb/src/test/resources/template-mapping.xml index 61a20872d3..001d3f4fa5 100644 --- a/spring-data-mongodb/src/test/resources/template-mapping.xml +++ b/spring-data-mongodb/src/test/resources/template-mapping.xml @@ -2,8 +2,8 @@ + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd"> diff --git a/src/docbkx/reference/mongo-repositories.xml b/src/docbkx/reference/mongo-repositories.xml index 9289838d6b..58d2b72311 100644 --- a/src/docbkx/reference/mongo-repositories.xml +++ b/src/docbkx/reference/mongo-repositories.xml @@ -9,8 +9,8 @@ This chapter will point out the specialties for repository support for MongoDB. This builds on the core repository support explained in . So make sure you've got a sound understanding - of the basic concepts explained there. + linkend="repositories"/>. So make sure you've got a sound understanding of + the basic concepts explained there.
    @@ -91,6 +91,36 @@ configure mongo-template-ref explicitly if you deviate from this convention. + If you'd rather like to go with JavaConfig use the + @EnableMongoRepositories annotation. The + annotation carries the very same attributes like the namespace element. If + no base package is configured the infrastructure will scan the package of + the annotated configuration class. + + + JavaConfig for repositories + + @Configuration +@EnableMongoRepositories +class ApplicationConfig extends AbstractMongoConfiguration { + + @Override + protected String getDatabaseName() { + return "e-store"; + } + + @Override + public Mongo mongo() throws Exception { + return new Mongo(); + } + + @Override + protected String getMappingBasePackage() { + return "com.oreilly.springdata.mongodb" + } +} + + As our domain repository extends PagingAndSortingRepository it provides you with CRUD operations as well as methods for paginated and sorted access to @@ -169,11 +199,11 @@ public class PersonRepositoryTests { Supported keywords for query methods - + - + - + @@ -370,7 +400,7 @@ Distance distance = new Distance(200, Metrics.KILOMETERS); Geo-near queries - + public interface PersonRepository extends MongoRepository<Person, String> @@ -512,4 +542,4 @@ Page<Person> page = repository.findAll(person.lastname.contains("a"), MongoDB queries.
    - \ No newline at end of file + From c3b58c24f1abddaa0f8be83001ee5a0428950409 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 17 Jul 2012 12:40:27 +0200 Subject: [PATCH 09/49] DATAMONGO-485 - Added test case to show complex id's are working. --- .../MappingMongoConverterUnitTests.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java index 05c3ccced1..cb1536a436 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java @@ -1196,6 +1196,42 @@ public void readsURLFromStringOutOfTheBox() throws Exception { assertThat(result.url, is(new URL("http://springsource.org"))); } + /** + * @see DATAMONGO-485 + */ + @Test + public void writesComplexIdCorrectly() { + + ComplexId id = new ComplexId(); + id.innerId = 4711L; + + ClassWithComplexId entity = new ClassWithComplexId(); + entity.complexId = id; + + DBObject dbObject = new BasicDBObject(); + converter.write(entity, dbObject); + + Object idField = dbObject.get("_id"); + assertThat(idField, is(notNullValue())); + assertThat(idField, is(instanceOf(DBObject.class))); + assertThat(((DBObject) idField).get("innerId"), is((Object) 4711L)); + } + + /** + * @see DATAMONGO-485 + */ + @Test + public void readsComplexIdCorrectly() { + + DBObject innerId = new BasicDBObject("innerId", 4711L); + DBObject entity = new BasicDBObject("_id", innerId); + + ClassWithComplexId result = converter.read(ClassWithComplexId.class, entity); + + assertThat(result.complexId, is(notNullValue())); + assertThat(result.complexId.innerId, is(4711L)); + } + private static void assertSyntheticFieldValueOf(Object target, Object expected) { for (int i = 0; i < 10; i++) { @@ -1373,6 +1409,16 @@ static class URLWrapper { URL url; } + static class ClassWithComplexId { + + @Id + ComplexId complexId; + } + + static class ComplexId { + Long innerId; + } + private class LocalDateToDateConverter implements Converter { public Date convert(LocalDate source) { From 73423c313619629301ca8a79f966a27cc46cd035 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 19 Jul 2012 01:24:02 +0200 Subject: [PATCH 10/49] DATAMONGO-486 - Polished namespace implementation. Be better citizen regarding namespace support in STS. Moved ParsingUtils to Spring Data Commons. --- .../config/AbstractMongoConfiguration.java | 2 +- .../mongodb/config/MongoDbFactoryParser.java | 61 +++++--- .../data/mongodb/config/MongoParser.java | 81 +++++----- .../mongodb/config/MongoParsingUtils.java | 103 +++++++++++++ .../data/mongodb/config/ParsingUtils.java | 141 ------------------ ...MongoRepositoryConfigurationExtension.java | 8 +- 6 files changed, 188 insertions(+), 208 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java delete mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ParsingUtils.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java index 4547166f2c..0a4f7fe50b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java @@ -127,7 +127,7 @@ public MongoMappingContext mongoMappingContext() throws ClassNotFoundException { MongoMappingContext mappingContext = new MongoMappingContext(); mappingContext.setInitialEntitySet(getInitialEntitySet()); mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder()); - mappingContext.afterPropertiesSet(); + mappingContext.initialize(); return mappingContext; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java index 4813a4494b..6e65a7c639 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 by the original author(s). + * Copyright 2011-2012 by the original author(s). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,19 +15,19 @@ */ package org.springframework.data.mongodb.config; -import static org.springframework.data.mongodb.config.BeanNames.*; -import static org.springframework.data.mongodb.config.ParsingUtils.*; +import static org.springframework.data.config.ParsingUtils.*; +import static org.springframework.data.mongodb.config.MongoParsingUtils.*; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.authentication.UserCredentials; +import org.springframework.data.config.BeanComponentDefinitionBuilder; import org.springframework.data.mongodb.core.MongoFactoryBean; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; import org.springframework.util.StringUtils; @@ -44,19 +44,29 @@ */ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser { + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext) + */ @Override protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException { - String id = element.getAttribute("id"); - if (!StringUtils.hasText(id)) { - id = DB_FACTORY; - } - return id; + + String id = super.resolveId(element, definition, parserContext); + return StringUtils.hasText(id) ? id : BeanNames.DB_FACTORY; } + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext) + */ @Override protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { + Object source = parserContext.extractSource(element); + + BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext); + String uri = element.getAttribute("uri"); String mongoRef = element.getAttribute("mongo-ref"); String dbname = element.getAttribute("dbname"); @@ -64,12 +74,11 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa // Common setup BeanDefinitionBuilder dbFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SimpleMongoDbFactory.class); - ParsingUtils.setPropertyValue(element, dbFactoryBuilder, "write-concern", "writeConcern"); + setPropertyValue(dbFactoryBuilder, element, "write-concern", "writeConcern"); if (StringUtils.hasText(uri)) { if (StringUtils.hasText(mongoRef) || StringUtils.hasText(dbname) || userCredentials != null) { - parserContext.getReaderContext().error("Configure either Mongo URI or details individually!", - parserContext.extractSource(element)); + parserContext.getReaderContext().error("Configure either Mongo URI or details individually!", source); } dbFactoryBuilder.addConstructorArgValue(getMongoUri(uri)); @@ -77,19 +86,26 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa } // Defaulting - mongoRef = StringUtils.hasText(mongoRef) ? mongoRef : registerMongoBeanDefinition(element, parserContext); - dbname = StringUtils.hasText(dbname) ? dbname : "db"; + if (StringUtils.hasText(mongoRef)) { + dbFactoryBuilder.addConstructorArgReference(mongoRef); + } else { + dbFactoryBuilder.addConstructorArgValue(registerMongoBeanDefinition(element, parserContext)); + } - dbFactoryBuilder.addConstructorArgValue(new RuntimeBeanReference(mongoRef)); + dbname = StringUtils.hasText(dbname) ? dbname : "db"; dbFactoryBuilder.addConstructorArgValue(dbname); if (userCredentials != null) { dbFactoryBuilder.addConstructorArgValue(userCredentials); } - ParsingUtils.registerWriteConcernPropertyEditor(parserContext.getRegistry()); + BeanDefinitionBuilder writeConcernPropertyEditorBuilder = getWriteConcernPropertyEditorBuilder(); + + BeanComponentDefinition component = helper.getComponent(writeConcernPropertyEditorBuilder); + parserContext.registerBeanComponent(component); - return getSourceBeanDefinition(dbFactoryBuilder, parserContext, element); + return (AbstractBeanDefinition) helper.getComponentIdButFallback(dbFactoryBuilder, BeanNames.DB_FACTORY) + .getBeanDefinition(); } /** @@ -100,14 +116,13 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa * @param parserContext must not be {@literal null}. * @return */ - private String registerMongoBeanDefinition(Element element, ParserContext parserContext) { + private BeanDefinition registerMongoBeanDefinition(Element element, ParserContext parserContext) { BeanDefinitionBuilder mongoBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoFactoryBean.class); - ParsingUtils.setPropertyValue(element, mongoBuilder, "host"); - ParsingUtils.setPropertyValue(element, mongoBuilder, "port"); + setPropertyValue(mongoBuilder, element, "host"); + setPropertyValue(mongoBuilder, element, "port"); - return BeanDefinitionReaderUtils.registerWithGeneratedName(mongoBuilder.getBeanDefinition(), - parserContext.getRegistry()); + return getSourceBeanDefinition(mongoBuilder, parserContext, element); } /** diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java index 8c8be401ee..f03f9c697c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 the original author or authors. + * Copyright 2011-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,20 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mongodb.config; import java.util.Map; -import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.CustomEditorConfigurer; -import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.parsing.CompositeComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.ManagedMap; -import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.data.config.BeanComponentDefinitionBuilder; +import org.springframework.data.config.ParsingUtils; import org.springframework.data.mongodb.core.MongoFactoryBean; import org.springframework.util.StringUtils; import org.w3c.dom.Element; @@ -35,54 +35,59 @@ * Parser for <mongo;gt; definitions. * * @author Mark Pollack + * @author Oliver Gierke */ -public class MongoParser extends AbstractSingleBeanDefinitionParser { +public class MongoParser implements BeanDefinitionParser { - @Override - protected Class getBeanClass(Element element) { - return MongoFactoryBean.class; - } + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext) + */ + public BeanDefinition parse(Element element, ParserContext parserContext) { + + Object source = parserContext.extractSource(element); + String id = element.getAttribute("id"); - @Override - protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext); - ParsingUtils.setPropertyValue(element, builder, "port", "port"); - ParsingUtils.setPropertyValue(element, builder, "host", "host"); - ParsingUtils.setPropertyValue(element, builder, "write-concern", "writeConcern"); + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MongoFactoryBean.class); + ParsingUtils.setPropertyValue(builder, element, "port", "port"); + ParsingUtils.setPropertyValue(builder, element, "host", "host"); + ParsingUtils.setPropertyValue(builder, element, "write-concern", "writeConcern"); - ParsingUtils.parseMongoOptions(element, builder); - ParsingUtils.parseReplicaSet(element, builder); + MongoParsingUtils.parseMongoOptions(element, builder); + MongoParsingUtils.parseReplicaSet(element, builder); - registerServerAddressPropertyEditor(parserContext.getRegistry()); - ParsingUtils.registerWriteConcernPropertyEditor(parserContext.getRegistry()); + String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO; + parserContext.pushContainingComponent(new CompositeComponentDefinition("Mongo", source)); + + BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId); + parserContext.registerBeanComponent(mongoComponent); + BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(registerServerAddressPropertyEditor()); + parserContext.registerBeanComponent(serverAddressPropertyEditor); + BeanComponentDefinition writeConcernPropertyEditor = helper.getComponent(MongoParsingUtils + .getWriteConcernPropertyEditorBuilder()); + parserContext.registerBeanComponent(writeConcernPropertyEditor); + + parserContext.popAndRegisterContainingComponent(); + + return mongoComponent.getBeanDefinition(); } /** * One should only register one bean definition but want to have the convenience of using * AbstractSingleBeanDefinitionParser but have the side effect of registering a 'default' property editor with the * container. - * - * @param parserContext the ParserContext to */ - private void registerServerAddressPropertyEditor(BeanDefinitionRegistry registry) { + private BeanDefinitionBuilder registerServerAddressPropertyEditor() { - BeanDefinitionBuilder customEditorConfigurer = BeanDefinitionBuilder - .genericBeanDefinition(CustomEditorConfigurer.class); Map customEditors = new ManagedMap(); customEditors.put("com.mongodb.ServerAddress[]", "org.springframework.data.mongodb.config.ServerAddressPropertyEditor"); - customEditorConfigurer.addPropertyValue("customEditors", customEditors); - BeanDefinitionReaderUtils.registerWithGeneratedName(customEditorConfigurer.getBeanDefinition(), registry); - } - @Override - protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) - throws BeanDefinitionStoreException { - String name = super.resolveId(element, definition, parserContext); - if (!StringUtils.hasText(name)) { - name = "mongo"; - } - return name; + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class); + builder.addPropertyValue("customEditors", customEditors); + return builder; } -} \ No newline at end of file +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java new file mode 100644 index 0000000000..6613f7066f --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java @@ -0,0 +1,103 @@ +/* + * Copyright 2011-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.config; + +import static org.springframework.data.config.ParsingUtils.*; + +import java.util.Map; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.CustomEditorConfigurer; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.data.mongodb.core.MongoOptionsFactoryBean; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +/** + * Utility methods for {@link BeanDefinitionParser} implementations for MongoDB. + * + * @author Mark Pollack + * @author Oliver Gierke + */ +abstract class MongoParsingUtils { + + private MongoParsingUtils() { + + } + + /** + * Parses the mongo replica-set element. + * + * @param parserContext the parser context + * @param element the mongo element + * @param mongoBuilder the bean definition builder to populate + * @return + */ + static void parseReplicaSet(Element element, BeanDefinitionBuilder mongoBuilder) { + setPropertyValue(mongoBuilder, element, "replica-set", "replicaSetSeeds"); + } + + /** + * Parses the mongo:options sub-element. Populates the given attribute factory with the proper attributes. + * + * @return true if parsing actually occured, false otherwise + */ + static boolean parseMongoOptions(Element element, BeanDefinitionBuilder mongoBuilder) { + Element optionsElement = DomUtils.getChildElementByTagName(element, "options"); + if (optionsElement == null) { + return false; + } + + BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder + .genericBeanDefinition(MongoOptionsFactoryBean.class); + + setPropertyValue(optionsDefBuilder, optionsElement, "connections-per-host", "connectionsPerHost"); + setPropertyValue(optionsDefBuilder, optionsElement, "threads-allowed-to-block-for-connection-multiplier", + "threadsAllowedToBlockForConnectionMultiplier"); + setPropertyValue(optionsDefBuilder, optionsElement, "max-wait-time", "maxWaitTime"); + setPropertyValue(optionsDefBuilder, optionsElement, "connect-timeout", "connectTimeout"); + setPropertyValue(optionsDefBuilder, optionsElement, "socket-timeout", "socketTimeout"); + setPropertyValue(optionsDefBuilder, optionsElement, "socket-keep-alive", "socketKeepAlive"); + setPropertyValue(optionsDefBuilder, optionsElement, "auto-connect-retry", "autoConnectRetry"); + setPropertyValue(optionsDefBuilder, optionsElement, "max-auto-connect-retry-time", "maxAutoConnectRetryTime"); + setPropertyValue(optionsDefBuilder, optionsElement, "write-number", "writeNumber"); + setPropertyValue(optionsDefBuilder, optionsElement, "write-timeout", "writeTimeout"); + setPropertyValue(optionsDefBuilder, optionsElement, "write-fsync", "writeFsync"); + setPropertyValue(optionsDefBuilder, optionsElement, "slave-ok", "slaveOk"); + + mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition()); + return true; + } + + /** + * Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a + * {@link WriteConcernPropertyEditor}. + * + * @return + */ + static BeanDefinitionBuilder getWriteConcernPropertyEditorBuilder() { + + Map> customEditors = new ManagedMap>(); + customEditors.put("com.mongodb.WriteConcern", WriteConcernPropertyEditor.class); + + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class); + builder.addPropertyValue("customEditors", customEditors); + + return builder; + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ParsingUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ParsingUtils.java deleted file mode 100644 index 36a2411d35..0000000000 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ParsingUtils.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2011 by the original author(s). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.data.mongodb.config; - -import java.util.Map; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.CustomEditorConfigurer; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.ManagedMap; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.data.mongodb.core.MongoOptionsFactoryBean; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; -import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Element; - -abstract class ParsingUtils { - - /** - * Parses the mongo replica-set element. - * - * @param parserContext the parser context - * @param element the mongo element - * @param mongoBuilder the bean definition builder to populate - * @return true if parsing actually occured, false otherwise - */ - static boolean parseReplicaSet(Element element, BeanDefinitionBuilder mongoBuilder) { - - String replicaSetString = element.getAttribute("replica-set"); - if (StringUtils.hasText(replicaSetString)) { - mongoBuilder.addPropertyValue("replicaSetSeeds", replicaSetString); - } - return true; - - } - - /** - * Parses the mongo:options sub-element. Populates the given attribute factory with the proper attributes. - * - * @return true if parsing actually occured, false otherwise - */ - static boolean parseMongoOptions(Element element, BeanDefinitionBuilder mongoBuilder) { - Element optionsElement = DomUtils.getChildElementByTagName(element, "options"); - if (optionsElement == null) { - return false; - } - - BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder - .genericBeanDefinition(MongoOptionsFactoryBean.class); - - setPropertyValue(optionsElement, optionsDefBuilder, "connections-per-host", "connectionsPerHost"); - setPropertyValue(optionsElement, optionsDefBuilder, "threads-allowed-to-block-for-connection-multiplier", - "threadsAllowedToBlockForConnectionMultiplier"); - setPropertyValue(optionsElement, optionsDefBuilder, "max-wait-time", "maxWaitTime"); - setPropertyValue(optionsElement, optionsDefBuilder, "connect-timeout", "connectTimeout"); - setPropertyValue(optionsElement, optionsDefBuilder, "socket-timeout", "socketTimeout"); - setPropertyValue(optionsElement, optionsDefBuilder, "socket-keep-alive", "socketKeepAlive"); - setPropertyValue(optionsElement, optionsDefBuilder, "auto-connect-retry", "autoConnectRetry"); - setPropertyValue(optionsElement, optionsDefBuilder, "max-auto-connect-retry-time", "maxAutoConnectRetryTime"); - setPropertyValue(optionsElement, optionsDefBuilder, "write-number", "writeNumber"); - setPropertyValue(optionsElement, optionsDefBuilder, "write-timeout", "writeTimeout"); - setPropertyValue(optionsElement, optionsDefBuilder, "write-fsync", "writeFsync"); - setPropertyValue(optionsElement, optionsDefBuilder, "slave-ok", "slaveOk"); - - mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition()); - return true; - } - - static void setPropertyValue(Element element, BeanDefinitionBuilder builder, String attrName, String propertyName) { - String attr = element.getAttribute(attrName); - if (StringUtils.hasText(attr)) { - builder.addPropertyValue(propertyName, attr); - } - } - - /** - * Sets the property with the given attribute name on the given {@link BeanDefinitionBuilder} to the value of the - * attribute with the given name. - * - * @param element must not be {@literal null}. - * @param builder must not be {@literal null}. - * @param attrName must not be {@literal null} or empty. - */ - static void setPropertyValue(Element element, BeanDefinitionBuilder builder, String attrName) { - String attr = element.getAttribute(attrName); - if (StringUtils.hasText(attr)) { - builder.addPropertyValue(attrName, attr); - } - } - - /** - * Returns the {@link BeanDefinition} built by the given {@link BeanDefinitionBuilder} enriched with source - * information derived from the given {@link Element}. - * - * @param builder must not be {@literal null}. - * @param context must not be {@literal null}. - * @param element must not be {@literal null}. - * @return - */ - static AbstractBeanDefinition getSourceBeanDefinition(BeanDefinitionBuilder builder, ParserContext context, - Element element) { - AbstractBeanDefinition definition = builder.getBeanDefinition(); - definition.setSource(context.extractSource(element)); - return definition; - } - - /** - * Registers a {@link WriteConcernPropertyEditor} in the given {@link BeanDefinitionRegistry}. - * - * @param registry must not be {@literal null}. - */ - static void registerWriteConcernPropertyEditor(BeanDefinitionRegistry registry) { - - Assert.notNull(registry); - - BeanDefinitionBuilder customEditorConfigurer = BeanDefinitionBuilder - .genericBeanDefinition(CustomEditorConfigurer.class); - Map> customEditors = new ManagedMap>(); - customEditors.put("com.mongodb.WriteConcern", WriteConcernPropertyEditor.class); - customEditorConfigurer.addPropertyValue("customEditors", customEditors); - BeanDefinitionReaderUtils.registerWithGeneratedName(customEditorConfigurer.getBeanDefinition(), registry); - } -} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java index 27395d8cb8..6963a9fa1d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java @@ -17,6 +17,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.data.config.ParsingUtils; import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean; import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource; import org.springframework.data.repository.config.RepositoryConfigurationExtension; @@ -60,11 +61,8 @@ public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfiguratio Element element = config.getElement(); - String attribute = element.getAttribute(MONGO_TEMPLATE_REF); - builder.addPropertyReference("mongoOperations", attribute); - - attribute = element.getAttribute(CREATE_QUERY_INDEXES); - builder.addPropertyValue("createIndexesForQueryMethods", attribute); + ParsingUtils.setPropertyReference(builder, element, MONGO_TEMPLATE_REF, "mongoOperations"); + ParsingUtils.setPropertyValue(builder, element, CREATE_QUERY_INDEXES, "createIndexesForQueryMethods"); } /* From cdc1efef89b3963ddda1c6ff603ded698b3f7bc4 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 23 Jul 2012 16:26:51 +0200 Subject: [PATCH 11/49] DATAMONGO-489 - Ensure read collections get converted to appropriate target type. When reading BasicDBLists we now make sure the resulting collection is converted into the actual target type eventually. It might be an array and thus need an additional round of massaging before being returned as value. --- .../core/convert/MappingMongoConverter.java | 8 +++---- .../MappingMongoConverterUnitTests.java | 23 ++++++++++++++++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index e5d90c5a39..f6452dde91 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -713,10 +713,10 @@ protected Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, Sp * * @param targetType must not be {@literal null}. * @param sourceValue must not be {@literal null}. - * @return the converted {@link Collections}, will never be {@literal null}. + * @return the converted {@link Collection} or array, will never be {@literal null}. */ @SuppressWarnings("unchecked") - private Collection readCollectionOrArray(TypeInformation targetType, BasicDBList sourceValue, Object parent) { + private Object readCollectionOrArray(TypeInformation targetType, BasicDBList sourceValue, Object parent) { Assert.notNull(targetType); @@ -746,7 +746,7 @@ private Collection readCollectionOrArray(TypeInformation targetType, Basic } } - return items; + return getPotentiallyConvertedSimpleRead(items, targetType.getType()); } /** @@ -948,7 +948,7 @@ public T getPropertyValue(MongoPersistentProperty property) { } else if (value instanceof DBRef) { return (T) (rawType.equals(DBRef.class) ? value : read(type, ((DBRef) value).fetch(), parent)); } else if (value instanceof BasicDBList) { - return (T) getPotentiallyConvertedSimpleRead(readCollectionOrArray(type, (BasicDBList) value, parent), rawType); + return (T) readCollectionOrArray(type, (BasicDBList) value, parent); } else if (value instanceof DBObject) { return (T) read(type, (DBObject) value, parent); } else { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java index cb1536a436..e2acf9a6a0 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java @@ -363,7 +363,6 @@ public void readsCollectionWithInterfaceCorrectly() { Contact contact = result.contacts.get(0); assertThat(contact, is(instanceOf(Person.class))); assertThat(((Person) contact).firstname, is("Oliver")); - } @Test @@ -1232,6 +1231,27 @@ public void readsComplexIdCorrectly() { assertThat(result.complexId.innerId, is(4711L)); } + /** + * @see DATAMONGO-489 + */ + @Test + public void readsArraysAsMapValuesCorrectly() { + + BasicDBList list = new BasicDBList(); + list.add("Foo"); + list.add("Bar"); + + DBObject map = new BasicDBObject("key", list); + DBObject wrapper = new BasicDBObject("mapOfStrings", map); + + ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, wrapper); + assertThat(result.mapOfStrings, is(notNullValue())); + + String[] values = result.mapOfStrings.get("key"); + assertThat(values, is(notNullValue())); + assertThat(values, is(arrayWithSize(2))); + } + private static void assertSyntheticFieldValueOf(Object target, Object expected) { for (int i = 0; i < 10; i++) { @@ -1311,6 +1331,7 @@ static class ClassWithMapProperty { Map map; Map> mapOfLists; Map mapOfObjects; + Map mapOfStrings; } static class ClassWithNestedMaps { From 281f8b3995ce9b3404eb213edd70fac910b95e4d Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 23 Jul 2012 17:01:12 +0200 Subject: [PATCH 12/49] DATAMONGO-490 - Fixed typos. --- .../data/mongodb/config/AbstractMongoConfiguration.java | 6 +++--- .../data/mongodb/core/convert/CustomConversions.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java index 0a4f7fe50b..25583dcbd1 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java @@ -86,12 +86,12 @@ public MongoTemplate mongoTemplate() throws Exception { @Bean public SimpleMongoDbFactory mongoDbFactory() throws Exception { - UserCredentials creadentials = getUserCredentials(); + UserCredentials credentials = getUserCredentials(); - if (creadentials == null) { + if (credentials == null) { return new SimpleMongoDbFactory(mongo(), getDatabaseName()); } else { - return new SimpleMongoDbFactory(mongo(), getDatabaseName(), creadentials); + return new SimpleMongoDbFactory(mongo(), getDatabaseName(), credentials); } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java index ada9514750..40354e1ecd 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java @@ -223,7 +223,7 @@ public Class getCustomWriteTarget(Class source) { /** * Returns the target type we can write an onject of the given source type to. The returned type might be a subclass - * oth the given expected type though. If {@code expexctedTargetType} is {@literal null} we will simply return the + * oth the given expected type though. If {@code expectedTargetType} is {@literal null} we will simply return the * first target type matching or {@literal null} if no conversion can be found. * * @param source must not be {@literal null} From 190422f65185ab6520e629986aa522cda82ed38d Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 24 Jul 2012 13:23:40 +0200 Subject: [PATCH 13/49] DATAMONGO-474 - Populating id's after save now inspects field only. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far the algorithm to inspect whether an id property has to be set after a save(…) operation has used the plain BeanWrapper.getProperty(PersistentProperty property) method. This caused problems in case the getter of the id field returned something completely different (to be precise: a complex type not convertible out of the box). We now inspect the id field only to retrieve the value. --- .../data/mongodb/core/MongoTemplate.java | 2 +- .../mongodb/core/MongoTemplateUnitTests.java | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index ed7e95aa75..58e0c53dae 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -1372,7 +1372,7 @@ protected void populateIdIfNecessary(Object savedObject, Object id) { try { - Object idValue = wrapper.getProperty(idProp); + Object idValue = wrapper.getProperty(idProp, idProp.getType(), true); if (idValue != null) { return; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java index 59db409389..b972c24e02 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java @@ -22,6 +22,7 @@ import java.math.BigInteger; import java.util.Collections; +import java.util.regex.Pattern; import org.bson.types.ObjectId; import org.junit.Before; @@ -172,6 +173,31 @@ public void convertsUpdateConstraintsUsingConverters() { verify(collection, times(1)).update(Mockito.any(DBObject.class), eq(reference), anyBoolean(), anyBoolean()); } + /** + * @see DATAMONGO-474 + */ + @Test + public void setsUnpopulatedIdField() { + + NotAutogenerateableId entity = new NotAutogenerateableId(); + + template.populateIdIfNecessary(entity, 5); + assertThat(entity.id, is(5)); + } + + /** + * @see DATAMONGO-474 + */ + @Test + public void doesNotSetAlreadyPopulatedId() { + + NotAutogenerateableId entity = new NotAutogenerateableId(); + entity.id = 5; + + template.populateIdIfNecessary(entity, 7); + assertThat(entity.id, is(5)); + } + class AutogenerateableId { @Id @@ -182,6 +208,10 @@ class NotAutogenerateableId { @Id Integer id; + + public Pattern getId() { + return Pattern.compile("."); + } } enum MyConverter implements Converter { From fc0fd14964ab2bdf98da73624dde7ac327398937 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 24 Jul 2012 15:27:55 +0200 Subject: [PATCH 14/49] DATAMONGO-491 - Upgrade to Spring Data Commons 1.4.0.M1. --- spring-data-mongodb-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index 7d08da5ee3..842ab9e9cb 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -18,7 +18,7 @@ 3.0.7.RELEASE 4.0.0.RELEASE [${org.springframework.version.30}, ${org.springframework.version.40}) - 1.4.0.BUILD-SNAPSHOT + 1.4.0.M1 1.6.11.RELEASE true From 7ae6d82c3fc549a9fd9d5c1822a86abc4bb8ee8c Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 24 Jul 2012 16:50:53 +0200 Subject: [PATCH 15/49] DATAMONGO-491 - Prepare 1.1.0.M2 release. Updated changelog and links to reference documentation. --- src/docbkx/index.xml | 4 +- src/main/resources/changelog.txt | 91 ++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/src/docbkx/index.xml b/src/docbkx/index.xml index 5290dd587f..327aa54f7e 100644 --- a/src/docbkx/index.xml +++ b/src/docbkx/index.xml @@ -52,7 +52,7 @@ - + @@ -72,7 +72,7 @@ Appendix - + diff --git a/src/main/resources/changelog.txt b/src/main/resources/changelog.txt index d4d701139d..dbea2c5a03 100644 --- a/src/main/resources/changelog.txt +++ b/src/main/resources/changelog.txt @@ -1,6 +1,97 @@ Spring Data MongoDB Changelog ============================================= +Changes in version 1.1.0.M2 (2012-24-07) +---------------------------------------- +** Bug + * [DATAMONGO-378] - MapReduceResults ClassCastException due to raw results counts as Long + * [DATAMONGO-424] - Declaring a list of DBRef in a domian class results in Null for each DBRef when reading from mongo database + * [DATAMONGO-425] - Binding a Date to a manually defined repository query fails + * [DATAMONGO-428] - ClassCastException when using outputDatabase option in map-reduce + * [DATAMONGO-446] - Pageable query methods returning List are broken + * [DATAMONGO-447] - Removal of Documents fails in in debug mode for Documents with complex ids + * [DATAMONGO-450] - enabling DEBUG causes RuntimeException + * [DATAMONGO-454] - ServerAddressPropertyEditor fails if a hostname is unresolvable + * [DATAMONGO-458] - When reading back empty collections unmodifiable instances of Collections.emptyList/Set is returned. + * [DATAMONGO-462] - findAll() fails with NPE - discovering the root cause + * [DATAMONGO-465] - Mongo inserts document with "_id" as an integer but saves with "_id" as a string. + * [DATAMONGO-467] - String @id field is not mapped to ObjectId when using QueryDSL ".id" path + * [DATAMONGO-469] - Query creation from method names using AND criteria does not work anymore + * [DATAMONGO-474] - Wrong property is used for Id mapping + * [DATAMONGO-475] - 'group' operation fails where query references non primitive property + * [DATAMONGO-480] - The WriteResultChecking is not used in case of insert or save of documents. + * [DATAMONGO-483] - @Indexed(unique=true, name="foo") puts name's value to the 'key' in the MongoDB + * [DATAMONGO-489] - ClassCastException when loading Map + +** Improvement + * [DATAMONGO-448] - Remove the need for Converters for complex classes that are used as IDs + * [DATAMONGO-455] - Document how to use raw queries using BasicQuery + * [DATAMONGO-460] - Improve Querydsl implementation internals + * [DATAMONGO-466] - QueryMapper shouldn't map id properties of nested classes + * [DATAMONGO-470] - Criteria and Query should have proper equals(…) and hashCode() method. + * [DATAMONGO-477] - Change upper bound of Google Guava package import to 13 + * [DATAMONGO-482] - typo in documentation - 2 i's in usiing + * [DATAMONGO-486] - Polish namspace implementation + * [DATAMONGO-491] - Release 1.1.0.M2 + +** New Feature + * [DATAMONGO-476] - JavaConfig support for Mongo repositories + +** Task + * [DATAMONGO-451] - Tweak pom.xml to let Sonar build run without Bundlor + * [DATAMONGO-490] - Fix minor typos + + +Changes in version 1.0.3.RELEASE (2012-24-07) +--------------------------------------------- +** Bug + * [DATAMONGO-467] - String @id field is not mapped to ObjectId when using QueryDSL ".id" path + * [DATAMONGO-469] - Query creation from method names using AND criteria does not work anymore + * [DATAMONGO-474] - Wrong property is used for Id mapping + * [DATAMONGO-475] - 'group' operation fails where query references non primitive property + * [DATAMONGO-480] - The WriteResultChecking is not used in case of insert or save of documents. + * [DATAMONGO-483] - @Indexed(unique=true, name="foo") puts name's value to the 'key' in the MongoDB + * [DATAMONGO-489] - ClassCastException when loading Map + +** Improvement + * [DATAMONGO-466] - QueryMapper shouldn't map id properties of nested classes + * [DATAMONGO-470] - Criteria and Query should have proper equals(…) and hashCode() method. + * [DATAMONGO-482] - typo in documentation - 2 i's in usiing + +** Task + * [DATAMONGO-492] - Release 1.0.3 + + +Changes in version 1.0.2.RELEASE (2012-06-20) +--------------------------------------------- +** Bug + * [DATAMONGO-360] - java.lang.ClassCastException when placing GeospatialIndex into IndexOperations and invoking IndexOperations.getIndexInfo() + * [DATAMONGO-366] - Chapter 3.2. points to wrong bugtracker + * [DATAMONGO-378] - MapReduceResults ClassCastException due to raw results counts as Long + * [DATAMONGO-382] - ClassCastException: "com.mongodb.BasicDBObject cannot be cast to com.mongodb.BasicDBList" during find() + * [DATAMONGO-411] - Potential ClassCastExceptions in MongoPersistentEntityIndexCreator + * [DATAMONGO-412] - getUserCredentials() is called twice in AbstractMongoConfiguration::mongoDbFactory() + * [DATAMONGO-413] - Using "Or" in repository query yields a ClassCastException + * [DATAMONGO-422] - UUIDToBinaryConverter not compatible with mongo java driver + * [DATAMONGO-423] - Criteria.regex should use java.util.Pattern instead of $regex + * [DATAMONGO-425] - Binding a Date to a manually defined repository query fails + * [DATAMONGO-428] - ClassCastException when using outputDatabase option in map-reduce + * [DATAMONGO-429] - using @Query annotation, arrays are translated somewhere between query creation and mongo interpretation + * [DATAMONGO-446] - Pageable query methods returning List are broken + * [DATAMONGO-447] - Removal of Documents fails in in debug mode for Documents with complex ids + * [DATAMONGO-450] - enabling DEBUG causes RuntimeException + * [DATAMONGO-454] - ServerAddressPropertyEditor fails if a hostname is unresolvable + * [DATAMONGO-461] - MappedConstructor potentially throws NullPointerException + * [DATAMONGO-462] - findAll() fails with NPE - discovering the root cause + +** Improvement + * [DATAMONGO-448] - Remove the need for Converters for complex classes that are used as IDs + * [DATAMONGO-455] - Document how to use raw queries using BasicQuery + +** Task + * [DATAMONGO-463] - Release 1.0.2 + + Changes in version 1.1.0.M1 (2012-05-07) ---------------------------------------- From c91fb8cb986ba68f0c59e3082656114c3f7ba9ad Mon Sep 17 00:00:00 2001 From: Spring Buildmaster Date: Tue, 24 Jul 2012 07:57:10 -0700 Subject: [PATCH 16/49] DATAMONGO-491 - Release 1.1.0.M2. --- pom.xml | 2 +- spring-data-mongodb-cross-store/pom.xml | 4 ++-- spring-data-mongodb-log4j/pom.xml | 2 +- spring-data-mongodb-parent/pom.xml | 2 +- spring-data-mongodb/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 87d1272bb5..163ea63771 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-dist Spring Data MongoDB Distribution - 1.1.0.BUILD-SNAPSHOT + 1.1.0.M2 pom spring-data-mongodb diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index 7c6e536dc2..a5271738df 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.BUILD-SNAPSHOT + 1.1.0.M2 ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-cross-store @@ -42,7 +42,7 @@ org.springframework.data spring-data-mongodb - 1.1.0.BUILD-SNAPSHOT + 1.1.0.M2 diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index 52a36bc15b..228dca0964 100644 --- a/spring-data-mongodb-log4j/pom.xml +++ b/spring-data-mongodb-log4j/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.BUILD-SNAPSHOT + 1.1.0.M2 ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-log4j diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index 842ab9e9cb..66918f7676 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -5,7 +5,7 @@ spring-data-mongodb-parent Spring Data MongoDB Parent http://www.springsource.org/spring-data/mongodb - 1.1.0.BUILD-SNAPSHOT + 1.1.0.M2 pom UTF-8 diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index d136285eff..caea35623d 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.BUILD-SNAPSHOT + 1.1.0.M2 ../spring-data-mongodb-parent/pom.xml spring-data-mongodb From 24e2f3b728d8d76ef1ca3f082648699d0b4ddbac Mon Sep 17 00:00:00 2001 From: Spring Buildmaster Date: Tue, 24 Jul 2012 07:57:13 -0700 Subject: [PATCH 17/49] DATAMONGO-491 - Prepare next development iteration. --- pom.xml | 2 +- spring-data-mongodb-cross-store/pom.xml | 4 ++-- spring-data-mongodb-log4j/pom.xml | 2 +- spring-data-mongodb-parent/pom.xml | 2 +- spring-data-mongodb/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 163ea63771..87d1272bb5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-dist Spring Data MongoDB Distribution - 1.1.0.M2 + 1.1.0.BUILD-SNAPSHOT pom spring-data-mongodb diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index a5271738df..7c6e536dc2 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.M2 + 1.1.0.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-cross-store @@ -42,7 +42,7 @@ org.springframework.data spring-data-mongodb - 1.1.0.M2 + 1.1.0.BUILD-SNAPSHOT diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index 228dca0964..52a36bc15b 100644 --- a/spring-data-mongodb-log4j/pom.xml +++ b/spring-data-mongodb-log4j/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.M2 + 1.1.0.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-log4j diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index 66918f7676..842ab9e9cb 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -5,7 +5,7 @@ spring-data-mongodb-parent Spring Data MongoDB Parent http://www.springsource.org/spring-data/mongodb - 1.1.0.M2 + 1.1.0.BUILD-SNAPSHOT pom UTF-8 diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index caea35623d..d136285eff 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.M2 + 1.1.0.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb From 0ebfb900fb4555c0d901eabfc2b555465dbe3247 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 24 Jul 2012 20:13:50 +0200 Subject: [PATCH 18/49] DATAMONGO-493 - Added test case to show the described scenario is working. --- .../core/convert/QueryMapperUnitTests.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java index 4c635e3051..e95ee32f9b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java @@ -21,7 +21,9 @@ import static org.springframework.data.mongodb.core.query.Query.*; import java.math.BigInteger; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.bson.types.ObjectId; import org.junit.Before; @@ -212,6 +214,23 @@ public void doesNotHandleNestedFieldsWithDefaultIdNames() { assertThat(((DBObject) result.get("nested")).get("id"), is(instanceOf(String.class))); } + /** + * @see DATAMONGO-493 + */ + @Test + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void foo() { + + Query query = Query.query(Criteria.where("id").is("id_value").and("publishers").ne("a_string_value")); + + DBObject dbObject = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(UserEntity.class)); + assertThat(dbObject.get("publishers"), isA((Class) DBObject.class)); + + DBObject publishers = (DBObject) dbObject.get("publishers"); + assertThat(publishers.containsField("$ne"), is(true)); + assertThat(publishers.get("$ne"), is((Object) "a_string_value")); + } + class IdWrapper { Object id; } @@ -237,4 +256,9 @@ class BigIntegerId { enum Enum { INSTANCE; } + + class UserEntity { + String id; + List publishers = new ArrayList(); + } } From fff89984557c7add8f9ccd4b767b618c1c32b2a1 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 24 Jul 2012 20:43:52 +0200 Subject: [PATCH 19/49] DATAMONGO-493 - Fixed broken $ne handling in QueryMapper. $ne expressions are now only being tried to be converted into an ObjectId in case they follow an id property. Previously they tried in every case which might have led to Strings being converted into ObjectIds that accidentally were valid ObjectIds but didn't represent an id at all. --- .../data/mongodb/core/convert/QueryMapper.java | 4 ++-- .../mongodb/core/convert/QueryMapperUnitTests.java | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java index 4c6aef514b..9f81181bdc 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java @@ -85,6 +85,8 @@ public DBObject getMappedObject(DBObject query, MongoPersistentEntity entity) ids.add(convertId(id)); } valueDbo.put(inKey, ids.toArray(new Object[ids.size()])); + } else if (valueDbo.containsField("$ne")) { + valueDbo.put("$ne", convertId(valueDbo.get("$ne"))); } else { value = getMappedObject((DBObject) value, null); } @@ -101,8 +103,6 @@ public DBObject getMappedObject(DBObject query, MongoPersistentEntity entity) newConditions.add(getMappedObject((DBObject) iter.next(), null)); } value = newConditions; - } else if (key.equals("$ne")) { - value = convertId(value); } newDbo.put(newKey, convertSimpleOrDBObject(value, null)); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java index e95ee32f9b..6fb7cfa7a5 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java @@ -218,17 +218,19 @@ public void doesNotHandleNestedFieldsWithDefaultIdNames() { * @see DATAMONGO-493 */ @Test - @SuppressWarnings({ "unchecked", "rawtypes" }) - public void foo() { + public void doesNotTranslateNonIdPropertiesFor$NeCriteria() { - Query query = Query.query(Criteria.where("id").is("id_value").and("publishers").ne("a_string_value")); + ObjectId accidentallyAnObjectId = new ObjectId(); + + Query query = Query.query(Criteria.where("id").is("id_value").and("publishers") + .ne(accidentallyAnObjectId.toString())); DBObject dbObject = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(UserEntity.class)); - assertThat(dbObject.get("publishers"), isA((Class) DBObject.class)); + assertThat(dbObject.get("publishers"), is(instanceOf(DBObject.class))); DBObject publishers = (DBObject) dbObject.get("publishers"); assertThat(publishers.containsField("$ne"), is(true)); - assertThat(publishers.get("$ne"), is((Object) "a_string_value")); + assertThat(publishers.get("$ne"), is(instanceOf(String.class))); } class IdWrapper { From 55a16a354c56ff6d3958a1e4548b3b06e6786f6d Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 26 Jul 2012 10:19:58 +0200 Subject: [PATCH 20/49] =?UTF-8?q?DATAMONGO-495=20-=20Fixed=20debug=20outpu?= =?UTF-8?q?t=20in=20MongoTemplate.doFind(=E2=80=A6).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using SerializationUtils to safely output the query to be executed. --- .../data/mongodb/core/MongoTemplate.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index 58e0c53dae..e3f6019bad 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -15,6 +15,7 @@ */ package org.springframework.data.mongodb.core; +import static org.springframework.data.mongodb.core.SerializationUtils.*; import static org.springframework.data.mongodb.core.query.Criteria.*; import java.io.IOException; @@ -337,7 +338,7 @@ protected void executeQuery(Query query, String collectionName, DocumentCallback if (LOGGER.isDebugEnabled()) { LOGGER.debug(String.format("Executing query: %s sort: %s fields: %s in collection: $s", - SerializationUtils.serializeToJsonSafely(queryObject), sortObject, fieldsObject, collectionName)); + serializeToJsonSafely(queryObject), sortObject, fieldsObject, collectionName)); } this.executeQueryInternal(new FindCallback(queryObject, fieldsObject), preparer, dch, collectionName); @@ -1021,8 +1022,7 @@ public MapReduceResults mapReduce(Query query, String inputCollectionName handleCommandError(commandResult, commandObject); if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format("MapReduce command result = [%s]", - SerializationUtils.serializeToJsonSafely(commandObject))); + LOGGER.debug(String.format("MapReduce command result = [%s]", serializeToJsonSafely(commandObject))); } MapReduceOutput mapReduceOutput = new MapReduceOutput(inputCollection, commandObject, commandResult); @@ -1075,8 +1075,7 @@ public GroupByResults group(Criteria criteria, String inputCollectionName DBObject commandObject = new BasicDBObject("group", dbo); if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format("Executing Group with DBObject [%s]", - SerializationUtils.serializeToJsonSafely(commandObject))); + LOGGER.debug(String.format("Executing Group with DBObject [%s]", serializeToJsonSafely(commandObject))); } CommandResult commandResult = executeCommand(commandObject, getDb().getOptions()); @@ -1252,11 +1251,14 @@ protected List doFind(String collectionName, DBObject query, DBObject fie protected List doFind(String collectionName, DBObject query, DBObject fields, Class entityClass, CursorPreparer preparer, DbObjectCallback objectCallback) { + MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); + if (LOGGER.isDebugEnabled()) { - LOGGER.debug("find using query: " + query + " fields: " + fields + " for class: " + entityClass - + " in collection: " + collectionName); + LOGGER.debug(String.format("find using query: %s fields: %s for class: %s in collection: %s", + serializeToJsonSafely(query), fields, entityClass, collectionName)); } + return executeFindMultiInternal(new FindCallback(mapper.getMappedObject(query, entity), fields), preparer, objectCallback, collectionName); } From 5e0bca9dc82137fb20c6e0171cfb0bc5280a39f5 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 27 Jul 2012 10:39:31 +0200 Subject: [PATCH 21/49] DATAMONGO-494 - QueryMapper now forwards entity metadata into nested $(n)or criterias. Introduced helper class to ease assertions on DBObjects as well. --- .../mongodb/core/convert/QueryMapper.java | 2 +- .../data/mongodb/core/DBObjectUtils.java | 81 +++++++++++++++++++ .../core/convert/QueryMapperUnitTests.java | 26 +++++- 3 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DBObjectUtils.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java index 9f81181bdc..440ba17026 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java @@ -100,7 +100,7 @@ public DBObject getMappedObject(DBObject query, MongoPersistentEntity entity) BasicBSONList newConditions = new BasicBSONList(); Iterator iter = conditions.iterator(); while (iter.hasNext()) { - newConditions.add(getMappedObject((DBObject) iter.next(), null)); + newConditions.add(getMappedObject((DBObject) iter.next(), entity)); } value = newConditions; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DBObjectUtils.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DBObjectUtils.java new file mode 100644 index 0000000000..a9be3ba3af --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DBObjectUtils.java @@ -0,0 +1,81 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.core; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import com.mongodb.BasicDBList; +import com.mongodb.DBObject; + +/** + * Helper classes to ease assertions on {@link DBObject}s. + * + * @author Oliver Gierke + */ +public abstract class DBObjectUtils { + + private DBObjectUtils() { + + } + + /** + * Expects the field with the given key to be not {@literal null} and a {@link DBObject} in turn and returns it. + * + * @param source the {@link DBObject} to lookup the nested one + * @param key the key of the field to lokup the nested {@link DBObject} + * @return + */ + public static DBObject getAsDBObject(DBObject source, String key) { + return getTypedValue(source, key, DBObject.class); + } + + /** + * Expects the field with the given key to be not {@literal null} and a {@link BasicDBList}. + * + * @param source the {@link DBObject} to lookup the {@link BasicDBList} in + * @param key the key of the field to find the {@link BasicDBList} in + * @return + */ + public static BasicDBList getAsDBList(DBObject source, String key) { + return getTypedValue(source, key, BasicDBList.class); + } + + /** + * Expects the list element with the given index to be a non-{@literal null} {@link DBObject} and returns it. + * + * @param source the {@link BasicDBList} to look up the {@link DBObject} element in + * @param index the index of the element expected to contain a {@link DBObject} + * @return + */ + public static DBObject getAsDBObject(BasicDBList source, int index) { + + assertThat(source.size(), greaterThanOrEqualTo(index + 1)); + Object value = source.get(index); + assertThat(value, is(instanceOf(DBObject.class))); + return (DBObject) value; + } + + @SuppressWarnings("unchecked") + private static T getTypedValue(DBObject source, String key, Class type) { + + Object value = source.get(key); + assertThat(value, is(notNullValue())); + assertThat(value, is(instanceOf(type))); + + return (T) value; + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java index 6fb7cfa7a5..c1c2945968 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java @@ -1,11 +1,11 @@ /* - * Copyright (c) 2011 by the original author(s). + * Copyright 2011-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,6 +19,7 @@ import static org.junit.Assert.*; import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*; +import static org.springframework.data.mongodb.core.DBObjectUtils.*; import java.math.BigInteger; import java.util.ArrayList; @@ -51,7 +52,6 @@ * @author Oliver Gierke */ @RunWith(MockitoJUnitRunner.class) -@SuppressWarnings("unused") public class QueryMapperUnitTests { QueryMapper mapper; @@ -233,6 +233,26 @@ public void doesNotHandleNestedFieldsWithDefaultIdNames() { assertThat(publishers.get("$ne"), is(instanceOf(String.class))); } + /** + * @see DATAMONGO-494 + */ + @Test + public void usesEntityMetadataInOr() { + + Query query = query(new Criteria().orOperator(where("foo").is("bar"))); + DBObject result = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(Sample.class)); + + assertThat(result.keySet(), hasSize(1)); + assertThat(result.keySet(), hasItem("$or")); + + BasicDBList ors = getAsDBList(result, "$or"); + assertThat(ors, hasSize(1)); + DBObject criterias = getAsDBObject(ors, 0); + assertThat(criterias.keySet(), hasSize(1)); + assertThat(criterias.get("_id"), is(notNullValue())); + assertThat(criterias.get("foo"), is(nullValue())); + } + class IdWrapper { Object id; } From dd7222d0aa1e82de1c6f1dca8e1ff973048a24b2 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 30 Jul 2012 15:39:22 +0200 Subject: [PATCH 22/49] DATAMONGO-497 - Fixed reading of empty collections. Reading an empty collection always returned a HashSet assuming the returned value would be converted into the assigned properties value later on. However the method should rather return the correct type already which we do now by invoking the potential conversion. --- .../core/convert/MappingMongoConverter.java | 5 +++-- .../MappingMongoConverterUnitTests.java | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index f6452dde91..3dcfb9dfee 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -720,11 +720,12 @@ private Object readCollectionOrArray(TypeInformation targetType, BasicDBList Assert.notNull(targetType); + Class collectionType = targetType.getType(); + if (sourceValue.isEmpty()) { - return new HashSet(); + return getPotentiallyConvertedSimpleRead(new HashSet(), collectionType); } - Class collectionType = targetType.getType(); collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class; Collection items = targetType.getType().isArray() ? new ArrayList() : CollectionFactory diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java index e2acf9a6a0..18d231a6ed 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java @@ -1252,6 +1252,18 @@ public void readsArraysAsMapValuesCorrectly() { assertThat(values, is(arrayWithSize(2))); } + /** + * @see DATAMONGO-497 + */ + @Test + public void readsEmptyCollectionIntoConstructorCorrectly() { + + DBObject source = new BasicDBObject("attributes", new BasicDBList()); + + TypWithCollectionConstructor result = converter.read(TypWithCollectionConstructor.class, source); + assertThat(result.attributes, is(notNullValue())); + } + private static void assertSyntheticFieldValueOf(Object target, Object expected) { for (int i = 0; i < 10; i++) { @@ -1440,6 +1452,15 @@ static class ComplexId { Long innerId; } + static class TypWithCollectionConstructor { + + List attributes; + + public TypWithCollectionConstructor(List attributes) { + this.attributes = attributes; + } + } + private class LocalDateToDateConverter implements Converter { public Date convert(LocalDate source) { From bf436ccaab152aaaaaddb5799c4c41e737753d1f Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 30 Jul 2012 17:27:44 +0200 Subject: [PATCH 23/49] DATAMONGO-496 - AbstractMongoConfiguration now defaults mapping base package. AbstractMappingConfiguration now uses the package of the class extending it to enable entity scanning for that package. To disable entity scanning entirely override the method to return null or an empty String. --- .../config/AbstractMongoConfiguration.java | 12 ++- .../AbstractMongoConfigurationUnitTests.java | 97 +++++++++++++++++++ 2 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AbstractMongoConfigurationUnitTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java index 25583dcbd1..6333d0ef6e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java @@ -39,7 +39,7 @@ import com.mongodb.Mongo; /** - * Base class for Spring Data Mongo configuration using JavaConfig. + * Base class for Spring Data MongoDB configuration using JavaConfig. * * @author Mark Pollack * @author Oliver Gierke @@ -96,12 +96,16 @@ public SimpleMongoDbFactory mongoDbFactory() throws Exception { } /** - * Return the base package to scan for mapped {@link Document}s. + * Return the base package to scan for mapped {@link Document}s. Will return the package name of the configuration + * class' (the concrete class, not this one here) by default. So if you have a {@code com.acme.AppConfig} extending + * {@link AbstractMongoConfiguration} the base package will be considered {@code com.acme} unless the method is + * overriden to implement alternate behaviour. * - * @return + * @return the base package to scan for mapped {@link Document} classes or {@literal null} to not enable scanning for + * entities. */ protected String getMappingBasePackage() { - return null; + return getClass().getPackage().getName(); } /** diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AbstractMongoConfigurationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AbstractMongoConfigurationUnitTests.java new file mode 100644 index 0000000000..9423978b2a --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AbstractMongoConfigurationUnitTests.java @@ -0,0 +1,97 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.config; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import org.junit.Test; +import org.springframework.context.annotation.Bean; +import org.springframework.data.mongodb.core.mapping.Document; + +import com.mongodb.Mongo; + +/** + * Unit tests for {@link AbstractMongoConfiguration}. + * + * @author Oliver Gierke + */ +public class AbstractMongoConfigurationUnitTests { + + /** + * @see DATAMONGO-496 + */ + @Test + public void usesConfigClassPackageAsBaseMappingPackage() throws ClassNotFoundException { + + AbstractMongoConfiguration configuration = new SampleMongoConfiguration(); + assertThat(configuration.getMappingBasePackage(), is(SampleMongoConfiguration.class.getPackage().getName())); + assertThat(configuration.getInitialEntitySet(), hasSize(1)); + assertThat(configuration.getInitialEntitySet(), hasItem(Entity.class)); + } + + /** + * @see DATAMONGO-496 + */ + @Test + public void doesNotScanPackageIfMappingPackageIsNull() throws ClassNotFoundException { + + assertScanningDisabled(null); + + } + + /** + * @see DATAMONGO-496 + */ + @Test + public void doesNotScanPackageIfMappingPackageIsEmpty() throws ClassNotFoundException { + + assertScanningDisabled(""); + assertScanningDisabled(" "); + } + + private static void assertScanningDisabled(final String value) throws ClassNotFoundException { + + AbstractMongoConfiguration configuration = new SampleMongoConfiguration() { + @Override + protected String getMappingBasePackage() { + return value; + } + }; + + assertThat(configuration.getMappingBasePackage(), is(value)); + assertThat(configuration.getInitialEntitySet(), hasSize(0)); + } + + static class SampleMongoConfiguration extends AbstractMongoConfiguration { + + @Override + protected String getDatabaseName() { + return "database"; + } + + @Bean + @Override + public Mongo mongo() throws Exception { + return new Mongo(); + } + } + + @Document + static class Entity { + + } +} From 5860a9d13de02c68772bb83df95bb491a269d4e9 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 31 Jul 2012 10:39:03 +0200 Subject: [PATCH 24/49] DATAMONGO-499 - Fixed namespace reference to repository XSD. --- .../springframework/data/mongodb/config/spring-mongo-1.0.xsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd index 702c855b03..a027962ae9 100644 --- a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd +++ b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.0.xsd @@ -14,7 +14,7 @@ + schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository-1.0.xsd" /> From 697a96bc6ed2710297660ddd9a480af1a4d65ee6 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 31 Jul 2012 15:32:56 +0200 Subject: [PATCH 25/49] DATAMONGO-500 - Index creation is only done for the correct MappingContext. Index creation now double checks the MappingContext a MappingContextEvent originates from before actually creating indexes. This avoids invalid indexes being created in a multi-database scenario. --- spring-data-mongodb-parent/pom.xml | 2 +- .../config/MappingMongoConverterParser.java | 39 ++++++----- .../data/mongodb/core/MongoTemplate.java | 18 ++--- .../core/convert/MappingMongoConverter.java | 11 +--- .../index/MongoMappingEventPublisher.java | 38 +++++++---- .../MongoPersistentEntityIndexCreator.java | 12 +++- ...entEntityIndexCreatorIntegrationTests.java | 66 +++++++++++++++++++ ...PersistentEntityIndexCreatorUnitTests.java | 26 ++++++++ .../data/mongodb/core/index/SampleEntity.java | 14 ++++ ...tyIndexCreatorIntegrationTests-context.xml | 23 +++++++ 10 files changed, 197 insertions(+), 52 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/SampleEntity.java create mode 100644 spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests-context.xml diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index 842ab9e9cb..7d08da5ee3 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -18,7 +18,7 @@ 3.0.7.RELEASE 4.0.0.RELEASE [${org.springframework.version.30}, ${org.springframework.version.40}) - 1.4.0.M1 + 1.4.0.BUILD-SNAPSHOT 1.6.11.RELEASE true diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java index dfb7e97914..8bfd4aaa6c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java @@ -48,6 +48,7 @@ import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.core.type.filter.TypeFilter; import org.springframework.data.annotation.Persistent; +import org.springframework.data.config.BeanComponentDefinitionBuilder; import org.springframework.data.mongodb.core.convert.CustomConversions; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator; @@ -166,27 +167,35 @@ private String potentiallyCreateMappingContext(Element element, ParserContext pa BeanDefinition conversionsDefinition) { String ctxRef = element.getAttribute("mapping-context-ref"); - if (!StringUtils.hasText(ctxRef)) { - BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder - .genericBeanDefinition(MongoMappingContext.class); - Set classesToAdd = getInititalEntityClasses(element, mappingContextBuilder); - if (classesToAdd != null) { - mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd); - } + if (StringUtils.hasText(ctxRef)) { + return ctxRef; + } - if (conversionsDefinition != null) { - AbstractBeanDefinition simpleTypesDefinition = new GenericBeanDefinition(); - simpleTypesDefinition.setFactoryBeanName("customConversions"); - simpleTypesDefinition.setFactoryMethodName("getSimpleTypeHolder"); + BeanComponentDefinitionBuilder componentDefinitionBuilder = new BeanComponentDefinitionBuilder(element, + parserContext); - mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition); - } + BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder + .genericBeanDefinition(MongoMappingContext.class); - parserContext.getRegistry().registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition()); - ctxRef = MAPPING_CONTEXT; + Set classesToAdd = getInititalEntityClasses(element, mappingContextBuilder); + if (classesToAdd != null) { + mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd); } + if (conversionsDefinition != null) { + AbstractBeanDefinition simpleTypesDefinition = new GenericBeanDefinition(); + simpleTypesDefinition.setFactoryBeanName("customConversions"); + simpleTypesDefinition.setFactoryMethodName("getSimpleTypeHolder"); + + mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition); + } + + parserContext.getRegistry().registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition()); + ctxRef = MAPPING_CONTEXT; + + parserContext.registerBeanComponent(componentDefinitionBuilder.getComponent(mappingContextBuilder, ctxRef)); + return ctxRef; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index e3f6019bad..f2c182d60b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -1372,21 +1372,13 @@ protected void populateIdIfNecessary(Object savedObject, Object id) { ConversionService conversionService = mongoConverter.getConversionService(); BeanWrapper, Object> wrapper = BeanWrapper.create(savedObject, conversionService); - try { - - Object idValue = wrapper.getProperty(idProp, idProp.getType(), true); - - if (idValue != null) { - return; - } - - wrapper.setProperty(idProp, id); + Object idValue = wrapper.getProperty(idProp, idProp.getType(), true); - } catch (IllegalAccessException e) { - throw new MappingException(e.getMessage(), e); - } catch (InvocationTargetException e) { - throw new MappingException(e.getMessage(), e); + if (idValue != null) { + return; } + + wrapper.setProperty(idProp, id); } private DBCollection getAndPrepareCollection(DB db, String collectionName) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index 3dcfb9dfee..68bfe67f19 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -15,7 +15,6 @@ */ package org.springframework.data.mongodb.core.convert; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -253,13 +252,9 @@ public void doWithPersistentProperty(MongoPersistentProperty prop) { public void doWithAssociation(Association association) { MongoPersistentProperty inverseProp = association.getInverse(); Object obj = getValueInternal(inverseProp, dbo, evaluator, result); - try { - wrapper.setProperty(inverseProp, obj); - } catch (IllegalAccessException e) { - throw new MappingException(e.getMessage(), e); - } catch (InvocationTargetException e) { - throw new MappingException(e.getMessage(), e); - } + + wrapper.setProperty(inverseProp, obj); + } }); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java index bf76048d28..f1197deb1d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java @@ -1,11 +1,11 @@ /* - * Copyright (c) 2011 by the original author(s). + * Copyright 2011-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,37 +13,51 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mongodb.core.index; +import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.mapping.event.MappingContextEvent; +import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; +import org.springframework.data.mongodb.core.mapping.event.AfterLoadEvent; +import org.springframework.data.mongodb.core.mapping.event.AfterSaveEvent; +import org.springframework.util.Assert; /** - * An implementation of ApplicationEventPublisher that will only fire MappingContextEvents for use by the index creator - * when MongoTemplate is used 'stand-alone', that is not declared inside a Spring ApplicationContext. - * - * Declare MongoTemplate inside an ApplicationContext to enable the publishing of all persistence events such as - * {@link AfterLoadEvent}, {@link AfterSaveEvent}, etc. + * An implementation of ApplicationEventPublisher that will only fire {@link MappingContextEvent}s for use by the index + * creator when MongoTemplate is used 'stand-alone', that is not declared inside a Spring {@link ApplicationContext}. + * Declare {@link MongoTemplate} inside an {@link ApplicationContext} to enable the publishing of all persistence events + * such as {@link AfterLoadEvent}, {@link AfterSaveEvent}, etc. * - * @author Jon Brisbin + * @author Jon Brisbin + * @author Oliver Gierke */ public class MongoMappingEventPublisher implements ApplicationEventPublisher { - private MongoPersistentEntityIndexCreator indexCreator; + private final MongoPersistentEntityIndexCreator indexCreator; + /** + * Creates a new {@link MongoMappingEventPublisher} for the given {@link MongoPersistentEntityIndexCreator}. + * + * @param indexCreator must not be {@literal null}. + */ public MongoMappingEventPublisher(MongoPersistentEntityIndexCreator indexCreator) { + + Assert.notNull(indexCreator); this.indexCreator = indexCreator; } + /* + * (non-Javadoc) + * @see org.springframework.context.ApplicationEventPublisher#publishEvent(org.springframework.context.ApplicationEvent) + */ @SuppressWarnings("unchecked") public void publishEvent(ApplicationEvent event) { if (event instanceof MappingContextEvent) { - indexCreator - .onApplicationEvent((MappingContextEvent, MongoPersistentProperty>) event); + indexCreator.onApplicationEvent((MappingContextEvent, MongoPersistentProperty>) event); } } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java index ed644a7feb..3356745e17 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java @@ -44,12 +44,13 @@ * @author Oliver Gierke */ public class MongoPersistentEntityIndexCreator implements - ApplicationListener, MongoPersistentProperty>> { + ApplicationListener, MongoPersistentProperty>> { private static final Logger log = LoggerFactory.getLogger(MongoPersistentEntityIndexCreator.class); private final Map, Boolean> classesSeen = new ConcurrentHashMap, Boolean>(); private final MongoDbFactory mongoDbFactory; + private final MongoMappingContext mappingContext; /** * Creats a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and @@ -62,7 +63,9 @@ public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, Mon Assert.notNull(mongoDbFactory); Assert.notNull(mappingContext); + this.mongoDbFactory = mongoDbFactory; + this.mappingContext = mappingContext; for (MongoPersistentEntity entity : mappingContext.getPersistentEntities()) { checkForIndexes(entity); @@ -73,8 +76,11 @@ public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, Mon * (non-Javadoc) * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) */ - public void onApplicationEvent( - MappingContextEvent, MongoPersistentProperty> event) { + public void onApplicationEvent(MappingContextEvent, MongoPersistentProperty> event) { + + if (!event.wasEmittedBy(mappingContext)) { + return; + } PersistentEntity entity = event.getPersistentEntity(); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests.java new file mode 100644 index 0000000000..fd468fda5c --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.core.index; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.util.List; + +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * Integration tests for {@link MongoPersistentEntityIndexCreator}. + * + * @author Oliver Gierke + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class MongoPersistentEntityIndexCreatorIntegrationTests { + + @Autowired + @Qualifier("mongo1") + MongoOperations templateOne; + + @Autowired + @Qualifier("mongo2") + MongoOperations templateTwo; + + @After + public void cleanUp() { + templateOne.dropCollection(SampleEntity.class); + templateTwo.dropCollection(SampleEntity.class); + } + + @Test + public void foo() { + + List indexInfo = templateOne.indexOps(SampleEntity.class).getIndexInfo(); + assertThat(indexInfo, hasSize(greaterThan(0))); + assertThat(indexInfo, Matchers. hasItem(hasProperty("name", is("prop")))); + + indexInfo = templateTwo.indexOps(SampleEntity.class).getIndexInfo(); + assertThat(indexInfo, hasSize(0)); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java index f99469b7cf..6e46b5d409 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java @@ -24,9 +24,13 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.data.mapping.event.MappingContextEvent; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.mapping.Field; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; +import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import com.mongodb.DBObject; @@ -40,6 +44,8 @@ public class MongoPersistentEntityIndexCreatorUnitTests { @Mock MongoDbFactory factory; + @Mock + ApplicationContext context; @Test public void buildsIndexDefinitionUsingFieldName() { @@ -55,6 +61,26 @@ public void buildsIndexDefinitionUsingFieldName() { assertThat(creator.name, is("indexName")); } + @Test + public void doesNotCreateIndexForEntityComingFromDifferentMappingContext() { + + MongoMappingContext mappingContext = new MongoMappingContext(); + + MongoMappingContext personMappingContext = new MongoMappingContext(); + personMappingContext.setInitialEntitySet(Collections.singleton(Person.class)); + personMappingContext.initialize(); + + DummyMongoPersistentEntityIndexCreator creator = new DummyMongoPersistentEntityIndexCreator(mappingContext, factory); + + MongoPersistentEntity entity = personMappingContext.getPersistentEntity(Person.class); + MappingContextEvent, MongoPersistentProperty> event = new MappingContextEvent, MongoPersistentProperty>( + personMappingContext, entity); + + creator.onApplicationEvent(event); + + assertThat(creator.indexDefinition, is(nullValue())); + } + static class Person { @Indexed(name = "indexName") diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/SampleEntity.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/SampleEntity.java new file mode 100644 index 0000000000..a099c4cb08 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/SampleEntity.java @@ -0,0 +1,14 @@ +package org.springframework.data.mongodb.core.index; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +public class SampleEntity { + + @Id + String id; + + @Indexed + String prop; +} diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests-context.xml new file mode 100644 index 0000000000..6ed28955f5 --- /dev/null +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests-context.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + From 4213be4caa4f9956d488f80ee73230ffb6d71a03 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 8 Aug 2012 18:56:18 +0200 Subject: [PATCH 26/49] DATAMONGO-502 - QueryMapper now translates property names into field names. --- .../mongodb/core/convert/QueryMapper.java | 32 +++++++++++++- .../core/convert/QueryMapperUnitTests.java | 42 ++++++++++++++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java index 440ba17026..170b6b1043 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java @@ -25,6 +25,10 @@ import org.springframework.core.convert.ConversionException; import org.springframework.core.convert.ConversionService; import org.springframework.data.mapping.PersistentEntity; +import org.springframework.data.mapping.PropertyPath; +import org.springframework.data.mapping.PropertyReferenceException; +import org.springframework.data.mapping.context.MappingContext; +import org.springframework.data.mapping.context.PersistentPropertyPath; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.util.Assert; @@ -46,6 +50,7 @@ public class QueryMapper { private final ConversionService conversionService; private final MongoConverter converter; + private final MappingContext, MongoPersistentProperty> mappingContext; /** * Creates a new {@link QueryMapper} with the given {@link MongoConverter}. @@ -53,9 +58,12 @@ public class QueryMapper { * @param converter must not be {@literal null}. */ public QueryMapper(MongoConverter converter) { + Assert.notNull(converter); + this.conversionService = converter.getConversionService(); this.converter = converter; + this.mappingContext = converter.getMappingContext(); } /** @@ -72,7 +80,7 @@ public DBObject getMappedObject(DBObject query, MongoPersistentEntity entity) for (String key : query.keySet()) { - String newKey = key; + String newKey = determineKey(key, entity); Object value = query.get(key); if (isIdKey(key, entity)) { @@ -111,6 +119,28 @@ public DBObject getMappedObject(DBObject query, MongoPersistentEntity entity) return newDbo; } + /** + * Returns the translated key assuming the given one is a propert (path) reference. + * + * @param key the source key + * @param entity the base entity + * @return the translated key + */ + private String determineKey(String key, MongoPersistentEntity entity) { + + if (entity == null) { + return key; + } + + try { + PropertyPath path = PropertyPath.from(key, entity.getTypeInformation()); + PersistentPropertyPath propertyPath = mappingContext.getPersistentPropertyPath(path); + return propertyPath.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE); + } catch (PropertyReferenceException e) { + return key; + } + } + /** * Retriggers mapping if the given source is a {@link DBObject} or simply invokes the * diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java index c1c2945968..ae7cf0ebd4 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java @@ -17,9 +17,9 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import static org.springframework.data.mongodb.core.DBObjectUtils.*; import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*; -import static org.springframework.data.mongodb.core.DBObjectUtils.*; import java.math.BigInteger; import java.util.ArrayList; @@ -35,6 +35,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.Person; +import org.springframework.data.mongodb.core.mapping.Field; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.query.BasicQuery; @@ -253,6 +254,39 @@ public void usesEntityMetadataInOr() { assertThat(criterias.get("foo"), is(nullValue())); } + @Test + public void translatesPropertyReferenceCorrectly() { + + Query query = query(where("field").is(new CustomizedField())); + DBObject result = mapper + .getMappedObject(query.getQueryObject(), context.getPersistentEntity(CustomizedField.class)); + + assertThat(result.containsField("foo"), is(true)); + assertThat(result.keySet().size(), is(1)); + } + + @Test + public void translatesNestedPropertyReferenceCorrectly() { + + Query query = query(where("field.field").is(new CustomizedField())); + DBObject result = mapper + .getMappedObject(query.getQueryObject(), context.getPersistentEntity(CustomizedField.class)); + + assertThat(result.containsField("foo.foo"), is(true)); + assertThat(result.keySet().size(), is(1)); + } + + @Test + public void returnsOriginalKeyIfNoPropertyReference() { + + Query query = query(where("bar").is(new CustomizedField())); + DBObject result = mapper + .getMappedObject(query.getQueryObject(), context.getPersistentEntity(CustomizedField.class)); + + assertThat(result.containsField("bar"), is(true)); + assertThat(result.keySet().size(), is(1)); + } + class IdWrapper { Object id; } @@ -283,4 +317,10 @@ class UserEntity { String id; List publishers = new ArrayList(); } + + class CustomizedField { + + @Field("foo") + CustomizedField field; + } } From 81d5bc8e535229f5fa15ec668d087be3cb8aa119 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 10 Aug 2012 19:58:36 +0200 Subject: [PATCH 27/49] DATAMONGO-472 - MongoQueryCreator now correctly translates Not keyword. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're now translating a negating property reference into a ne(…) call instead of a not().is(…). --- .../mongodb/repository/query/MongoQueryCreator.java | 2 +- .../AbstractPersonRepositoryIntegrationTests.java | 13 ++++++++++++- .../data/mongodb/repository/PersonRepository.java | 7 +++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java index 6bdb4ced40..00c5c91282 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java @@ -228,7 +228,7 @@ private Criteria from(Type type, MongoPersistentProperty property, Criteria crit case SIMPLE_PROPERTY: return criteria.is(parameters.nextConverted(property)); case NEGATING_SIMPLE_PROPERTY: - return criteria.not().is(parameters.nextConverted(property)); + return criteria.ne(parameters.nextConverted(property)); } throw new IllegalArgumentException("Unsupported keyword!"); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java index 7bc53f6853..28f6437892 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java @@ -495,4 +495,15 @@ public void bindsDateParameterForManuallyDefinedQueryCorrectly() { List result = repository.findByCreatedAtLessThanManually(boyd.createdAt); assertThat(result.isEmpty(), is(false)); } -} \ No newline at end of file + + /** + * @see DATAMONGO-472 + */ + @Test + public void findsPeopleUsingNotPredicate() { + + List result = repository.findByLastnameNot("Matthews"); + assertThat(result, not(hasItem(dave))); + assertThat(result, hasSize(5)); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java index 66667ca167..e2af969b77 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java @@ -183,4 +183,11 @@ public interface PersonRepository extends MongoRepository, Query */ List findByCreatedAtAfter(Date date); + /** + * @see DATAMONGO-472 + * @param lastname + * @return + */ + List findByLastnameNot(String lastname); + } From 538bccd8a7da92baa920d41546157ba11a751ceb Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 13 Aug 2012 11:37:59 +0200 Subject: [PATCH 28/49] DATAMONGO-476 - @EnableMongoRepositories is now inherited into sub-classes. --- .../data/mongodb/repository/config/EnableMongoRepositories.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/EnableMongoRepositories.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/EnableMongoRepositories.java index b2ba8f6486..dc0fbb91c0 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/EnableMongoRepositories.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/EnableMongoRepositories.java @@ -17,6 +17,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -38,6 +39,7 @@ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented +@Inherited @Import(MongoRepositoriesRegistrar.class) public @interface EnableMongoRepositories { From 3cf79519478d0079268765228887e3663e44cf3b Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 13 Aug 2012 14:27:19 +0200 Subject: [PATCH 29/49] DATACMNS-212 - Apply refactorings in Spring Data Commons. --- .../data/mongodb/core/index/MongoMappingEventPublisher.java | 2 +- .../mongodb/core/index/MongoPersistentEntityIndexCreator.java | 2 +- .../core/index/MongoPersistentEntityIndexCreatorUnitTests.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java index f1197deb1d..ddd1fcdbc9 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java @@ -18,7 +18,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; -import org.springframework.data.mapping.event.MappingContextEvent; +import org.springframework.data.mapping.context.MappingContextEvent; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java index 3356745e17..90e2a34f96 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java @@ -24,7 +24,7 @@ import org.springframework.context.ApplicationListener; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PropertyHandler; -import org.springframework.data.mapping.event.MappingContextEvent; +import org.springframework.data.mapping.context.MappingContextEvent; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java index 6e46b5d409..f47eddd445 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java @@ -25,7 +25,7 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.context.ApplicationContext; -import org.springframework.data.mapping.event.MappingContextEvent; +import org.springframework.data.mapping.context.MappingContextEvent; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.mapping.Field; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; From 5e5df90b25f39e8305214d2ff995e17b1ea5dd68 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 15 Aug 2012 15:16:44 +0200 Subject: [PATCH 30/49] DATAMONGO-505 - Fixed handling of parameter binding of associations and collection values. Instead of converting given association values as-is, ConvertingParameterAccessor now converts each collection value into a DBRef individually. --- .../query/ConvertingParameterAccessor.java | 57 ++++++++++++++- .../ConvertingParameterAccessorUnitTests.java | 72 ++++++++++++++++++- 2 files changed, 126 insertions(+), 3 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessor.java index 8d9c6b1b07..98a06f3294 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessor.java @@ -15,7 +15,11 @@ */ package org.springframework.data.mongodb.repository.query; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.Iterator; +import java.util.List; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -25,6 +29,9 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.repository.query.ParameterAccessor; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import com.mongodb.DBRef; /** * Custom {@link ParameterAccessor} that uses a {@link MongoWriter} to serialize parameters into Mongo format. @@ -158,7 +165,28 @@ public Object next() { * @see org.springframework.data.mongodb.repository.ConvertingParameterAccessor.PotentiallConvertingIterator#nextConverted() */ public Object nextConverted(MongoPersistentProperty property) { - return property.isAssociation() ? writer.toDBRef(next(), property) : getConvertedValue(next()); + + Object next = next(); + + if (next == null) { + return null; + } + + if (property.isAssociation()) { + if (next.getClass().isArray() || next instanceof Iterable) { + + List dbRefs = new ArrayList(); + for (Object element : asCollection(next)) { + dbRefs.add(writer.toDBRef(element, property)); + } + + return dbRefs; + } else { + return writer.toDBRef(next, property); + } + } + + return getConvertedValue(next); } /* @@ -170,6 +198,33 @@ public void remove() { } } + /** + * Returns the given object as {@link Collection}. Will do a copy of it if it implements {@link Iterable} or is an + * array. Will return an empty {@link Collection} in case {@literal null} is given. Will wrap all other types into a + * single-element collction + * + * @param source + * @return + */ + private static Collection asCollection(Object source) { + + if (source instanceof Iterable) { + + List result = new ArrayList(); + for (Object element : (Iterable) source) { + result.add(element); + } + + return result; + } + + if (source == null) { + return Collections.emptySet(); + } + + return source.getClass().isArray() ? CollectionUtils.arrayToList(source) : Collections.singleton(source); + } + /** * Custom {@link Iterator} that adds a method to access elements in a converted manner. * diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessorUnitTests.java index 6b70a23c6f..10f40c2d2f 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessorUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessorUnitTests.java @@ -15,11 +15,13 @@ */ package org.springframework.data.mongodb.repository.query; -import static org.mockito.Mockito.*; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; -import static org.hamcrest.CoreMatchers.*; +import static org.mockito.Mockito.*; import java.util.Arrays; +import java.util.Collection; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -27,7 +29,11 @@ import org.mockito.runners.MockitoJUnitRunner; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; +import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; +import org.springframework.data.mongodb.repository.query.ConvertingParameterAccessor.PotentiallyConvertingIterator; import com.mongodb.BasicDBList; @@ -76,4 +82,66 @@ public void convertsCollectionUponAccess() { assertThat(result, is((Object) reference)); } + + /** + * @see DATAMONGO-505 + */ + @Test + public void convertsAssociationsToDBRef() { + + Property property = new Property(); + property.id = 5L; + + Object result = setupAndConvert(property); + + assertThat(result, is(instanceOf(com.mongodb.DBRef.class))); + com.mongodb.DBRef dbRef = (com.mongodb.DBRef) result; + assertThat(dbRef.getRef(), is("property")); + assertThat(dbRef.getId(), is((Object) 5L)); + } + + /** + * @see DATAMONGO-505 + */ + @Test + public void convertsAssociationsToDBRefForCollections() { + + Property property = new Property(); + property.id = 5L; + + Object result = setupAndConvert(Arrays.asList(property)); + + assertThat(result, is(instanceOf(Collection.class))); + Collection collection = (Collection) result; + + assertThat(collection, hasSize(1)); + Object element = collection.iterator().next(); + + assertThat(element, is(instanceOf(com.mongodb.DBRef.class))); + com.mongodb.DBRef dbRef = (com.mongodb.DBRef) element; + assertThat(dbRef.getRef(), is("property")); + assertThat(dbRef.getId(), is((Object) 5L)); + } + + private Object setupAndConvert(Object... parameters) { + + MongoParameterAccessor delegate = new StubParameterAccessor(parameters); + PotentiallyConvertingIterator iterator = new ConvertingParameterAccessor(converter, delegate).iterator(); + + MongoPersistentEntity entity = context.getPersistentEntity(Entity.class); + MongoPersistentProperty property = entity.getPersistentProperty("property"); + + return iterator.nextConverted(property); + } + + static class Entity { + + @DBRef + Property property; + } + + static class Property { + + Long id; + } } From 9257f84505a009beb90a506256cc5d1f003fcbf5 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 15 Aug 2012 16:38:56 +0200 Subject: [PATCH 31/49] DATAMONGO-508 - Eagerly return DBRef creation if the given value already is a DBRef. --- .../core/convert/MappingMongoConverter.java | 4 ++++ .../convert/MappingMongoConverterUnitTests.java | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index 68bfe67f19..359c4cd5d2 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -671,6 +671,10 @@ protected DBRef createDBRef(Object target, org.springframework.data.mongodb.core Assert.notNull(target); + if (target instanceof DBRef) { + return (DBRef) target; + } + MongoPersistentEntity targetEntity = mappingContext.getPersistentEntity(target.getClass()); if (null == targetEntity) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java index 18d231a6ed..1c329014b5 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java @@ -1278,6 +1278,20 @@ private static void assertSyntheticFieldValueOf(Object target, Object expected) fail(String.format("Didn't find synthetic field on %s!", target)); } + /** + * @see DATAMGONGO-508 + */ + @Test + public void eagerlyReturnsDBRefObjectIfTargetAlreadyIsOne() { + + DB db = mock(DB.class); + DBRef dbRef = new DBRef(db, "collection", "id"); + + org.springframework.data.mongodb.core.mapping.DBRef annotation = mock(org.springframework.data.mongodb.core.mapping.DBRef.class); + + assertThat(converter.createDBRef(dbRef, annotation), is(dbRef)); + } + static class GenericType { T content; } From b440b4e19b7d1c88f622accf85ccf449c446090b Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 15 Aug 2012 18:16:03 +0200 Subject: [PATCH 32/49] =?UTF-8?q?DATAMONGO-509=20-=20SimpleMongoRepository?= =?UTF-8?q?.exists(=E2=80=A6)=20now=20avoids=20loading=20unnecessary=20dat?= =?UTF-8?q?a.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're explicitly ruling out the entities attributes via a field spec to avoid unnecessary object marshaling just to find out whether it exists or not. --- .../mongodb/repository/support/SimpleMongoRepository.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java index e1b81e13d3..1fcf386e98 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java @@ -131,8 +131,11 @@ private Criteria getVersionCriteria(Object version) { public boolean exists(ID id) { Assert.notNull(id, "The given id must not be null!"); - return mongoOperations.findOne(new Query(Criteria.where("_id").is(id)), Object.class, - entityInformation.getCollectionName()) != null; + + final Query idQuery = getIdQuery(id); + idQuery.fields(); + + return mongoOperations.findOne(idQuery, entityInformation.getJavaType(), entityInformation.getCollectionName()) != null; } /* From c63dc00b186200c34b0e18c789664ab4d133b7c0 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 15 Aug 2012 18:17:03 +0200 Subject: [PATCH 33/49] DATAMONGO-510 - Criteria now only uses BasicDBList internally. --- .../data/mongodb/core/query/Criteria.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java index 14e0c16554..4c8b8aea6a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java @@ -25,7 +25,6 @@ import java.util.regex.Pattern; import org.bson.BSON; -import org.bson.types.BasicBSONList; import org.springframework.data.mongodb.InvalidMongoDbApiUsageException; import org.springframework.data.mongodb.core.geo.Circle; import org.springframework.data.mongodb.core.geo.Point; @@ -33,6 +32,7 @@ import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; +import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; @@ -400,7 +400,7 @@ public Criteria elemMatch(Criteria c) { * @param criteria */ public Criteria orOperator(Criteria... criteria) { - BasicBSONList bsonList = createCriteriaList(criteria); + BasicDBList bsonList = createCriteriaList(criteria); criteriaChain.add(new Criteria("$or").is(bsonList)); return this; } @@ -411,7 +411,7 @@ public Criteria orOperator(Criteria... criteria) { * @param criteria */ public Criteria norOperator(Criteria... criteria) { - BasicBSONList bsonList = createCriteriaList(criteria); + BasicDBList bsonList = createCriteriaList(criteria); criteriaChain.add(new Criteria("$nor").is(bsonList)); return this; } @@ -422,7 +422,7 @@ public Criteria norOperator(Criteria... criteria) { * @param criteria */ public Criteria andOperator(Criteria... criteria) { - BasicBSONList bsonList = createCriteriaList(criteria); + BasicDBList bsonList = createCriteriaList(criteria); criteriaChain.add(new Criteria("$and").is(bsonList)); return this; } @@ -478,8 +478,8 @@ protected DBObject getSingleCriteriaObject() { return queryCriteria; } - private BasicBSONList createCriteriaList(Criteria[] criteria) { - BasicBSONList bsonList = new BasicBSONList(); + private BasicDBList createCriteriaList(Criteria[] criteria) { + BasicDBList bsonList = new BasicDBList(); for (Criteria c : criteria) { bsonList.add(c.getCriteriaObject()); } From 60769efd43ec4fb3f50ff3dd2eb32b9a9edafe91 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 15 Aug 2012 18:26:43 +0200 Subject: [PATCH 34/49] DATAMONGO-511 - QueryMapper now maps associations correctly. Complete overhaul of the QueryMapper to better handle complex scenarios like property paths and association references. --- .../mongodb/core/convert/QueryMapper.java | 196 ++++++++++++++---- .../core/convert/QueryMapperUnitTests.java | 53 ++++- 2 files changed, 208 insertions(+), 41 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java index 170b6b1043..10ac4303d6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java @@ -17,7 +17,6 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import org.bson.types.BasicBSONList; @@ -76,47 +75,121 @@ public QueryMapper(MongoConverter converter) { */ public DBObject getMappedObject(DBObject query, MongoPersistentEntity entity) { - DBObject newDbo = new BasicDBObject(); + if (isKeyWord(query)) { + return getMappedKeyword(query, entity); + } + + DBObject result = new BasicDBObject(); for (String key : query.keySet()) { + MongoPersistentProperty targetProperty = getTargetProperty(key, entity); String newKey = determineKey(key, entity); Object value = query.get(key); - if (isIdKey(key, entity)) { - if (value instanceof DBObject) { - DBObject valueDbo = (DBObject) value; - if (valueDbo.containsField("$in") || valueDbo.containsField("$nin")) { - String inKey = valueDbo.containsField("$in") ? "$in" : "$nin"; - List ids = new ArrayList(); - for (Object id : (Iterable) valueDbo.get(inKey)) { - ids.add(convertId(id)); - } - valueDbo.put(inKey, ids.toArray(new Object[ids.size()])); - } else if (valueDbo.containsField("$ne")) { - valueDbo.put("$ne", convertId(valueDbo.get("$ne"))); - } else { - value = getMappedObject((DBObject) value, null); + result.put(newKey, getMappedValue(value, targetProperty, newKey)); + } + + return result; + } + + /** + * Returns the given {@link DBObject} representing a keyword by mapping the keyword's value. + * + * @param query the {@link DBObject} representing a keyword (e.g. {@code $ne : … } ) + * @param entity + * @return + */ + private DBObject getMappedKeyword(DBObject query, MongoPersistentEntity entity) { + + String newKey = query.keySet().iterator().next(); + Object value = query.get(newKey); + + // $or/$nor + if (newKey.matches(N_OR_PATTERN)) { + + Iterable conditions = (Iterable) value; + BasicDBList newConditions = new BasicDBList(); + + for (Object condition : conditions) { + newConditions.add(getMappedObject((DBObject) condition, entity)); + } + + return new BasicDBObject(newKey, newConditions); + } + + return new BasicDBObject(newKey, convertSimpleOrDBObject(value, entity)); + } + + /** + * Returns the mapped value for the given source object assuming it's a value for the given + * {@link MongoPersistentProperty}. + * + * @param source the source object to be mapped + * @param property the property the value is a value for + * @param newKey the key the value will be bound to eventually + * @return + */ + private Object getMappedValue(Object source, MongoPersistentProperty property, String newKey) { + + if (property == null) { + return convertSimpleOrDBObject(source, null); + } + + if (property.isIdProperty() || "_id".equals(newKey)) { + + if (source instanceof DBObject) { + DBObject valueDbo = (DBObject) source; + if (valueDbo.containsField("$in") || valueDbo.containsField("$nin")) { + String inKey = valueDbo.containsField("$in") ? "$in" : "$nin"; + List ids = new ArrayList(); + for (Object id : (Iterable) valueDbo.get(inKey)) { + ids.add(convertId(id)); } + valueDbo.put(inKey, ids.toArray(new Object[ids.size()])); + } else if (valueDbo.containsField("$ne")) { + valueDbo.put("$ne", convertId(valueDbo.get("$ne"))); } else { - value = convertId(value); - } - newKey = "_id"; - } else if (key.matches(N_OR_PATTERN)) { - // $or/$nor - Iterable conditions = (Iterable) value; - BasicBSONList newConditions = new BasicBSONList(); - Iterator iter = conditions.iterator(); - while (iter.hasNext()) { - newConditions.add(getMappedObject((DBObject) iter.next(), entity)); + return getMappedObject((DBObject) source, null); } - value = newConditions; + + return valueDbo; + + } else { + return convertId(source); } + } + + if (property.isAssociation()) { + return isKeyWord(source) ? getMappedValue(getKeywordValue(source), property, newKey) : convertAssociation(source, + property); + } + + return convertSimpleOrDBObject(source, mappingContext.getPersistentEntity(property)); + } + + private MongoPersistentProperty getTargetProperty(String key, MongoPersistentEntity entity) { + + if (isIdKey(key, entity)) { + return entity.getIdProperty(); + } + + PersistentPropertyPath path = getPath(key, entity); + return path == null ? null : path.getLeafProperty(); + } - newDbo.put(newKey, convertSimpleOrDBObject(value, null)); + private PersistentPropertyPath getPath(String key, MongoPersistentEntity entity) { + + if (entity == null) { + return null; } - return newDbo; + try { + PropertyPath path = PropertyPath.from(key, entity.getTypeInformation()); + return mappingContext.getPersistentPropertyPath(path); + } catch (PropertyReferenceException e) { + return null; + } } /** @@ -128,17 +201,12 @@ public DBObject getMappedObject(DBObject query, MongoPersistentEntity entity) */ private String determineKey(String key, MongoPersistentEntity entity) { - if (entity == null) { - return key; + if (entity == null && DEFAULT_ID_NAMES.contains(key)) { + return "_id"; } - try { - PropertyPath path = PropertyPath.from(key, entity.getTypeInformation()); - PersistentPropertyPath propertyPath = mappingContext.getPersistentPropertyPath(path); - return propertyPath.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE); - } catch (PropertyReferenceException e) { - return key; - } + PersistentPropertyPath path = getPath(key, entity); + return path == null ? key : path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE); } /** @@ -161,6 +229,30 @@ private Object convertSimpleOrDBObject(Object source, MongoPersistentEntity e return converter.convertToMongoType(source); } + /** + * Converts the given source assuming it's actually an association to anoter object. + * + * @param source + * @param property + * @return + */ + private Object convertAssociation(Object source, MongoPersistentProperty property) { + + if (property == null || !property.isAssociation()) { + return source; + } + + if (source instanceof Iterable) { + BasicBSONList result = new BasicBSONList(); + for (Object element : (Iterable) source) { + result.add(converter.toDBRef(element, property)); + } + return result; + } + + return converter.toDBRef(source, property); + } + /** * Returns whether the given key will be considered an id key. * @@ -183,6 +275,34 @@ private boolean isIdKey(String key, MongoPersistentEntity entity) { return DEFAULT_ID_NAMES.contains(key); } + /** + * Returns whether the given value is representing a query keyword. + * + * @param value + * @return + */ + private static boolean isKeyWord(Object value) { + + if (!(value instanceof DBObject) || value instanceof BasicDBList) { + return false; + } + + DBObject dbObject = (DBObject) value; + return dbObject.keySet().size() == 1 && dbObject.keySet().iterator().next().startsWith("$"); + } + + /** + * Returns the value of the given source assuming it's a query keyword. + * + * @param source + * @return + */ + private static Object getKeywordValue(Object source) { + + DBObject dbObject = (DBObject) source; + return dbObject.get(dbObject.keySet().iterator().next()); + } + /** * Converts the given raw id value into either {@link ObjectId} or {@link String}. * diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java index ae7cf0ebd4..0a02a8db57 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java @@ -35,6 +35,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.Person; +import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.Field; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; @@ -57,6 +58,7 @@ public class QueryMapperUnitTests { QueryMapper mapper; MongoMappingContext context; + MappingMongoConverter converter; @Mock MongoDbFactory factory; @@ -66,7 +68,7 @@ public void setUp() { context = new MongoMappingContext(); - MappingMongoConverter converter = new MappingMongoConverter(factory, context); + converter = new MappingMongoConverter(factory, context); converter.afterPropertiesSet(); mapper = new QueryMapper(converter); @@ -203,7 +205,7 @@ public void transformsArraysCorrectly() { } @Test - public void doesNotHandleNestedFieldsWithDefaultIdNames() { + public void doesHandleNestedFieldsWithDefaultIdNames() { BasicDBObject dbObject = new BasicDBObject("id", new ObjectId().toString()); dbObject.put("nested", new BasicDBObject("id", new ObjectId().toString())); @@ -212,7 +214,7 @@ public void doesNotHandleNestedFieldsWithDefaultIdNames() { DBObject result = mapper.getMappedObject(dbObject, entity); assertThat(result.get("_id"), is(instanceOf(ObjectId.class))); - assertThat(((DBObject) result.get("nested")).get("id"), is(instanceOf(String.class))); + assertThat(((DBObject) result.get("nested")).get("_id"), is(instanceOf(ObjectId.class))); } /** @@ -287,6 +289,35 @@ public void returnsOriginalKeyIfNoPropertyReference() { assertThat(result.keySet().size(), is(1)); } + @Test + public void convertsAssociationCorrectly() { + + Reference reference = new Reference(); + reference.id = 5L; + + Query query = query(where("reference").is(reference)); + DBObject object = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WithDBRef.class)); + + Object referenceObject = object.get("reference"); + + assertThat(referenceObject, is(instanceOf(com.mongodb.DBRef.class))); + } + + @Test + public void convertsNestedAssociationCorrectly() { + + Reference reference = new Reference(); + reference.id = 5L; + + Query query = query(where("withDbRef.reference").is(reference)); + DBObject object = mapper.getMappedObject(query.getQueryObject(), + context.getPersistentEntity(WithDBRefWrapper.class)); + + Object referenceObject = object.get("withDbRef.reference"); + + assertThat(referenceObject, is(instanceOf(com.mongodb.DBRef.class))); + } + class IdWrapper { Object id; } @@ -323,4 +354,20 @@ class CustomizedField { @Field("foo") CustomizedField field; } + + class WithDBRef { + + @DBRef + Reference reference; + } + + class Reference { + + Long id; + } + + class WithDBRefWrapper { + + WithDBRef withDbRef; + } } From 5a9aad9f3800282b02ca8e45c7bb57478ee5ac99 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 15 Aug 2012 19:24:14 +0200 Subject: [PATCH 35/49] DATAMONGO-506 - Added test case to show BasicQuery is working for nested properties. --- .../data/mongodb/core/MongoTemplateTests.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java index eeaaa3460e..16feb45361 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java @@ -51,6 +51,7 @@ import org.springframework.data.mongodb.core.index.IndexField; import org.springframework.data.mongodb.core.index.IndexInfo; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.core.query.BasicQuery; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Order; import org.springframework.data.mongodb.core.query.Query; @@ -1232,6 +1233,35 @@ public void storesAndRemovesTypeWithComplexId() { template.remove(query(where("id").is(id)), TypeWithMyId.class); } + /** + * @see DATAMONGO-506 + */ + @Test + public void exceutesBasicQueryCorrectly() { + + Address address = new Address(); + address.state = "PA"; + address.city = "Philadelphia"; + + MyPerson person = new MyPerson(); + person.name = "Oleg"; + person.address = address; + + template.save(person); + + Query query = new BasicQuery("{'name' : 'Oleg'}"); + List result = template.find(query, MyPerson.class); + + assertThat(result, hasSize(1)); + assertThat(result.get(0), hasProperty("name", is("Oleg"))); + + query = new BasicQuery("{'address.state' : 'PA' }"); + result = template.find(query, MyPerson.class); + + assertThat(result, hasSize(1)); + assertThat(result.get(0), hasProperty("name", is("Oleg"))); + } + static class MyId { String first; @@ -1278,4 +1308,21 @@ public DateTime convert(Date source) { return source == null ? null : new DateTime(source.getTime()); } } + + public static class MyPerson { + + String id; + String name; + Address address; + + public String getName() { + return name; + } + } + + static class Address { + + String state; + String city; + } } From ff7e8977c9c3df85d344f471ad1be9834f5aa379 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 16 Aug 2012 14:10:02 +0200 Subject: [PATCH 36/49] DATACMNS-214 - Adapted API change in Spring Data Commons. Plus additional cleanups. --- .../data/mongodb/core/MongoTemplate.java | 2 -- .../MongoPersistentEntityIndexCreator.java | 4 ++-- .../core/mapping/MongoMappingContext.java | 10 ++++++++ .../data/mongodb/core/MongoTemplateTests.java | 23 ++++++++++--------- .../mongodb/core/TestMongoConfiguration.java | 2 +- .../mapping/MongoMappingContextUnitTests.java | 12 ++++++++++ 6 files changed, 37 insertions(+), 16 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index f2c182d60b..573ff556a5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -19,7 +19,6 @@ import static org.springframework.data.mongodb.core.query.Criteria.*; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -208,7 +207,6 @@ public MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverte ((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher); } } - } /** diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java index 90e2a34f96..84c342d1f0 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java @@ -56,8 +56,8 @@ public class MongoPersistentEntityIndexCreator implements * Creats a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and * {@link MongoDbFactory}. * - * @param mappingContext must not be {@@iteral null} - * @param mongoDbFactory must not be {@@iteral null} + * @param mappingContext must not be {@literal null} + * @param mongoDbFactory must not be {@literal null} */ public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, MongoDbFactory mongoDbFactory) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java index 89210b59ba..6f99ea0912 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java @@ -42,6 +42,15 @@ public MongoMappingContext() { setSimpleTypeHolder(MongoSimpleTypes.HOLDER); } + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.context.AbstractMappingContext#shouldCreatePersistentEntityFor(org.springframework.data.util.TypeInformation) + */ + @Override + protected boolean shouldCreatePersistentEntityFor(TypeInformation type) { + return !MongoSimpleTypes.HOLDER.isSimpleType(type.getType()); + } + /* * (non-Javadoc) * @see org.springframework.data.mapping.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.mapping.MutablePersistentEntity, org.springframework.data.mapping.SimpleTypeHolder) @@ -72,6 +81,7 @@ protected BasicMongoPersistentEntity createPersistentEntity(TypeInformati * (non-Javadoc) * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) */ + @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = applicationContext; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java index 16feb45361..59f6dfffcd 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java @@ -124,18 +124,19 @@ public void cleanUp() { } protected void cleanDb() { - template.dropCollection(template.getCollectionName(Person.class)); - template.dropCollection(template.getCollectionName(PersonWithAList.class)); - template.dropCollection(template.getCollectionName(PersonWith_idPropertyOfTypeObjectId.class)); - template.dropCollection(template.getCollectionName(PersonWith_idPropertyOfTypeString.class)); - template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfTypeObjectId.class)); - template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfTypeString.class)); - template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfTypeInteger.class)); - template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfPrimitiveInt.class)); - template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfTypeLong.class)); - template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfPrimitiveLong.class)); - template.dropCollection(template.getCollectionName(TestClass.class)); + template.dropCollection(Person.class); + template.dropCollection(PersonWithAList.class); + template.dropCollection(PersonWith_idPropertyOfTypeObjectId.class); + template.dropCollection(PersonWith_idPropertyOfTypeString.class); + template.dropCollection(PersonWithIdPropertyOfTypeObjectId.class); + template.dropCollection(PersonWithIdPropertyOfTypeString.class); + template.dropCollection(PersonWithIdPropertyOfTypeInteger.class); + template.dropCollection(PersonWithIdPropertyOfPrimitiveInt.class); + template.dropCollection(PersonWithIdPropertyOfTypeLong.class); + template.dropCollection(PersonWithIdPropertyOfPrimitiveLong.class); + template.dropCollection(TestClass.class); template.dropCollection(Sample.class); + template.dropCollection(MyPerson.class); } @Test diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/TestMongoConfiguration.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/TestMongoConfiguration.java index 2f393b1183..0701556fa8 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/TestMongoConfiguration.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/TestMongoConfiguration.java @@ -21,7 +21,7 @@ public String getDatabaseName() { @Override @Bean public Mongo mongo() throws Exception { - return new Mongo("localhost", 27017); + return new Mongo("127.0.0.1", 27017); } @Override diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/MongoMappingContextUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/MongoMappingContextUnitTests.java index ea53a2808e..16f3c7d5f2 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/MongoMappingContextUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/MongoMappingContextUnitTests.java @@ -16,6 +16,9 @@ package org.springframework.data.mongodb.core.mapping; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + import java.util.Collections; import java.util.Map; @@ -23,6 +26,8 @@ import org.springframework.data.annotation.Id; import org.springframework.data.mapping.model.MappingException; +import com.mongodb.DBRef; + /** * Unit tests for {@link MongoMappingContext}. * @@ -46,6 +51,13 @@ public void rejectsEntityWithMultipleIdProperties() { context.getPersistentEntity(ClassWithMultipleIdProperties.class); } + @Test + public void doesNotReturnPersistentEntityForMongoSimpleType() { + + MongoMappingContext context = new MongoMappingContext(); + assertThat(context.getPersistentEntity(DBRef.class), is(nullValue())); + } + class ClassWithMultipleIdProperties { @Id From f00962a268247aa3411427db9d72484d7d2a8ca5 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 20 Aug 2012 17:19:37 +0200 Subject: [PATCH 37/49] DATAMONGO-519 - Make Spring 3.1.2.RELEASE default Spring dependency version. We move away from Maven version ranges as they complicate the build and dependency resolution process. They make the build in-reproducible. Users stuck with a 3.0.x version of Spring will now have to manually declare Spring dependencies in their needed 3.0.x version. Not that at least Spring 3.0.7 is required currently. --- spring-data-mongodb-parent/pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index 7d08da5ee3..88131bbad2 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -16,8 +16,7 @@ 1.6.1 1.6.1 3.0.7.RELEASE - 4.0.0.RELEASE - [${org.springframework.version.30}, ${org.springframework.version.40}) + 3.1.2.RELEASE 1.4.0.BUILD-SNAPSHOT 1.6.11.RELEASE true From cbdedd18fbe69c9a3e5db9567681a4419df4e1a9 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 21 Aug 2012 12:08:44 +0200 Subject: [PATCH 38/49] DATAMONGO-517 - Fixed complex keyword handling. Introduced intermediate getMappedKeyword(Keyword keyword, MongoPersistentProperty property) to correctly return a DBObject for keyword plus converted value. A few refactorings and improvements in the implementation of QueryMapper (Keyword value object etc.). --- .../mongodb/core/convert/QueryMapper.java | 113 +++++++++++------- .../core/convert/QueryMapperUnitTests.java | 17 +++ 2 files changed, 86 insertions(+), 44 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java index 10ac4303d6..279b93bd36 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java @@ -1,11 +1,11 @@ /* - * Copyright (c) 2011 by the original author(s). + * Copyright 2011-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,7 +19,6 @@ import java.util.Arrays; import java.util.List; -import org.bson.types.BasicBSONList; import org.bson.types.ObjectId; import org.springframework.core.convert.ConversionException; import org.springframework.core.convert.ConversionService; @@ -35,11 +34,12 @@ import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; +import com.mongodb.DBRef; /** * A helper class to encapsulate any modifications of a Query object before it gets submitted to the database. * - * @author Jon Brisbin + * @author Jon Brisbin * @author Oliver Gierke */ public class QueryMapper { @@ -75,8 +75,8 @@ public QueryMapper(MongoConverter converter) { */ public DBObject getMappedObject(DBObject query, MongoPersistentEntity entity) { - if (isKeyWord(query)) { - return getMappedKeyword(query, entity); + if (Keyword.isKeyword(query)) { + return getMappedKeyword(new Keyword(query), entity); } DBObject result = new BasicDBObject(); @@ -100,25 +100,38 @@ public DBObject getMappedObject(DBObject query, MongoPersistentEntity entity) * @param entity * @return */ - private DBObject getMappedKeyword(DBObject query, MongoPersistentEntity entity) { - - String newKey = query.keySet().iterator().next(); - Object value = query.get(newKey); + private DBObject getMappedKeyword(Keyword query, MongoPersistentEntity entity) { // $or/$nor - if (newKey.matches(N_OR_PATTERN)) { + if (query.key.matches(N_OR_PATTERN)) { - Iterable conditions = (Iterable) value; + Iterable conditions = (Iterable) query.value; BasicDBList newConditions = new BasicDBList(); for (Object condition : conditions) { newConditions.add(getMappedObject((DBObject) condition, entity)); } - return new BasicDBObject(newKey, newConditions); + return new BasicDBObject(query.key, newConditions); } - return new BasicDBObject(newKey, convertSimpleOrDBObject(value, entity)); + return new BasicDBObject(query.key, convertSimpleOrDBObject(query.value, entity)); + } + + /** + * Returns the mapped keyword considered defining a criteria for the given property. + * + * @param keyword + * @param property + * @return + */ + public DBObject getMappedKeyword(Keyword keyword, MongoPersistentProperty property) { + + if (property.isAssociation()) { + convertAssociation(keyword.value, property); + } + + return new BasicDBObject(keyword.key, getMappedValue(keyword.value, property, keyword.key)); } /** @@ -161,7 +174,7 @@ private Object getMappedValue(Object source, MongoPersistentProperty property, S } if (property.isAssociation()) { - return isKeyWord(source) ? getMappedValue(getKeywordValue(source), property, newKey) : convertAssociation(source, + return Keyword.isKeyword(source) ? getMappedKeyword(new Keyword(source), property) : convertAssociation(source, property); } @@ -243,14 +256,14 @@ private Object convertAssociation(Object source, MongoPersistentProperty propert } if (source instanceof Iterable) { - BasicBSONList result = new BasicBSONList(); + BasicDBList result = new BasicDBList(); for (Object element : (Iterable) source) { - result.add(converter.toDBRef(element, property)); + result.add(element instanceof DBRef ? element : converter.toDBRef(element, property)); } return result; } - return converter.toDBRef(source, property); + return source instanceof DBRef ? source : converter.toDBRef(source, property); } /** @@ -276,47 +289,59 @@ private boolean isIdKey(String key, MongoPersistentEntity entity) { } /** - * Returns whether the given value is representing a query keyword. + * Converts the given raw id value into either {@link ObjectId} or {@link String}. * - * @param value + * @param id * @return */ - private static boolean isKeyWord(Object value) { + public Object convertId(Object id) { - if (!(value instanceof DBObject) || value instanceof BasicDBList) { - return false; + try { + return conversionService.convert(id, ObjectId.class); + } catch (ConversionException e) { + // Ignore } - DBObject dbObject = (DBObject) value; - return dbObject.keySet().size() == 1 && dbObject.keySet().iterator().next().startsWith("$"); + return converter.convertToMongoType(id); } /** - * Returns the value of the given source assuming it's a query keyword. + * Value object to capture a query keyword representation. * - * @param source - * @return + * @author Oliver Gierke */ - private static Object getKeywordValue(Object source) { + private static class Keyword { - DBObject dbObject = (DBObject) source; - return dbObject.get(dbObject.keySet().iterator().next()); - } + String key; + Object value; - /** - * Converts the given raw id value into either {@link ObjectId} or {@link String}. - * - * @param id - * @return - */ - public Object convertId(Object id) { + Keyword(Object source) { - try { - return conversionService.convert(id, ObjectId.class); - } catch (ConversionException e) { - // Ignore + Assert.isInstanceOf(DBObject.class, source); + + DBObject value = (DBObject) source; + + Assert.isTrue(value.keySet().size() == 1, "Keyword must have a single key only!"); + + this.key = value.keySet().iterator().next(); + this.value = value.get(key); } - return converter.convertToMongoType(id); + /** + * Returns whether the given value actually represents a keyword. If this returns {@literal true} it's safe to call + * the constructor. + * + * @param value + * @return + */ + static boolean isKeyword(Object value) { + + if (!(value instanceof DBObject)) { + return false; + } + + DBObject dbObject = (DBObject) value; + return dbObject.keySet().size() == 1 && dbObject.keySet().iterator().next().startsWith("$"); + } } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java index 0a02a8db57..7478c276db 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java @@ -34,6 +34,7 @@ import org.mockito.runners.MockitoJUnitRunner; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.DBObjectUtils; import org.springframework.data.mongodb.core.Person; import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.Field; @@ -318,6 +319,22 @@ public void convertsNestedAssociationCorrectly() { assertThat(referenceObject, is(instanceOf(com.mongodb.DBRef.class))); } + @Test + public void convertsInKeywordCorrectly() { + + Reference first = new Reference(); + first.id = 5L; + + Reference second = new Reference(); + second.id = 6L; + + Query query = query(where("reference").in(first, second)); + DBObject result = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WithDBRef.class)); + + DBObject reference = DBObjectUtils.getAsDBObject(result, "reference"); + assertThat(reference.containsField("$in"), is(true)); + } + class IdWrapper { Object id; } From b412cf4b7ecf649606eef4a21ee3061bf73b587c Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 23 Aug 2012 20:12:41 +0200 Subject: [PATCH 39/49] DATAMONGO-513 - Update to Spring Data Commons 1.4.0.RC1. --- spring-data-mongodb-parent/pom.xml | 6 +++--- src/docbkx/index.xml | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index 88131bbad2..2c19c52e63 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -17,7 +17,7 @@ 1.6.1 3.0.7.RELEASE 3.1.2.RELEASE - 1.4.0.BUILD-SNAPSHOT + 1.4.0.RC1 1.6.11.RELEASE true @@ -247,8 +247,8 @@ - spring-libs-snapshot - http://repo.springsource.org/libs-snapshot + spring-libs-milestone + http://repo.springsource.org/libs-milestone diff --git a/src/docbkx/index.xml b/src/docbkx/index.xml index 327aa54f7e..03d6d63e4e 100644 --- a/src/docbkx/index.xml +++ b/src/docbkx/index.xml @@ -52,7 +52,7 @@ - + @@ -72,9 +72,12 @@ Appendix - + + + + From 649572af6191938d3a63cbeae5ebdd3b10b385d1 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 24 Aug 2012 11:16:54 +0200 Subject: [PATCH 40/49] DATAMONGO-513 - Prepare changelog for 1.1.0.RC1. --- src/main/resources/changelog.txt | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/main/resources/changelog.txt b/src/main/resources/changelog.txt index dbea2c5a03..848224f052 100644 --- a/src/main/resources/changelog.txt +++ b/src/main/resources/changelog.txt @@ -1,6 +1,44 @@ Spring Data MongoDB Changelog ============================================= +Changes in version 1.1.0.RC1 (2012-24-08) +----------------------------------------- +** Bug + * [DATAMONGO-493] - Criteria.ne() method converts all value into ObjectId + * [DATAMONGO-494] - $or/$nor expressions do not consider entity class mapping + * [DATAMONGO-495] - JSON can't serialize Enum when printing Query in DEBUG message + * [DATAMONGO-497] - Reading an empty List throws a MappingInstantiationException because it returns an HashSet instead of returning an ArrayList + * [DATAMONGO-505] - Conversion of associations doesn't work for collection values + * [DATAMONGO-508] - DBRef can accidentally get added as PersistentProperty + * [DATAMONGO-517] - QueryMapping incorrectly translates complex keywords + +** Improvement + * [DATAMONGO-496] - AbstractMongoConfiguration.getMappingBasePackage() could default to config class' package + * [DATAMONGO-499] - Namespace XSDs of current release version should refer to repositories XSD in version 1.0 + * [DATAMONGO-500] - Index creation reacts on events not intended for it + * [DATAMONGO-502] - QueryMapper should transparently translate property names to field names + * [DATAMONGO-509] - SimpleMongoRepository.exists(…) can be improved. + * [DATAMONGO-510] - Criteria should only use BasicDBList internally + * [DATAMONGO-511] - QueryMapper should correctly transform associations + * [DATAMONGO-516] - Make Spring 3.1.2.RELEASE default Spring dependency version + +** Task + * [DATAMONGO-513] - Release 1.1 RC1 + + +Changes in version 1.0.4.RELEASE MongoDB (2012-08-24) +----------------------------------------------------- +** Bug + * [DATAMONGO-493] - Criteria.ne() method converts all value into ObjectId + * [DATAMONGO-494] - $or/$nor expressions do not consider entity class mapping + * [DATAMONGO-495] - JSON can't serialize Enum when printing Query in DEBUG message + +** Improvement + * [DATAMONGO-499] - Namespace XSDs of current release version should refer to repositories XSD in version 1.0 + +** Task + * [DATAMONGO-514] - Release 1.0.4. + Changes in version 1.1.0.M2 (2012-24-07) ---------------------------------------- ** Bug From 0b91218c6d6c97b471edeff02ad07ce5ea227fce Mon Sep 17 00:00:00 2001 From: Spring Buildmaster Date: Fri, 24 Aug 2012 02:24:06 -0700 Subject: [PATCH 41/49] DATAMONGO-513 - Release 1.1.0.RC1. --- pom.xml | 2 +- spring-data-mongodb-cross-store/pom.xml | 4 ++-- spring-data-mongodb-log4j/pom.xml | 2 +- spring-data-mongodb-parent/pom.xml | 2 +- spring-data-mongodb/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 87d1272bb5..c8789ed420 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-dist Spring Data MongoDB Distribution - 1.1.0.BUILD-SNAPSHOT + 1.1.0.RC1 pom spring-data-mongodb diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index 7c6e536dc2..5b205dfb08 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.BUILD-SNAPSHOT + 1.1.0.RC1 ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-cross-store @@ -42,7 +42,7 @@ org.springframework.data spring-data-mongodb - 1.1.0.BUILD-SNAPSHOT + 1.1.0.RC1 diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index 52a36bc15b..f7552351ce 100644 --- a/spring-data-mongodb-log4j/pom.xml +++ b/spring-data-mongodb-log4j/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.BUILD-SNAPSHOT + 1.1.0.RC1 ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-log4j diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index 2c19c52e63..d72529a954 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -5,7 +5,7 @@ spring-data-mongodb-parent Spring Data MongoDB Parent http://www.springsource.org/spring-data/mongodb - 1.1.0.BUILD-SNAPSHOT + 1.1.0.RC1 pom UTF-8 diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index d136285eff..4d0b90cde1 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.BUILD-SNAPSHOT + 1.1.0.RC1 ../spring-data-mongodb-parent/pom.xml spring-data-mongodb From 1c3b5c2dd6b5f8ef031c82238434649802669328 Mon Sep 17 00:00:00 2001 From: Spring Buildmaster Date: Fri, 24 Aug 2012 02:24:09 -0700 Subject: [PATCH 42/49] DATAMONGO-513 - Prepare next development iteration. --- pom.xml | 2 +- spring-data-mongodb-cross-store/pom.xml | 4 ++-- spring-data-mongodb-log4j/pom.xml | 2 +- spring-data-mongodb-parent/pom.xml | 2 +- spring-data-mongodb/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index c8789ed420..87d1272bb5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-dist Spring Data MongoDB Distribution - 1.1.0.RC1 + 1.1.0.BUILD-SNAPSHOT pom spring-data-mongodb diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index 5b205dfb08..7c6e536dc2 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.RC1 + 1.1.0.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-cross-store @@ -42,7 +42,7 @@ org.springframework.data spring-data-mongodb - 1.1.0.RC1 + 1.1.0.BUILD-SNAPSHOT diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index f7552351ce..52a36bc15b 100644 --- a/spring-data-mongodb-log4j/pom.xml +++ b/spring-data-mongodb-log4j/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.RC1 + 1.1.0.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-log4j diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index d72529a954..2c19c52e63 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -5,7 +5,7 @@ spring-data-mongodb-parent Spring Data MongoDB Parent http://www.springsource.org/spring-data/mongodb - 1.1.0.RC1 + 1.1.0.BUILD-SNAPSHOT pom UTF-8 diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 4d0b90cde1..d136285eff 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -4,7 +4,7 @@ org.springframework.data spring-data-mongodb-parent - 1.1.0.RC1 + 1.1.0.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb From 95e44e2bc9fdc60352fda8f6089c509fadecfae6 Mon Sep 17 00:00:00 2001 From: mpollack Date: Sat, 25 Aug 2012 16:17:43 -0400 Subject: [PATCH 43/49] DATAMONGO-526 - Polished README.md. Update README to remove references to old API, Docs links as well as CouchDB. Remove reference to Spring Data Document, copy initial paragraph introducing the project from http://www.springsource.org/spring-data/mongodb --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 76fb0b09d4..479696797b 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,22 @@ -Spring Data - Document +Spring Data MongoDB ====================== The primary goal of the [Spring Data](http://www.springsource.org/spring-data) project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services. -As the name implies, the **Document** modules provides integration with document databases such as [MongoDB](http://www.mongodb.org/) and [CouchDB](http://couchdb.apache.org/). + +The Spring Data MongoDB aims to provide a familiar and consistent Spring-based programming model for for new datastores while retaining store-specific features and capabilities. The Spring Data MongoDB project provides integration with the MongoDB document database. Key functional areas of Spring Data MongoDB are a POJO centric model for interacting with a MongoDB DBCollection and easily writing a Repository style data access layer Getting Help ------------ -At this point your best bet is to look at the Look at the [JavaDocs](http://static.springsource.org/spring-data/data-document/docs/1.0.0.BUILD-SNAPSHOT/spring-data-mongodb/apidocs/) for MongoDB integration and corresponding and source code. For more detailed questions, use the [forum](http://forum.springsource.org/forumdisplay.php?f=80). If you are new to Spring as well as to Spring Data, look for information about [Spring projects](http://www.springsource.org/projects). +For a comprehensive treatmet of all the Spring Data MongoDB features, please refer to the The [User Guide](http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/) + +The [JavaDocs](http://static.springsource.org/spring-data/data-mongodb/docs/current/api/) have extensive comments in them as well. + +The home page of [Spring Data MongoDB](http://www.springsource.org/spring-data/mongodb) contains links to articles and other resources. -The [User Guide](http://static.springsource.org/spring-data/data-document/docs/1.0.0.BUILD-SNAPSHOT/reference/html/) (A work in progress). +For more detailed questions, use the [forum](http://forum.springsource.org/forumdisplay.php?f=80). +If you are new to Spring as well as to Spring Data, look for information about [Spring projects](http://www.springsource.org/projects). Quick Start @@ -137,11 +143,6 @@ This will register an object in the container named PersonRepository. You can u } -## CouchDB - -TBD - - Contributing to Spring Data --------------------------- From a5d7ce5fb9e6b3930a66cbac0e4e78e74ff93f30 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 30 Aug 2012 11:56:25 +0200 Subject: [PATCH 44/49] DATAMONGO-513 - Update to Spring Data Commons 1.4.0.BUILD-SNAPSHOT. --- spring-data-mongodb-parent/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index 2c19c52e63..88131bbad2 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -17,7 +17,7 @@ 1.6.1 3.0.7.RELEASE 3.1.2.RELEASE - 1.4.0.RC1 + 1.4.0.BUILD-SNAPSHOT 1.6.11.RELEASE true @@ -247,8 +247,8 @@ - spring-libs-milestone - http://repo.springsource.org/libs-milestone + spring-libs-snapshot + http://repo.springsource.org/libs-snapshot From 9bb331160bb25794cb0c10f2c21cd95d4b429262 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 3 Sep 2012 13:44:56 +0200 Subject: [PATCH 45/49] DATAMONGO-523 - Added test case to verify type alias detection. --- .../MappingMongoConverterUnitTests.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java index 1c329014b5..ef8eb2077b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java @@ -49,6 +49,7 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.annotation.TypeAlias; import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mapping.model.MappingInstantiationException; @@ -1292,6 +1293,23 @@ public void eagerlyReturnsDBRefObjectIfTargetAlreadyIsOne() { assertThat(converter.createDBRef(dbRef, annotation), is(dbRef)); } + /** + * @see DATAMONGO-523 + */ + @Test + public void considersTypeAliasAnnotation() { + + Aliased aliased = new Aliased(); + aliased.name = "foo"; + + DBObject result = new BasicDBObject(); + converter.write(aliased, result); + + Object type = result.get("_class"); + assertThat(type, is(notNullValue())); + assertThat(type.toString(), is("_")); + } + static class GenericType { T content; } @@ -1475,6 +1493,11 @@ public TypWithCollectionConstructor(List attributes) { } } + @TypeAlias("_") + static class Aliased { + String name; + } + private class LocalDateToDateConverter implements Converter { public Date convert(LocalDate source) { From 3e4016c2c3eaac46f67484c10d86008d3443e5c1 Mon Sep 17 00:00:00 2001 From: noter Date: Tue, 4 Sep 2012 13:38:25 +0200 Subject: [PATCH 46/49] DATAMONGO-279 --- spring-data-mongodb/pom.xml | 2 +- .../data/mongodb/core/MongoTemplate.java | 41 ++++++++--- .../support/SimpleMongoRepository.java | 16 ----- .../data/mongodb/core/MongoTemplateTests.java | 35 ++++++++++ ...ersonWithVersionPropertyOfTypeInteger.java | 68 +++++++++++++++++++ 5 files changed, 136 insertions(+), 26 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/PersonWithVersionPropertyOfTypeInteger.java diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index d136285eff..e5fd0599ff 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -181,7 +181,7 @@ com.mysema.maven maven-apt-plugin - 1.0.2 + 1.0.4 generate-test-sources diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index 573ff556a5..84eec1615b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -44,6 +44,7 @@ import org.springframework.dao.DataAccessException; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.data.authentication.UserCredentials; import org.springframework.data.convert.EntityReader; import org.springframework.data.mapping.PersistentEntity; @@ -703,7 +704,26 @@ public void save(Object objectToSave) { } public void save(Object objectToSave, String collectionName) { - doSave(collectionName, objectToSave, this.mongoConverter); + MongoPersistentEntity mongoPersistentEntity = getPersistentEntity(objectToSave.getClass()); + if(mongoPersistentEntity.hasVersion()){ + BeanWrapper, Object> beanWrapper = BeanWrapper.create(objectToSave, null); + Object id = beanWrapper.getProperty(mongoPersistentEntity.getIdProperty()); + if(id == null){ + beanWrapper.setProperty(mongoPersistentEntity.getVersionProperty(), 0); + doSave(collectionName, objectToSave, this.mongoConverter); + } else { + updateFirst( getUpdateVersionQuery(id, + beanWrapper.getProperty(mongoPersistentEntity.getVersionProperty()),mongoPersistentEntity), + objectToSave, objectToSave.getClass()); + } + } else { + doSave(collectionName, objectToSave, this.mongoConverter); + } + } + + private Query getUpdateVersionQuery(Object id, Object version,MongoPersistentEntity mongoPersistentEntity) { + return new Query( Criteria.where(mongoPersistentEntity.getIdProperty().getName()).is(id) + .and(mongoPersistentEntity.getVersionProperty().getName()).is(version)); } protected void doSave(String collectionName, T objectToSave, MongoWriter writer) { @@ -823,7 +843,7 @@ public WriteResult updateFirst(final Query query, final Object object, BasicDBObject dbObject = new BasicDBObject(); this.mongoConverter.write(object, dbObject); - return doUpdate(determineEntityCollectionName(entityClass), query, + return doUpdate(determineCollectionName(entityClass), query, Update.fromDBObject(dbObject, ID, getPersistentEntity(entityClass).getVersionProperty() .getName()), entityClass, false, false); @@ -847,12 +867,13 @@ public WriteResult doInCollection(DBCollection collection) throws MongoException DBObject queryObj = query == null ? new BasicDBObject() : mapper.getMappedObject(query.getQueryObject(), entity); - DBObject updateObj = update == null ? new BasicDBObject() : mapper.getMappedObject(update.getUpdateObject(), - entity); - - if(null != update && entity.hasVersion()) { + + if(null != update && null != entity && entity.hasVersion()) { update.inc(entity.getVersionProperty().getName(), 1); } + + DBObject updateObj = update == null ? new BasicDBObject() : mapper.getMappedObject(update.getUpdateObject(), + entity); if (LOGGER.isDebugEnabled()) { LOGGER.debug("calling update using query: " + queryObj + " and update: " + updateObj + " in collection: " @@ -868,6 +889,11 @@ public WriteResult doInCollection(DBCollection collection) throws MongoException } else { wr = collection.update(queryObj, updateObj, upsert, multi, writeConcernToUse); } + if(null != entity && entity.hasVersion() && !multi){ + if(wr.getN() == 0){ + throw new OptimisticLockingFailureException("Optimistic lock exception on saveing entity: "+updateObj.toMap().toString()); + } + } handleAnyWriteResultErrors(wr, queryObj, "update with '" + updateObj + "'"); return wr; } @@ -1483,9 +1509,6 @@ private MongoPersistentProperty getIdPropertyFor(Class type) { private String determineEntityCollectionName(T obj) { if (null != obj) { - if(obj instanceof Class) { - return determineEntityCollectionName((Class)obj); - } return determineCollectionName(obj.getClass()); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java index 1fcf386e98..b171e6b661 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java @@ -69,13 +69,6 @@ public S save(S entity) { Assert.notNull(entity, "Entity must not be null!"); - - if (entityInformation.isNew(entity) || !entityInformation.hasVersion(entity)) { - mongoOperations.save(entity, entityInformation.getCollectionName()); - } else { - mongoOperations.updateFirst( getUpdateQuery(entityInformation.getId(entity), - entityInformation.getVersion(entity)), entity, entity.getClass()); - } mongoOperations.save(entity, entityInformation.getCollectionName()); return entity; } @@ -114,15 +107,6 @@ private Query getIdQuery(Object id) { private Criteria getIdCriteria(Object id) { return where(entityInformation.getIdAttribute()).is(id); } - - private Query getUpdateQuery(Object id, Object version) { - return new Query(getIdCriteria(id).andOperator( - getVersionCriteria(version))); - } - - private Criteria getVersionCriteria(Object version) { - return where(entityInformation.getVersionAttribute()).is(version); - } /* * (non-Javadoc) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java index 59f6dfffcd..b2e5ee5798 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java @@ -40,6 +40,7 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.mongodb.InvalidMongoDbApiUsageException; @@ -134,6 +135,7 @@ protected void cleanDb() { template.dropCollection(PersonWithIdPropertyOfPrimitiveInt.class); template.dropCollection(PersonWithIdPropertyOfTypeLong.class); template.dropCollection(PersonWithIdPropertyOfPrimitiveLong.class); + template.dropCollection(PersonWithVersionPropertyOfTypeInteger.class); template.dropCollection(TestClass.class); template.dropCollection(Sample.class); template.dropCollection(MyPerson.class); @@ -1262,6 +1264,39 @@ public void exceutesBasicQueryCorrectly() { assertThat(result, hasSize(1)); assertThat(result.get(0), hasProperty("name", is("Oleg"))); } + + @Test(expected = OptimisticLockingFailureException.class) + public void optimisticLockingHandling() { + + //Init version + PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger(); + person.setAge(29); + person.setFirstName("Patryk"); + template.save(person); + + List result = template.findAll(PersonWithVersionPropertyOfTypeInteger.class); + + assertThat(result, hasSize(1)); + assertThat(result.get(0), hasProperty("version", is(0))); + + //Version change + person = result.get(0); + person.setFirstName("Patryk2"); + + template.save(person); + + result = mappingTemplate.findAll(PersonWithVersionPropertyOfTypeInteger.class); + + assertThat(result, hasSize(1)); + assertThat(result.get(0), hasProperty("version", is(1))); + + //Optimistic lock exception + person.setVersion(0); + person.setFirstName("Patryk3"); + + template.save(person); + + } static class MyId { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/PersonWithVersionPropertyOfTypeInteger.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/PersonWithVersionPropertyOfTypeInteger.java new file mode 100644 index 0000000000..64bbcf6a79 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/PersonWithVersionPropertyOfTypeInteger.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.core; + +import org.springframework.data.mongodb.core.mapping.Version; + +public class PersonWithVersionPropertyOfTypeInteger { + + private String id; + + private String firstName; + + private int age; + + @Version + private Integer version; + + public void setId(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + @Override + public String toString() { + return "PersonWithVersionPropertyOfTypeInteger [id=" + id + ", firstName=" + firstName + ", age=" + age + ", version="+ version + "]"; + } + +} From 58854afb592653595239e1224fd4d5ccbada0d7c Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 3 Sep 2012 16:46:53 +0200 Subject: [PATCH 47/49] DATAMONGO-521 - Added test case to show that repository AND query works. --- ...bstractPersonRepositoryIntegrationTests.java | 17 +++++++++++++++++ .../mongodb/repository/PersonRepository.java | 2 ++ .../PersonRepositoryIntegrationTests.java | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java index 28f6437892..99cd7bc6de 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java @@ -506,4 +506,21 @@ public void findsPeopleUsingNotPredicate() { assertThat(result, not(hasItem(dave))); assertThat(result, hasSize(5)); } + + /** + * @see DATAMONGO-521 + */ + @Test + public void executesAndQueryCorrectly() { + + List result = repository.findByFirstnameAndLastname("Dave", "Matthews"); + + assertThat(result, hasSize(1)); + assertThat(result, hasItem(dave)); + + result = repository.findByFirstnameAndLastname("Oliver August", "Matthews"); + + assertThat(result, hasSize(1)); + assertThat(result, hasItem(oliver)); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java index e2af969b77..bf35a99b6b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java @@ -106,6 +106,8 @@ public interface PersonRepository extends MongoRepository, Query */ List findByFirstnameNotIn(Collection firstnames); + List findByFirstnameAndLastname(String firstname, String lastname); + /** * Returns all {@link Person}s with an age between the two given values. * diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests.java index 45ebae97e7..51196811ec 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2010-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 1cf70f679087b6fcdce3d7947fc42db9e6bf85c5 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 3 Sep 2012 18:47:25 +0200 Subject: [PATCH 48/49] =?UTF-8?q?DATAMONGO-527=20-=20Fixed=20Criteria.equa?= =?UTF-8?q?ls(=E2=80=A6).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/mongodb/core/query/Criteria.java | 25 ++++++++++++++++--- .../mongodb/core/query/CriteriaTests.java | 14 +++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java index 4c8b8aea6a..2874fe2a1c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java @@ -514,9 +514,28 @@ public boolean equals(Object obj) { Criteria that = (Criteria) obj; - boolean keyEqual = this.key == null ? that.key == null : this.key.equals(that.key); - boolean criteriaEqual = this.criteria.equals(that.criteria); - boolean valueEqual = isEqual(this.isValue, that.isValue); + if (this.criteriaChain.size() != that.criteriaChain.size()) { + return false; + } + + for (int i = 0; i < this.criteriaChain.size(); i++) { + + Criteria left = this.criteriaChain.get(i); + Criteria right = that.criteriaChain.get(i); + + if (!simpleCriteriaEquals(left, right)) { + return false; + } + } + + return true; + } + + private boolean simpleCriteriaEquals(Criteria left, Criteria right) { + + boolean keyEqual = left.key == null ? right.key == null : left.key.equals(right.key); + boolean criteriaEqual = left.criteria.equals(right.criteria); + boolean valueEqual = isEqual(left.isValue, right.isValue); return keyEqual && criteriaEqual && valueEqual; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/CriteriaTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/CriteriaTests.java index 2b141a5e5f..fac13a5d6b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/CriteriaTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/CriteriaTests.java @@ -15,11 +15,11 @@ */ package org.springframework.data.mongodb.core.query; -import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + import org.junit.Test; import org.springframework.data.mongodb.InvalidMongoDbApiUsageException; -import org.springframework.data.mongodb.core.query.Criteria; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; @@ -58,4 +58,14 @@ public void testCriteriaWithMultipleConditionsForSameKey() { Criteria c = new Criteria("name").gte("M").and("name").ne("A"); c.getCriteriaObject(); } + + @Test + public void equalIfCriteriaMatches() { + + Criteria left = new Criteria("name").is("Foo").and("lastname").is("Bar"); + Criteria right = new Criteria("name").is("Bar").and("lastname").is("Bar"); + + assertThat(left, is(not(right))); + assertThat(right, is(not(left))); + } } From c5f5f64b6869206068da41328957400e2f1ce404 Mon Sep 17 00:00:00 2001 From: noter Date: Tue, 4 Sep 2012 16:01:13 +0200 Subject: [PATCH 49/49] DATAMONGO-279 - fix broken repository tests --- .../data/mongodb/repository/Person.java | 12 +----------- .../repository/SimpleMongoRepositoryVersionTest.java | 11 ----------- 2 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/SimpleMongoRepositoryVersionTest.java diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java index ea3d0bb67b..34d6f2366f 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java @@ -23,7 +23,6 @@ import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.Document; -import org.springframework.data.mongodb.core.mapping.Version; /** * Sample domain class. @@ -55,10 +54,8 @@ public enum Sex { @DBRef User creator; - @Version - private Long version= 1L; - public Person() { + this(null, null); } @@ -193,13 +190,6 @@ public void setShippingAddresses(Set
    addresses) { public String getName() { return String.format("%s %s", firstname, lastname); } - - /** - * @return the version - */ - public Long getVersion() { - return version; - } /* * (non-Javadoc) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/SimpleMongoRepositoryVersionTest.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/SimpleMongoRepositoryVersionTest.java deleted file mode 100644 index cd87d61bbe..0000000000 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/SimpleMongoRepositoryVersionTest.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.springframework.data.mongodb.repository; - -import org.junit.runner.RunWith; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -public class SimpleMongoRepositoryVersionTest { - -}