From ccf006e41b4e8d18695f39ef77ddf92f734d030d Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Wed, 9 May 2012 16:59:42 +0200 Subject: [PATCH 01/49] DATAMONGO-446 - Fixed bug in paging query methods returning Lists Using List as return type for paginating methods didn't work for query methods currently. Fixed by inspecting the Pageable parameter potentially handed into them and restricting the result set accordingly. --- .../repository/query/AbstractMongoQuery.java | 15 +++++++++++++-- .../AbstractPersonRepositoryIntegrationTests.java | 10 ++++++++++ .../data/mongodb/repository/PersonRepository.java | 4 +++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java index ce7406cc28..a51f9a0c14 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 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. @@ -85,7 +85,7 @@ public Object execute(Object[] parameters) { } else if (method.isGeoNearQuery()) { return new GeoNearExecution(accessor).execute(query); } else if (method.isCollectionQuery()) { - return new CollectionExecution().execute(query); + return new CollectionExecution(accessor.getPageable()).execute(query); } else if (method.isPageQuery()) { return new PagedExecution(accessor.getPageable()).execute(query); } else { @@ -133,12 +133,23 @@ protected List readCollection(Query query) { */ class CollectionExecution extends Execution { + private final Pageable pageable; + + CollectionExecution(Pageable pageable) { + this.pageable = pageable; + } + /* * (non-Javadoc) * @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query) */ @Override public Object execute(Query query) { + + if (pageable != null) { + query = applyPagination(query, pageable); + } + return readCollection(query); } } 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 aba8c4145a..97a46f6e6f 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 @@ -310,6 +310,16 @@ public void findsPeopleBySexCorrectly() { assertThat(females.get(0), is(alicia)); } + /** + * @see DATAMONGO-446 + */ + @Test + public void findsPeopleBySexPaginated() { + + List males = repository.findBySex(Sex.MALE, new PageRequest(0, 2)); + assertThat(males.size(), is(2)); + } + @Test public void findsPeopleByNamedQuery() { List result = repository.findByNamedQuery("Dave"); 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 3b217f593d..8c9d84f783 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 @@ -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. @@ -147,6 +147,8 @@ public interface PersonRepository extends MongoRepository, Query List findBySex(Sex sex); + List findBySex(Sex sex, Pageable pageable); + List findByNamedQuery(String firstname); GeoResults findByLocationNear(Point point, Distance maxDistance); From 651255ca5832974d59679469da3a42bba94992bc Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 14 Jun 2012 12:19:06 +0200 Subject: [PATCH 02/49] DATAMONGO-447 - Fixed broken log output in debug level. The debug output now uses the already mapped query object when concatenating the log string. Improved applying the id after save operations by inspecting whether the object already has the id set before trying to set it. This could have caused problems in case you use a complex id and don't provide a custom converter as it can be serialized out of the box. Fixed minor glitch in MappingMongoConverter which was not really a bug as another path through the code has covered the scenario later on. Introduced SerializationUtils class that provides a method to safely serialize objects to pseudo JSON. Pseudo in the sense that it simply renders a complex object as { $java : object.toString() }. This is useful for debug output before the DBObject was mapped into Mongo-native types. --- .../data/mongodb/core/MongoTemplate.java | 17 ++- .../data/mongodb/core/SerializationUtils.java | 110 ++++++++++++++++++ .../core/convert/MappingMongoConverter.java | 3 +- .../data/mongodb/core/query/Query.java | 12 ++ .../repository/query/MongoQueryCreator.java | 2 +- .../data/mongodb/core/MongoTemplateTests.java | 29 +++++ .../core/SerializationUtilsUnitTests.java | 66 +++++++++++ .../MappingMongoConverterUnitTests.java | 18 +++ 8 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SerializationUtils.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SerializationUtilsUnitTests.java 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 0fcf67e29f..f29125f447 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 @@ -50,6 +50,7 @@ import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.authentication.UserCredentials; import org.springframework.data.convert.EntityReader; +import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.BeanWrapper; import org.springframework.data.mapping.model.MappingException; @@ -938,7 +939,7 @@ public Void doInCollection(DBCollection collection) throws MongoException, DataA entityClass, null, queryObject); WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction); if (LOGGER.isDebugEnabled()) { - LOGGER.debug("remove using query: " + queryObject + " in collection: " + collection.getName()); + LOGGER.debug("remove using query: " + dboq + " in collection: " + collection.getName()); } if (writeConcernToUse == null) { wr = collection.remove(dboq); @@ -1364,9 +1365,19 @@ protected void populateIdIfNecessary(Object savedObject, Object id) { return; } + ConversionService conversionService = mongoConverter.getConversionService(); + BeanWrapper, Object> wrapper = BeanWrapper.create(savedObject, conversionService); + try { - BeanWrapper.create(savedObject, mongoConverter.getConversionService()).setProperty(idProp, id); - return; + + Object idValue = wrapper.getProperty(idProp); + + if (idValue != null) { + return; + } + + wrapper.setProperty(idProp, id); + } catch (IllegalAccessException e) { throw new MappingException(e.getMessage(), e); } catch (InvocationTargetException e) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SerializationUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SerializationUtils.java new file mode 100644 index 0000000000..d21098843e --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SerializationUtils.java @@ -0,0 +1,110 @@ +/* + * 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 java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.springframework.core.convert.converter.Converter; + +import com.mongodb.DBObject; +import com.mongodb.util.JSON; + +/** + * Utility methods for JSON serialization. + * + * @author Oliver Gierke + */ +public abstract class SerializationUtils { + + private SerializationUtils() { + + } + + /** + * Serializes the given object into pseudo-JSON meaning it's trying to create a JSON representation as far as possible + * but falling back to the given object's {@link Object#toString()} method if it's not serializable. Useful for + * printing raw {@link DBObject}s containing complex values before actually converting them into Mongo native types. + * + * @param value + * @return + */ + public static String serializeToJsonSafely(Object value) { + + if (value == null) { + return null; + } + + try { + return JSON.serialize(value); + } catch (Exception e) { + if (value instanceof Collection) { + return toString((Collection) value); + } else if (value instanceof Map) { + return toString((Map) value); + } else if (value instanceof DBObject) { + return toString(((DBObject) value).toMap()); + } else { + return String.format("{ $java : %s }", value.toString()); + } + } + } + + private static String toString(Map source) { + return iterableToDelimitedString(source.entrySet(), "{ ", " }", new Converter, Object>() { + public Object convert(Entry source) { + return String.format("\"%s\" : %s", source.getKey(), serializeToJsonSafely(source.getValue())); + } + }); + } + + private static String toString(Collection source) { + return iterableToDelimitedString(source, "[ ", " ]", new Converter() { + public Object convert(Object source) { + return serializeToJsonSafely(source); + } + }); + } + + /** + * Creates a string representation from the given {@link Iterable} prepending the postfix, applying the given + * {@link Converter} to each element before adding it to the result {@link String}, concatenating each element with + * {@literal ,} and applying the postfix. + * + * @param source + * @param prefix + * @param postfix + * @param transformer + * @return + */ + private static String iterableToDelimitedString(Iterable source, String prefix, String postfix, + Converter transformer) { + + StringBuilder builder = new StringBuilder(prefix); + Iterator iterator = source.iterator(); + + while (iterator.hasNext()) { + builder.append(transformer.convert(iterator.next())); + if (iterator.hasNext()) { + builder.append(", "); + } + } + + return builder.append(postfix).toString(); + } +} 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 96b1c7160e..da069ad6f1 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 @@ -439,7 +439,6 @@ private static Collection asCollection(Object source) { * * @param collection must not be {@literal null}. * @param property must not be {@literal null}. - * * @return */ protected DBObject createCollection(Collection collection, MongoPersistentProperty property) { @@ -819,7 +818,7 @@ public Object convertToMongoType(Object obj) { return null; } - Class target = conversions.getCustomWriteTarget(getClass()); + Class target = conversions.getCustomWriteTarget(obj.getClass()); if (target != null) { return conversionService.convert(obj, target); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java index 40565fd588..58798acaf9 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java @@ -15,6 +15,8 @@ */ package org.springframework.data.mongodb.core.query; +import static org.springframework.data.mongodb.core.SerializationUtils.*; + import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -140,4 +142,14 @@ public String getHint() { protected List getCriteria() { return new ArrayList(this.criteria.values()); } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return String.format("Query: %s, Fields: %s, Sort: %s", serializeToJsonSafely(getQueryObject()), + serializeToJsonSafely(getFieldsObject()), serializeToJsonSafely(getSortObject())); + } } 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 c73aba066d..1fe9bd706c 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 @@ -157,7 +157,7 @@ protected Query complete(Criteria criteria, Sort sort) { QueryUtils.applySorting(query, sort); if (LOG.isDebugEnabled()) { - LOG.debug("Created query " + query.getQueryObject()); + LOG.debug("Created query " + query); } return query; 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 045c9351b0..4f4d13f7fe 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 @@ -1103,6 +1103,35 @@ public void executesQueryWithNegatedRegexCorrectly() { assertThat(result.get(0).field, is("Beauford")); } + /** + * @see DATAMONGO-447 + */ + @Test + public void storesAndRemovesTypeWithComplexId() { + + MyId id = new MyId(); + id.first = "foo"; + id.second = "bar"; + + TypeWithMyId source = new TypeWithMyId(); + source.id = id; + + template.save(source); + template.remove(query(where("id").is(id)), TypeWithMyId.class); + } + + static class MyId { + + String first; + String second; + } + + static class TypeWithMyId { + + @Id + MyId id; + } + public static class Sample { @Id diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SerializationUtilsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SerializationUtilsUnitTests.java new file mode 100644 index 0000000000..883729bb6f --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SerializationUtilsUnitTests.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; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.springframework.data.mongodb.core.SerializationUtils.*; + +import java.util.Arrays; + +import org.hamcrest.Matcher; +import org.junit.Test; + +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; + +/** + * Unit tests for {@link SerializationUtils}. + * + * @author Oliver Gierke + */ +public class SerializationUtilsUnitTests { + + @Test + public void writesSimpleDBObject() { + + DBObject dbObject = new BasicDBObject("foo", "bar"); + assertThat(serializeToJsonSafely(dbObject), is("{ \"foo\" : \"bar\"}")); + } + + @Test + public void writesComplexObjectAsPlainToString() { + + DBObject dbObject = new BasicDBObject("foo", new Complex()); + assertThat(serializeToJsonSafely(dbObject), + startsWith("{ \"foo\" : { $java : org.springframework.data.mongodb.core.SerializationUtilsUnitTests$Complex")); + } + + @Test + public void writesCollection() { + + DBObject dbObject = new BasicDBObject("foo", Arrays.asList("bar", new Complex())); + Matcher expectedOutput = allOf( + startsWith("{ \"foo\" : [ \"bar\", { $java : org.springframework.data.mongodb.core.SerializationUtilsUnitTests$Complex"), + endsWith(" } ] }")); + assertThat(serializeToJsonSafely(dbObject), is(expectedOutput)); + } + + static class Complex { + + } + +} 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 41e051c4c7..e982a11671 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 @@ -120,6 +120,24 @@ public void convertsJodaTimeTypesCorrectly() { assertThat(result.birthDate, is(notNullValue())); } + @Test + public void convertsCustomTypeOnConvertToMongoType() { + + List> converters = new ArrayList>(); + converters.add(new LocalDateToDateConverter()); + converters.add(new DateToLocalDateConverter()); + + CustomConversions conversions = new CustomConversions(converters); + mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder()); + + converter = new MappingMongoConverter(factory, mappingContext); + converter.setCustomConversions(conversions); + converter.afterPropertiesSet(); + + LocalDate date = new LocalDate(); + converter.convertToMongoType(date); + } + /** * @see DATAMONGO-130 */ From a4a03b01648904af8c98696db2cf7fb6a018f6bb Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 14 Jun 2012 12:36:42 +0200 Subject: [PATCH 03/49] DATAMONGO-450 - Log output uses mapped query for debug logging. --- .../data/mongodb/core/MongoTemplate.java | 10 ++++++---- 1 file changed, 6 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 f29125f447..438829518d 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 @@ -1338,13 +1338,15 @@ protected T doFindAndModify(String collectionName, DBObject query, DBObject updateObj.put(key, mongoConverter.convertToMongoType(updateObj.get(key))); } + DBObject mappedQuery = mapper.getMappedObject(query, entity); + if (LOGGER.isDebugEnabled()) { - LOGGER.debug("findAndModify using query: " + query + " fields: " + fields + " sort: " + sort + " for class: " - + entityClass + " and update: " + updateObj + " in collection: " + collectionName); + LOGGER.debug("findAndModify using query: " + mappedQuery + " fields: " + fields + " sort: " + sort + + " for class: " + entityClass + " and update: " + updateObj + " in collection: " + collectionName); } - return executeFindOneInternal(new FindAndModifyCallback(mapper.getMappedObject(query, entity), fields, sort, - updateObj, options), new ReadDbObjectCallback(readerToUse, entityClass), collectionName); + return executeFindOneInternal(new FindAndModifyCallback(mappedQuery, fields, sort, updateObj, options), + new ReadDbObjectCallback(readerToUse, entityClass), collectionName); } /** From 3c90b4987d8eb5ea340a62ffca5ca7c727b7bc93 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 15 Jun 2012 19:23:32 +0200 Subject: [PATCH 04/49] Added missing dependency declarations. Build has worked so far because we relied on the dependencies being pulled in transitively but it's best practice not to do so. --- spring-data-mongodb-parent/pom.xml | 5 +++++ spring-data-mongodb/pom.xml | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index b4b94171ec..9744c12e57 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -187,6 +187,11 @@ spring-tx ${org.springframework.version.range} + + org.springframework + spring-context + ${org.springframework.version.range} + org.springframework spring-orm diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 51c7d91dc9..6d57ffefba 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -18,10 +18,22 @@ + + org.springframework + spring-tx + + + org.springframework + spring-context + org.springframework spring-beans + + org.springframework + spring-core + org.springframework spring-expression From b02e81c481d255bee790efa92553d70a98b1b054 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 19 Jun 2012 09:27:04 +0200 Subject: [PATCH 05/49] DATAMONGO-428 - Fixed parsing of output collection for complex MapReduce result. The raw result for a map-reduce operation might contain a complex element containing the output collection in case the original request configured an output database as option. Adapted the parsing of the output collection to accommodate both scenarios (plain String value as well as DBObject wrapper). --- .../core/mapreduce/MapReduceResults.java | 103 ++++++++++++------ .../mapreduce/MapReduceResultsUnitTests.java | 59 ++++++++++ 2 files changed, 129 insertions(+), 33 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResultsUnitTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResults.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResults.java index adfbeaef96..a32cbf1a09 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResults.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResults.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. @@ -26,33 +26,39 @@ * Collects the results of performing a MapReduce operations. * * @author Mark Pollack - * - * @param The class in which the results are mapped onto, accessible via an interator. + * @author Oliver Gierke + * @param The class in which the results are mapped onto, accessible via an iterator. */ public class MapReduceResults implements Iterable { private final List mappedResults; - - private DBObject rawResults; - - private MapReduceTiming mapReduceTiming; - - private MapReduceCounts mapReduceCounts; - - private String outputCollection; - + private final DBObject rawResults; + private final String outputCollection; + private final MapReduceTiming mapReduceTiming; + private final MapReduceCounts mapReduceCounts; + + /** + * Creates a new {@link MapReduceResults} from the given mapped results and the raw one. + * + * @param mappedResults must not be {@literal null}. + * @param rawResults must not be {@literal null}. + */ public MapReduceResults(List mappedResults, DBObject rawResults) { + Assert.notNull(mappedResults); Assert.notNull(rawResults); + this.mappedResults = mappedResults; this.rawResults = rawResults; - parseTiming(rawResults); - parseCounts(rawResults); - if (rawResults.get("result") != null) { - this.outputCollection = (String) rawResults.get("result"); - } + this.mapReduceTiming = parseTiming(rawResults); + this.mapReduceCounts = parseCounts(rawResults); + this.outputCollection = parseOutputCollection(rawResults); } + /* + * (non-Javadoc) + * @see java.lang.Iterable#iterator() + */ public Iterator iterator() { return mappedResults.iterator(); } @@ -73,28 +79,59 @@ public DBObject getRawResults() { return rawResults; } - protected void parseTiming(DBObject rawResults) { + private MapReduceTiming parseTiming(DBObject rawResults) { + DBObject timing = (DBObject) rawResults.get("timing"); - if (timing != null) { - if (timing.get("mapTime") != null && timing.get("emitLoop") != null && timing.get("total") != null) { - mapReduceTiming = new MapReduceTiming((Long) timing.get("mapTime"), (Integer) timing.get("emitLoop"), - (Integer) timing.get("total")); - } - } else { - mapReduceTiming = new MapReduceTiming(-1, -1, -1); + + if (timing == null) { + return new MapReduceTiming(-1, -1, -1); + } + + if (timing.get("mapTime") != null && timing.get("emitLoop") != null && timing.get("total") != null) { + return new MapReduceTiming((Long) timing.get("mapTime"), (Integer) timing.get("emitLoop"), + (Integer) timing.get("total")); } + + return new MapReduceTiming(-1, -1, -1); } - protected void parseCounts(DBObject rawResults) { + /** + * Parses the raw {@link DBObject} result into a {@link MapReduceCounts} value object. + * + * @param rawResults + * @return + */ + private MapReduceCounts parseCounts(DBObject rawResults) { + DBObject counts = (DBObject) rawResults.get("counts"); - if (counts != null) { - if (counts.get("input") != null && counts.get("emit") != null && counts.get("output") != null) { - mapReduceCounts = new MapReduceCounts((Integer) counts.get("input"), (Integer) counts.get("emit"), - (Integer) counts.get("output")); - } - } else { - mapReduceCounts = new MapReduceCounts(-1, -1, -1); + + if (counts == null) { + return new MapReduceCounts(-1, -1, -1); + } + + if (counts.get("input") != null && counts.get("emit") != null && counts.get("output") != null) { + return new MapReduceCounts((Integer) counts.get("input"), (Integer) counts.get("emit"), + (Integer) counts.get("output")); } + + return new MapReduceCounts(-1, -1, -1); } + /** + * Parses the output collection from the raw {@link DBObject} result. + * + * @param rawResults + * @return + */ + private String parseOutputCollection(DBObject rawResults) { + + Object resultField = rawResults.get("result"); + + if (resultField == null) { + return null; + } + + return resultField instanceof DBObject ? ((DBObject) resultField).get("collection").toString() : resultField + .toString(); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResultsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResultsUnitTests.java new file mode 100644 index 0000000000..b5eafc9980 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResultsUnitTests.java @@ -0,0 +1,59 @@ +/* + * 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.mapreduce; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import java.util.Collections; + +import org.junit.Test; + +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; + +/** + * Unit tests for {@link MapReduceResults}. + * + * @author Oliver Gierke + */ +public class MapReduceResultsUnitTests { + + /** + * @see DATAMONGO-428 + */ + @Test + public void resolvesOutputCollectionForPlainResult() { + + DBObject rawResult = new BasicDBObject("result", "FOO"); + MapReduceResults results = new MapReduceResults(Collections.emptyList(), rawResult); + + assertThat(results.getOutputCollection(), is("FOO")); + } + + /** + * @see DATAMONGO-428 + */ + @Test + public void resolvesOutputCollectionForDBObjectResult() { + + DBObject rawResult = new BasicDBObject("result", new BasicDBObject("collection", "FOO")); + MapReduceResults results = new MapReduceResults(Collections.emptyList(), rawResult); + + assertThat(results.getOutputCollection(), is("FOO")); + } + +} From 783cec032544d3560ae97a645ca713d61d06bf8a Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 19 Jun 2012 17:46:54 +0200 Subject: [PATCH 06/49] DATAMONGO-461 - Fixed potential NullPointerException in MappedConstructor. Reject PersistentEntity instances that don't have a PersistenceConstructor as this indicates a mapping problem (either a constructor needed to be annotated or a custom converter registered). --- .../core/convert/MappedConstructor.java | 18 ++++++-- .../convert/MappedConstructorUnitTests.java | 44 +++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappedConstructorUnitTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappedConstructor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappedConstructor.java index bc1f01152c..5f7e4b8549 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappedConstructor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappedConstructor.java @@ -18,6 +18,7 @@ import java.util.HashSet; import java.util.Set; +import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PreferredConstructor; @@ -25,6 +26,7 @@ import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.context.PersistentPropertyPath; +import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.util.TypeInformation; @@ -37,6 +39,9 @@ */ class MappedConstructor { + private static final String REJECT_CONSTRUCTOR = String.format("Entity doesn't have a usable constructor, either " + + "provide a custom converter or annotate a constructor with @%s!", PersistenceConstructor.class.getSimpleName()); + private final Set parameters; /** @@ -44,13 +49,19 @@ class MappedConstructor { * * @param entity must not be {@literal null}. * @param context must not be {@literal null}. + * @throws MappingException in case the {@link MongoPersistentEntity} handed in does not have a + * {@link PreferredConstructor}. */ public MappedConstructor(MongoPersistentEntity entity, - MappingContext, MongoPersistentProperty> context) { + MappingContext, MongoPersistentProperty> context) throws MappingException { Assert.notNull(entity); Assert.notNull(context); + if (entity.getPreferredConstructor() == null) { + throw new MappingException(REJECT_CONSTRUCTOR); + } + this.parameters = new HashSet(); for (Parameter parameter : entity.getPreferredConstructor().getParameters()) { @@ -83,6 +94,7 @@ public boolean isConstructorParameter(PersistentProperty property) { * * @param parameter must not be {@literal null}. * @return + * @throws MappingException in case no {@link MappedParameter} can be found for the given {@link Parameter}. */ public MappedParameter getFor(Parameter parameter) { @@ -92,7 +104,7 @@ public MappedParameter getFor(Parameter parameter) { } } - throw new IllegalStateException(String.format("Didn't find a MappedParameter for %s!", parameter.toString())); + throw new MappingException(String.format("Didn't find a MappedParameter for %s!", parameter.toString())); } /** @@ -165,4 +177,4 @@ public boolean maps(PersistentProperty property) { return this.property.equals(property); } } -} \ No newline at end of file +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappedConstructorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappedConstructorUnitTests.java new file mode 100644 index 0000000000..e44b23ecce --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappedConstructorUnitTests.java @@ -0,0 +1,44 @@ +/* + * 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.convert; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.mapping.context.MappingContext; +import org.springframework.data.mapping.model.MappingException; +import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; +import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; + +/** + * Unit tests for {@link MappedConstructor}. + * + * @author Oliver Gierke + */ +@RunWith(MockitoJUnitRunner.class) +public class MappedConstructorUnitTests { + + @Mock + MongoPersistentEntity entity; + @Mock + MappingContext, MongoPersistentProperty> mappingContext; + + @Test(expected = MappingException.class) + public void rejectsEntityWithoutPersistenceConstructor() { + new MappedConstructor(entity, mappingContext); + } +} From 25a94bc45e7d2856e8dd13b80b7d3c908b6424ed Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 19 Jun 2012 18:55:19 +0200 Subject: [PATCH 07/49] DATAMONGO-462 - Added custom converters for URL. So far URL instances were treated as entities and serialized as nested document. As there was no custom converter registered to re-instantiate the objects and URL does not contain a no-arg constructor, reading the instances back in resulted in an ugly exception in ReflectionEntityInstantiator. We now register a custom Converter to serialize URL instances as their plain toString() representation. This causes the reading working out of the box as the StringToObjectConverter registered by default uses the constructor taking a String on URL accidentally. To make sure this still works we added an explicit StringToURLConverter to implement symmetric conversions. --- .../core/convert/CustomConversions.java | 4 +++ .../mongodb/core/convert/MongoConverters.java | 28 ++++++++++++++++++ .../convert/CustomConversionsUnitTests.java | 20 +++++++++++++ .../MappingMongoConverterUnitTests.java | 29 +++++++++++++++++++ 4 files changed, 81 insertions(+) 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 71f80b8ee1..27b1720e48 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 @@ -38,6 +38,8 @@ import org.springframework.data.mongodb.core.convert.MongoConverters.BigIntegerToStringConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigDecimalConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigIntegerConverter; +import org.springframework.data.mongodb.core.convert.MongoConverters.StringToURLConverter; +import org.springframework.data.mongodb.core.convert.MongoConverters.URLToStringConverter; import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes; import org.springframework.util.Assert; @@ -89,6 +91,8 @@ public CustomConversions(List converters) { this.converters.add(StringToBigDecimalConverter.INSTANCE); this.converters.add(BigIntegerToStringConverter.INSTANCE); this.converters.add(StringToBigIntegerConverter.INSTANCE); + this.converters.add(URLToStringConverter.INSTANCE); + this.converters.add(StringToURLConverter.INSTANCE); this.converters.addAll(converters); for (Object c : this.converters) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java index 80e116ff83..07655c8440 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java @@ -17,8 +17,12 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.net.MalformedURLException; +import java.net.URL; import org.bson.types.ObjectId; +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.Converter; import org.springframework.util.StringUtils; @@ -119,4 +123,28 @@ public BigInteger convert(String source) { return StringUtils.hasText(source) ? new BigInteger(source) : null; } } + + public static enum URLToStringConverter implements Converter { + INSTANCE; + + public String convert(URL source) { + return source == null ? null : source.toString(); + } + } + + public static enum StringToURLConverter implements Converter { + INSTANCE; + + private static final TypeDescriptor SOURCE = TypeDescriptor.valueOf(String.class); + private static final TypeDescriptor TARGET = TypeDescriptor.valueOf(URL.class); + + public URL convert(String source) { + + try { + return source == null ? null : new URL(source); + } catch (MalformedURLException e) { + throw new ConversionFailedException(SOURCE, TARGET, source, e); + } + } + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/CustomConversionsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/CustomConversionsUnitTests.java index 8660c47cfa..9fae44fe68 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/CustomConversionsUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/CustomConversionsUnitTests.java @@ -3,6 +3,7 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import java.net.URL; import java.text.DateFormat; import java.text.Format; import java.util.Arrays; @@ -152,6 +153,25 @@ public void considersBinaryASimpleType() { assertThat(conversions.isSimpleType(Binary.class), is(true)); } + /** + * @see DATAMONGO-462 + */ + @Test + public void hasWriteConverterForURL() { + + CustomConversions conversions = new CustomConversions(); + assertThat(conversions.hasCustomWriteTarget(URL.class), is(true)); + } + + /** + * @see DATAMONGO-462 + */ + @Test + public void readTargetForURL() { + CustomConversions conversions = new CustomConversions(); + assertThat(conversions.hasCustomReadTarget(String.class, URL.class), is(true)); + } + enum FormatToStringConverter implements Converter { INSTANCE; 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 e982a11671..7591dc464f 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 @@ -21,6 +21,7 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -1034,6 +1035,30 @@ public void convertsSetToBasicDBList() { assertThat(readResult.iterator().next(), is(Map.class)); } + /** + * @see DATAMONGO-462 + */ + @Test + public void readsURLsAsStringsByDefault() throws Exception { + DBObject dbObject = new BasicDBObject("url", new URL("http://springsource.org")); + URLWrapper result = converter.read(URLWrapper.class, dbObject); + assertThat(result.url, is(new URL("http://springsource.org"))); + } + + /** + * @see DATAMONGO-462 + */ + @Test + public void writesURLsAsStringsByDefault() throws Exception { + + URLWrapper wrapper = new URLWrapper(); + wrapper.url = new URL("http://springsource.org"); + DBObject sink = new BasicDBObject(); + + converter.write(wrapper, sink); + assertThat(sink.get("url"), is((Object) "http://springsource.org")); + } + static class GenericType { T content; } @@ -1165,6 +1190,10 @@ static class Attribute { Object value; } + static class URLWrapper { + URL url; + } + private class LocalDateToDateConverter implements Converter { public Date convert(LocalDate source) { From 11f0c515b013efcd99a471845c516d20e3c0b353 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 20 Jun 2012 10:05:16 +0200 Subject: [PATCH 08/49] DATAMONGO-378 - Fixed potential ClassCastException for MapReduceResults and upcoming MongoDB release. The type of the value returned for the total field of the timing map in map-reduce results has changed from Integer to Long as of MongoDB version 2.1.0 apparently. Changed MapReduceResults to accommodate either Integer or Long types. --- .../mongodb/core/mapreduce/MapReduceResults.java | 16 ++++++++++++++-- .../mapreduce/MapReduceResultsUnitTests.java | 13 +++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResults.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResults.java index a32cbf1a09..34769d7ea4 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResults.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResults.java @@ -88,13 +88,25 @@ private MapReduceTiming parseTiming(DBObject rawResults) { } if (timing.get("mapTime") != null && timing.get("emitLoop") != null && timing.get("total") != null) { - return new MapReduceTiming((Long) timing.get("mapTime"), (Integer) timing.get("emitLoop"), - (Integer) timing.get("total")); + return new MapReduceTiming(getAsLong(timing, "mapTime"), getAsLong(timing, "emitLoop"), + getAsLong(timing, "total")); } return new MapReduceTiming(-1, -1, -1); } + /** + * Returns the value of the source's field with the given key as {@link Long}. + * + * @param source + * @param key + * @return + */ + private Long getAsLong(DBObject source, String key) { + Object raw = source.get(key); + return raw instanceof Long ? (Long) raw : (Integer) raw; + } + /** * Parses the raw {@link DBObject} result into a {@link MapReduceCounts} value object. * diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResultsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResultsUnitTests.java index b5eafc9980..ac7b29d61c 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResultsUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapreduce/MapReduceResultsUnitTests.java @@ -56,4 +56,17 @@ public void resolvesOutputCollectionForDBObjectResult() { assertThat(results.getOutputCollection(), is("FOO")); } + /** + * @see DATAMONGO-378 + */ + @Test + public void handlesLongTotalInResult() { + + DBObject inner = new BasicDBObject("total", 1L); + inner.put("mapTime", 1L); + inner.put("emitLoop", 1); + + DBObject source = new BasicDBObject("timing", inner); + new MapReduceResults(Collections.emptyList(), source); + } } From c4c8e368ca917f54829e0ede348ac0349a496292 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 20 Jun 2012 10:42:50 +0200 Subject: [PATCH 09/49] DATAMONGO-454 - Improvements to ServerAddressPropertyEditor. ServerAddressPropertyEditor now only eventually fails if none of the configured addresses can be parsed correctly. Strengthened the parsing implementation to not fail for host-only parsing or accidental double commas. Cleaned up test dependency setup. --- spring-data-mongodb-cross-store/pom.xml | 29 ------- spring-data-mongodb-log4j/pom.xml | 38 --------- spring-data-mongodb-parent/pom.xml | 38 ++++++--- spring-data-mongodb/pom.xml | 21 +---- .../config/ServerAddressPropertyEditor.java | 54 ++++++++++--- .../config/MongoNamespaceReplicaSetTests.java | 39 +++++---- .../mongodb/config/NamespaceTestSupport.java | 42 ---------- .../ServerAddressPropertyEditorUnitTests.java | 80 +++++++++++++++++++ .../data/mongodb/core/MongoTemplateTests.java | 2 - .../MappingMongoConverterUnitTests.java | 40 +++++----- .../core/query/QueryMapperUnitTests.java | 18 ++--- .../SpringDataMongodbSerializerUnitTests.java | 4 +- 12 files changed, 202 insertions(+), 203 deletions(-) delete mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/NamespaceTestSupport.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditorUnitTests.java diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index 901c60de6a..384fcd12d2 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -68,24 +68,6 @@ log4j log4j - - - javax.mail - mail - - - javax.jms - jms - - - com.sun.jdmk - jmxtools - - - com.sun.jmx - jmxri - - runtime @@ -95,17 +77,6 @@ true - - org.mockito - mockito-all - test - - - - junit - junit - - org.aspectj aspectjrt diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index dc07dc40d3..e04deca560 100644 --- a/spring-data-mongodb-log4j/pom.xml +++ b/spring-data-mongodb-log4j/pom.xml @@ -27,47 +27,9 @@ log4j log4j - - - javax.mail - mail - - - javax.jms - jms - - - com.sun.jdmk - jmxtools - - - com.sun.jmx - jmxri - - compile - - - org.mockito - mockito-all - test - - - - org.hamcrest - hamcrest-all - 1.1 - test - - - - junit - junit - test - - diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index 9744c12e57..fa074ce756 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -11,9 +11,10 @@ UTF-8 - 4.8.1 + 4.10 1.2.15 1.8.4 + 1.2.1 1.5.10 1.6.1 3.0.7.RELEASE @@ -289,14 +290,14 @@ org.mockito - mockito-all + mockito-core ${org.mockito.version} test junit - junit + junit-dep ${junit.version} test @@ -304,19 +305,34 @@ - + + log4j log4j ${log4j.version} test + + + org.hamcrest + hamcrest-library + ${hamcrest.version} + test + + + + org.mockito + mockito-core + test + + + + junit + junit-dep + test + + @@ -398,7 +414,7 @@ **/*Tests.java - junit:junit + junit:junit-dep diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 6d57ffefba..6332136323 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -91,25 +91,6 @@ - - org.mockito - mockito-all - test - - - - org.hamcrest - hamcrest-all - 1.1 - test - - - - junit - junit - test - - joda-time joda-time @@ -120,8 +101,8 @@ org.slf4j slf4j-api - test + org.slf4j jcl-over-slf4j diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditor.java index 1cddded9c7..a38566db48 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditor.java @@ -17,7 +17,11 @@ import java.beans.PropertyEditorSupport; import java.net.UnknownHostException; +import java.util.HashSet; +import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.util.StringUtils; import com.mongodb.ServerAddress; @@ -30,6 +34,8 @@ */ public class ServerAddressPropertyEditor extends PropertyEditorSupport { + private static final Log LOG = LogFactory.getLog(ServerAddressPropertyEditor.class); + /* * (non-Javadoc) * @see java.beans.PropertyEditorSupport#setAsText(java.lang.String) @@ -38,21 +44,49 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport { public void setAsText(String replicaSetString) { String[] replicaSetStringArray = StringUtils.commaDelimitedListToStringArray(replicaSetString); - ServerAddress[] serverAddresses = new ServerAddress[replicaSetStringArray.length]; + Set serverAddresses = new HashSet(replicaSetStringArray.length); - for (int i = 0; i < replicaSetStringArray.length; i++) { + for (String element : replicaSetStringArray) { - String[] hostAndPort = StringUtils.delimitedListToStringArray(replicaSetStringArray[i], ":"); + ServerAddress address = parseServerAddress(element); - try { - serverAddresses[i] = new ServerAddress(hostAndPort[0], Integer.parseInt(hostAndPort[1])); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Could not parse port " + hostAndPort[1], e); - } catch (UnknownHostException e) { - throw new IllegalArgumentException("Could not parse host " + hostAndPort[0], e); + if (address != null) { + serverAddresses.add(address); } } - setValue(serverAddresses); + if (serverAddresses.isEmpty()) { + throw new IllegalArgumentException( + "Could not resolve at least one server of the replica set configuration! Validate your config!"); + } + + setValue(serverAddresses.toArray(new ServerAddress[serverAddresses.size()])); + } + + /** + * Parses the given source into a {@link ServerAddress}. + * + * @param source + * @return the + */ + private ServerAddress parseServerAddress(String source) { + + String[] hostAndPort = StringUtils.delimitedListToStringArray(source.trim(), ":"); + + if (!StringUtils.hasText(source) || hostAndPort.length > 2) { + LOG.warn(String.format("Could not parse address source '%s'. Check your replica set configuration!", source)); + return null; + } + + try { + return hostAndPort.length == 1 ? new ServerAddress(hostAndPort[0]) : new ServerAddress(hostAndPort[0], + Integer.parseInt(hostAndPort[1])); + } catch (UnknownHostException e) { + LOG.warn(String.format("Could not parse host '%s'. Check your replica set configuration!", hostAndPort[0])); + } catch (NumberFormatException e) { + LOG.warn(String.format("Could not parse port '%s'. Check your replica set configuration!", hostAndPort[1])); + } + + return null; } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests.java index 0affa2f55d..975812f774 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2010 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. @@ -16,6 +16,7 @@ package org.springframework.data.mongodb.config; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.util.List; @@ -29,6 +30,7 @@ import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.util.ReflectionTestUtils; import com.mongodb.CommandResult; import com.mongodb.Mongo; @@ -36,47 +38,45 @@ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration -public class MongoNamespaceReplicaSetTests extends NamespaceTestSupport { +public class MongoNamespaceReplicaSetTests { @Autowired private ApplicationContext ctx; @Test + @SuppressWarnings("unchecked") public void testParsingMongoWithReplicaSets() throws Exception { + assertTrue(ctx.containsBean("replicaSetMongo")); MongoFactoryBean mfb = (MongoFactoryBean) ctx.getBean("&replicaSetMongo"); - List replicaSetSeeds = readField("replicaSetSeeds", mfb); - assertNotNull(replicaSetSeeds); - - assertEquals("127.0.0.1", replicaSetSeeds.get(0).getHost()); - assertEquals(10001, replicaSetSeeds.get(0).getPort()); - - assertEquals("localhost", replicaSetSeeds.get(1).getHost()); - assertEquals(10002, replicaSetSeeds.get(1).getPort()); + List replicaSetSeeds = (List) ReflectionTestUtils.getField(mfb, "replicaSetSeeds"); + assertThat(replicaSetSeeds, is(notNullValue())); + assertThat(replicaSetSeeds, hasItems(new ServerAddress("127.0.0.1", 10001), new ServerAddress("localhost", 10002))); } @Test + @SuppressWarnings("unchecked") public void testParsingWithPropertyPlaceHolder() throws Exception { + assertTrue(ctx.containsBean("manyReplicaSetMongo")); MongoFactoryBean mfb = (MongoFactoryBean) ctx.getBean("&manyReplicaSetMongo"); - List replicaSetSeeds = readField("replicaSetSeeds", mfb); - assertNotNull(replicaSetSeeds); - - assertEquals("192.168.174.130", replicaSetSeeds.get(0).getHost()); - assertEquals(27017, replicaSetSeeds.get(0).getPort()); - assertEquals("192.168.174.130", replicaSetSeeds.get(1).getHost()); - assertEquals(27018, replicaSetSeeds.get(1).getPort()); - assertEquals("192.168.174.130", replicaSetSeeds.get(2).getHost()); - assertEquals(27019, replicaSetSeeds.get(2).getPort()); + List replicaSetSeeds = (List) ReflectionTestUtils.getField(mfb, "replicaSetSeeds"); + assertThat(replicaSetSeeds, is(notNullValue())); + assertThat(replicaSetSeeds, hasSize(3)); + assertThat( + replicaSetSeeds, + hasItems(new ServerAddress("192.168.174.130", 27017), new ServerAddress("192.168.174.130", 27018), + new ServerAddress("192.168.174.130", 27019))); } @Test @Ignore("CI infrastructure does not yet support replica sets") public void testMongoWithReplicaSets() { + Mongo mongo = ctx.getBean(Mongo.class); assertEquals(2, mongo.getAllAddress().size()); List servers = mongo.getAllAddress(); @@ -88,6 +88,5 @@ public void testMongoWithReplicaSets() { MongoTemplate template = new MongoTemplate(mongo, "admin"); CommandResult result = template.executeCommand("{replSetGetStatus : 1}"); assertEquals("blort", result.getString("set")); - } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/NamespaceTestSupport.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/NamespaceTestSupport.java deleted file mode 100644 index bc5faf1fdb..0000000000 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/NamespaceTestSupport.java +++ /dev/null @@ -1,42 +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.config; - -import java.lang.reflect.Field; - -public class NamespaceTestSupport { - - @SuppressWarnings({ "unchecked" }) - public static T readField(String name, Object target) throws Exception { - Field field = null; - Class clazz = target.getClass(); - do { - try { - field = clazz.getDeclaredField(name); - } catch (Exception ex) { - } - - clazz = clazz.getSuperclass(); - } while (field == null && !clazz.equals(Object.class)); - - if (field == null) - throw new IllegalArgumentException("Cannot find field '" + name + "' in the class hierarchy of " - + target.getClass()); - field.setAccessible(true); - return (T) field.get(target); - } -} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditorUnitTests.java new file mode 100644 index 0000000000..3271b1da11 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditorUnitTests.java @@ -0,0 +1,80 @@ +/* + * 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 java.net.UnknownHostException; +import java.util.Arrays; +import java.util.Collection; + +import org.junit.Before; +import org.junit.Test; + +import com.mongodb.ServerAddress; + +/** + * Unit tests for {@link ServerAddressPropertyEditor}. + * + * @author Oliver Gierke + */ +public class ServerAddressPropertyEditorUnitTests { + + ServerAddressPropertyEditor editor; + + @Before + public void setUp() { + editor = new ServerAddressPropertyEditor(); + } + + /** + * @see DATAMONGO-454 + */ + @Test(expected = IllegalArgumentException.class) + public void rejectsAddressConfigWithoutASingleParsableServerAddress() { + + editor.setAsText("foo, bar"); + } + + /** + * @see DATAMONGO-454 + */ + @Test + public void skipsUnparsableAddressIfAtLeastOneIsParsable() throws UnknownHostException { + + editor.setAsText("foo, localhost"); + assertSingleAddressOfLocalhost(editor.getValue()); + } + + /** + * @see DATAMONGO-454 + */ + @Test + public void handlesEmptyAddressAsParseError() throws UnknownHostException { + + editor.setAsText(", localhost"); + assertSingleAddressOfLocalhost(editor.getValue()); + } + + private static void assertSingleAddressOfLocalhost(Object result) throws UnknownHostException { + + assertThat(result, is(instanceOf(ServerAddress[].class))); + Collection addresses = Arrays.asList((ServerAddress[]) result); + assertThat(addresses, hasSize(1)); + assertThat(addresses, hasItem(new ServerAddress("localhost"))); + } +} 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 4f4d13f7fe..dad91857f2 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 @@ -907,8 +907,6 @@ public void testWriteConcernResolver() { assertThat(lastMongoAction.getEntityClass().toString(), is(PersonWithIdPropertyOfTypeObjectId.class.toString())); assertThat(lastMongoAction.getMongoActionOperation(), is(MongoActionOperation.UPDATE)); assertThat(lastMongoAction.getQuery(), equalTo(q.getQueryObject())); - assertThat(lastMongoAction.getDocument(), equalTo(u.getUpdateObject())); - } private class FsyncSafeWriteConcernResolver implements WriteConcernResolver { 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 7591dc464f..451b4d12ef 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 @@ -115,7 +115,7 @@ public void convertsJodaTimeTypesCorrectly() { DBObject dbObject = new BasicDBObject(); converter.write(person, dbObject); - assertThat(dbObject.get("birthDate"), is(Date.class)); + assertThat(dbObject.get("birthDate"), is(instanceOf(Date.class))); Person result = converter.read(Person.class, dbObject); assertThat(result.birthDate, is(notNullValue())); @@ -176,7 +176,7 @@ public void usesDocumentsStoredTypeIfSubtypeOfRequest() { dbObject.put("birthDate", new LocalDate()); dbObject.put(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Person.class.getName()); - assertThat(converter.read(Contact.class, dbObject), is(Person.class)); + assertThat(converter.read(Contact.class, dbObject), is(instanceOf(Person.class))); } /** @@ -189,7 +189,7 @@ public void ignoresDocumentsStoredTypeIfCompletelyDifferentTypeRequested() { dbObject.put("birthDate", new LocalDate()); dbObject.put(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Person.class.getName()); - assertThat(converter.read(BirthDateContainer.class, dbObject), is(BirthDateContainer.class)); + assertThat(converter.read(BirthDateContainer.class, dbObject), is(instanceOf(BirthDateContainer.class))); } @Test @@ -217,7 +217,7 @@ public void writesEnumsCorrectly() { DBObject result = new BasicDBObject(); converter.write(value, result); - assertThat(result.get("sampleEnum"), is(String.class)); + assertThat(result.get("sampleEnum"), is(instanceOf(String.class))); assertThat(result.get("sampleEnum").toString(), is("FIRST")); } @@ -233,7 +233,7 @@ public void writesEnumCollectionCorrectly() { DBObject result = new BasicDBObject(); converter.write(value, result); - assertThat(result.get("enums"), is(BasicDBList.class)); + assertThat(result.get("enums"), is(instanceOf(BasicDBList.class))); BasicDBList enums = (BasicDBList) result.get("enums"); assertThat(enums.size(), is(1)); @@ -263,7 +263,7 @@ public void readsEnumCollectionsCorrectly() { ClassWithEnumProperty result = converter.read(ClassWithEnumProperty.class, dbObject); - assertThat(result.enums, is(List.class)); + assertThat(result.enums, is(instanceOf(List.class))); assertThat(result.enums.size(), is(1)); assertThat(result.enums, hasItem(SampleEnum.FIRST)); } @@ -328,7 +328,7 @@ public void writesCollectionWithInterfaceCorrectly() { converter.write(wrapper, dbObject); Object result = dbObject.get("contacts"); - assertThat(result, is(BasicDBList.class)); + assertThat(result, is(instanceOf(BasicDBList.class))); BasicDBList contacts = (BasicDBList) result; DBObject personDbObject = (DBObject) contacts.get(0); assertThat(personDbObject.get("foo").toString(), is("Oliver")); @@ -351,7 +351,7 @@ public void readsCollectionWithInterfaceCorrectly() { assertThat(result.contacts, is(notNullValue())); assertThat(result.contacts.size(), is(1)); Contact contact = result.contacts.get(0); - assertThat(contact, is(Person.class)); + assertThat(contact, is(instanceOf(Person.class))); assertThat(((Person) contact).firstname, is("Oliver")); } @@ -365,7 +365,7 @@ public void convertsLocalesOutOfTheBox() { converter.write(wrapper, dbObject); Object localeField = dbObject.get("locale"); - assertThat(localeField, is(String.class)); + assertThat(localeField, is(instanceOf(String.class))); assertThat((String) localeField, is("en_US")); LocaleWrapper read = converter.read(LocaleWrapper.class, dbObject); @@ -473,13 +473,13 @@ public void convertsObjectIdStringsToObjectIdCorrectly() { DBObject dbo1 = new BasicDBObject(); converter.write(p1, dbo1); - assertThat(dbo1.get("_id"), is(String.class)); + assertThat(dbo1.get("_id"), is(instanceOf(String.class))); PersonPojoStringId p2 = new PersonPojoStringId(new ObjectId().toString(), "Text-1"); DBObject dbo2 = new BasicDBObject(); converter.write(p2, dbo2); - assertThat(dbo2.get("_id"), is(ObjectId.class)); + assertThat(dbo2.get("_id"), is(instanceOf(ObjectId.class))); } /** @@ -493,8 +493,8 @@ public void convertsCustomEmptyMapCorrectly() { ClassWithSortedMap result = converter.read(ClassWithSortedMap.class, wrapper); - assertThat(result, is(ClassWithSortedMap.class)); - assertThat(result.map, is(SortedMap.class)); + assertThat(result, is(instanceOf(ClassWithSortedMap.class))); + assertThat(result.map, is(instanceOf(SortedMap.class))); } /** @@ -760,7 +760,7 @@ public void writesPlainMapOfCollectionsCorrectly() { assertThat(result.containsField("Foo"), is(true)); assertThat(result.get("Foo"), is(notNullValue())); - assertThat(result.get("Foo"), is(BasicDBList.class)); + assertThat(result.get("Foo"), is(instanceOf(BasicDBList.class))); BasicDBList list = (BasicDBList) result.get("Foo"); @@ -811,11 +811,11 @@ public void writesArraysAsMapValuesCorrectly() { converter.write(wrapper, result); Object mapObject = result.get("mapOfObjects"); - assertThat(mapObject, is(BasicDBObject.class)); + assertThat(mapObject, is(instanceOf(BasicDBObject.class))); DBObject map = (DBObject) mapObject; Object valueObject = map.get("foo"); - assertThat(valueObject, is(BasicDBList.class)); + assertThat(valueObject, is(instanceOf(BasicDBList.class))); List list = (List) valueObject; assertThat(list.size(), is(1)); @@ -906,7 +906,7 @@ public void writesNullValuesForCollection() { converter.write(wrapper, result); Object contacts = result.get("contacts"); - assertThat(contacts, is(Collection.class)); + assertThat(contacts, is(instanceOf(Collection.class))); assertThat(((Collection) contacts).size(), is(2)); assertThat(((Collection) contacts), hasItem(nullValue())); } @@ -969,7 +969,7 @@ public void writesListForObjectPropertyCorrectly() { Item read = converter.read(Item.class, result); assertThat(read.attributes.size(), is(1)); assertThat(read.attributes.get(0).key, is(attribute.key)); - assertThat(read.attributes.get(0).value, is(Collection.class)); + assertThat(read.attributes.get(0).value, is(instanceOf(Collection.class))); @SuppressWarnings("unchecked") Collection values = (Collection) read.attributes.get(0).value; @@ -1028,11 +1028,11 @@ public void convertsSetToBasicDBList() { address.street = "Foo"; Object result = converter.convertToMongoType(Collections.singleton(address)); - assertThat(result, is(BasicDBList.class)); + assertThat(result, is(instanceOf(BasicDBList.class))); Set readResult = converter.read(Set.class, (BasicDBList) result); assertThat(readResult.size(), is(1)); - assertThat(readResult.iterator().next(), is(Map.class)); + assertThat(readResult.iterator().next(), is(instanceOf(Map.class))); } /** diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java index df042827d0..37adfee426 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java @@ -84,7 +84,7 @@ public void convertsStringIntoObjectId() { DBObject query = new BasicDBObject("_id", new ObjectId().toString()); DBObject result = mapper.getMappedObject(query, null); - assertThat(result.get("_id"), is(ObjectId.class)); + assertThat(result.get("_id"), is(instanceOf(ObjectId.class))); } @Test @@ -114,9 +114,9 @@ public void handlesObjectIdCapableBigIntegerIdsCorrectly() { DBObject result = mapper.getMappedObject(criteria.getCriteriaObject(), context.getPersistentEntity(Sample.class)); Object object = result.get("_id"); - assertThat(object, is(DBObject.class)); + assertThat(object, is(instanceOf(DBObject.class))); DBObject dbObject = (DBObject) object; - assertThat(dbObject.get("$ne"), is(ObjectId.class)); + assertThat(dbObject.get("$ne"), is(instanceOf(ObjectId.class))); } /** @@ -128,7 +128,7 @@ public void handlesEnumsCorrectly() { DBObject result = mapper.getMappedObject(query.getQueryObject(), null); Object object = result.get("foo"); - assertThat(object, is(String.class)); + assertThat(object, is(instanceOf(String.class))); } @Test @@ -137,10 +137,10 @@ public void handlesEnumsInNotEqualCorrectly() { DBObject result = mapper.getMappedObject(query.getQueryObject(), null); Object object = result.get("foo"); - assertThat(object, is(DBObject.class)); + assertThat(object, is(instanceOf(DBObject.class))); Object ne = ((DBObject) object).get("$ne"); - assertThat(ne, is(String.class)); + assertThat(ne, is(instanceOf(String.class))); assertThat(ne.toString(), is(Enum.INSTANCE.name())); } @@ -151,14 +151,14 @@ public void handlesEnumsInNotEqualCorrectly() { DBObject result = mapper.getMappedObject(query.getQueryObject(), null); Object object = result.get("foo"); - assertThat(object, is(DBObject.class)); + assertThat(object, is(instanceOf(DBObject.class))); Object in = ((DBObject) object).get("$in"); - assertThat(in, is(BasicDBList.class)); + assertThat(in, is(instanceOf(BasicDBList.class))); BasicDBList list = (BasicDBList) in; assertThat(list.size(), is(1)); - assertThat(list.get(0), is(String.class)); + assertThat(list.get(0), is(instanceOf(String.class))); assertThat(list.get(0).toString(), is(Enum.INSTANCE.name())); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializerUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializerUnitTests.java index 1b36291f19..db2d8ed99d 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializerUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializerUnitTests.java @@ -77,12 +77,12 @@ public void convertsComplexObjectOnSerializing() { address.zipCode = "01234"; DBObject result = serializer.asDBObject("foo", address); - assertThat(result, is(BasicDBObject.class)); + assertThat(result, is(instanceOf(BasicDBObject.class))); BasicDBObject dbObject = (BasicDBObject) result; Object value = dbObject.get("foo"); assertThat(value, is(notNullValue())); - assertThat(value, is(BasicDBObject.class)); + assertThat(value, is(instanceOf(BasicDBObject.class))); Object reference = converter.convertToMongoType(address); assertThat(value, is(reference)); From a41b877081c0b6d75ad9e86ac8e4ebcd0c1dd54c Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 20 Jun 2012 12:23:32 +0200 Subject: [PATCH 10/49] DATAMONGO-455 - Documentation mentions BasicQuery. --- src/docbkx/reference/mongodb.xml | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/docbkx/reference/mongodb.xml b/src/docbkx/reference/mongodb.xml index 0e822369b3..e0285d037d 100644 --- a/src/docbkx/reference/mongodb.xml +++ b/src/docbkx/reference/mongodb.xml @@ -624,7 +624,7 @@ public class MongoConfiguration { } - +
@@ -686,7 +686,7 @@ public class MongoConfiguration { <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> </bean> - +
@@ -1546,8 +1546,17 @@ assertThat(p.getAge(), is(1)); follow a fluent API style so that you can easily chain together multiple method criteria and queries while having easy to understand code. Static imports in Java are used to help remove the need to see the 'new' keyword - for creating Query and Criteria instances so as to improve - readability.
+ for creating Query and + Criteria instances so as to improve readability. If + you like to create Query instances from a plain + JSON String use BasicQuery. + + + Creating a Query instance from a plain JSON String + + BasicQuery query = new BasicQuery("{ age : { $lt : 50 }, accounts.balance : { $gt : 1000.00 }}"); +List<Person> result = mongoTemplate.find(query, Person.class); + GeoSpatial queries are also supported and are described more in the section GeoSpatial Queries. @@ -1572,10 +1581,10 @@ assertThat(p.getAge(), is(1)); import static org.springframework.data.mongodb.core.query.Criteria.where; import static org.springframework.data.mongodb.core.query.Query.query; - ... +… - List<Person> result = mongoTemplate.find(query(where("age").lt(50).and("accounts.balance").gt(1000.00d)), Person.class); - +List<Person> result = mongoTemplate.find(query(where("age").lt(50) + .and("accounts.balance").gt(1000.00d)), Person.class); All find methods take a Query object as a @@ -1769,7 +1778,7 @@ import static org.springframework.data.mongodb.core.query.Query.query; Criteria withinBox (Box box) Creates a geospatial criterion using a $within $box operation - + @@ -2722,4 +2731,4 @@ mongoTemplate.dropCollection("MyNewCollection"); } }); - \ No newline at end of file + From 416dc563f2a0d8f7037a71f150e41de1a75692b2 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 20 Jun 2012 12:24:27 +0200 Subject: [PATCH 11/49] DATAMONGO-463 - Update reference documentation to point to 1.0.2.RELEASE JARS. --- 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..883db5e1bf 100644 --- a/src/docbkx/reference/mongodb.xml +++ b/src/docbkx/reference/mongodb.xml @@ -251,7 +251,7 @@ public class MongoApp { - spring-data-mongodb-1.0.0.RELEASE.jar + spring-data-mongodb-1.0.2.RELEASE.jar From b5b11772b6e95d2c85e72b8f88b79d89088109e7 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 20 Jun 2012 12:36:48 +0200 Subject: [PATCH 12/49] DATAMONGO-463 - Prepare 1.0.2 release. Polished pom and updated changelog. --- spring-data-mongodb-parent/pom.xml | 95 +----------------------------- src/main/resources/changelog.txt | 28 +++++++++ 2 files changed, 30 insertions(+), 93 deletions(-) diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index fa074ce756..af246b6899 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -96,42 +96,6 @@ - - - strict - - false - - - - fast - - true - true - - - - staging - - - spring-site-staging - file:///${java.io.tmpdir}/spring-data/mongodb/docs - - - spring-milestone-staging - file:///${java.io.tmpdir}/spring-data/mongodb/milestone - - - spring-snapshot-staging - file:///${java.io.tmpdir}/spring-data/mongodb/snapshot - - - - - bootstrap - - - http://www.springsource.com/download/community @@ -260,24 +224,6 @@ log4j log4j ${log4j.version} - - - javax.mail - mail - - - javax.jms - jms - - - com.sun.jdmk - jmxtools - - - com.sun.jmx - jmxri - - runtime @@ -347,48 +293,11 @@ 3.1.0.RELEASE - - - ${project.basedir}/src/main/java - - **/* - - - **/*.java - - - - ${project.basedir}/src/main/resources - - **/* - - - - - - ${project.basedir}/src/test/java - - **/* - - - **/*.java - - - - ${project.basedir}/src/test/resources - - **/* - - - **/*.java - - - org.apache.maven.plugins maven-compiler-plugin - 2.3.2 + 2.4 1.5 1.5 @@ -408,7 +317,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.8 + 2.10 false diff --git a/src/main/resources/changelog.txt b/src/main/resources/changelog.txt index 868868ba80..74b93ac765 100644 --- a/src/main/resources/changelog.txt +++ b/src/main/resources/changelog.txt @@ -1,6 +1,34 @@ Spring Data Document Changelog ============================================= +Changes in version 1.0.2.RELEASE MongoDB (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-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.0.1.RELEASE MongoDB (2012-02-11) ----------------------------------------------------- ** Bug From 7e3dfa5504ddc517f47620a690609c10a7381a0e Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 20 Jun 2012 12:48:14 +0200 Subject: [PATCH 13/49] DATAMONGO-463 - Polished pom. Upgrade to Log4J 1.2.16 to remove the need for the exclusions. Replaced ${pom.version} with ${project.version}. --- pom.xml | 2 +- spring-data-mongodb-parent/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c267f367b4..5468908153 100644 --- a/pom.xml +++ b/pom.xml @@ -151,7 +151,7 @@ version - ${pom.version} + ${project.version} diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index af246b6899..a7270d63c3 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -12,7 +12,7 @@ UTF-8 4.10 - 1.2.15 + 1.2.16 1.8.4 1.2.1 1.5.10 From 80ee7d95530e61b6f869affc420a40f2a4582d45 Mon Sep 17 00:00:00 2001 From: Spring Buildmaster Date: Wed, 20 Jun 2012 03:53:28 -0700 Subject: [PATCH 14/49] DATAMONGO-463 - Release 1.0.2.RELEASE. --- pom.xml | 2 +- spring-data-mongodb-cross-store/pom.xml | 2 +- spring-data-mongodb-log4j/pom.xml | 2 +- spring-data-mongodb-parent/pom.xml | 4 ++-- spring-data-mongodb/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 5468908153..1afe12755e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Distribution Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.2.BUILD-SNAPSHOT + 1.0.2.RELEASE pom spring-data-mongodb diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index 384fcd12d2..ead6c33606 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.0.2.BUILD-SNAPSHOT + 1.0.2.RELEASE ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-cross-store diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index e04deca560..c28d97f598 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.0.2.BUILD-SNAPSHOT + 1.0.2.RELEASE ../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 a7270d63c3..09289615da 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Parent Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.2.BUILD-SNAPSHOT + 1.0.2.RELEASE pom UTF-8 @@ -198,7 +198,7 @@ org.springframework.data spring-data-mongodb - 1.0.2.BUILD-SNAPSHOT + 1.0.2.RELEASE diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 6332136323..ad43b861f3 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.0.2.BUILD-SNAPSHOT + 1.0.2.RELEASE ../spring-data-mongodb-parent/pom.xml spring-data-mongodb From dad078935668e6988d66e3eb436c6a3a24d9b21a Mon Sep 17 00:00:00 2001 From: Spring Buildmaster Date: Wed, 20 Jun 2012 03:53:31 -0700 Subject: [PATCH 15/49] DATAMONGO-463 - Prepare next development iteration. --- pom.xml | 2 +- spring-data-mongodb-cross-store/pom.xml | 2 +- spring-data-mongodb-log4j/pom.xml | 2 +- spring-data-mongodb-parent/pom.xml | 4 ++-- spring-data-mongodb/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 1afe12755e..9818c57504 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Distribution Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.2.RELEASE + 1.0.3.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 ead6c33606..de608054ba 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.0.2.RELEASE + 1.0.3.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-cross-store diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index c28d97f598..5b927bc833 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.0.2.RELEASE + 1.0.3.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 09289615da..fcae5f57a8 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Parent Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.2.RELEASE + 1.0.3.BUILD-SNAPSHOT pom UTF-8 @@ -198,7 +198,7 @@ org.springframework.data spring-data-mongodb - 1.0.2.RELEASE + 1.0.3.BUILD-SNAPSHOT diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index ad43b861f3..5646e7822b 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.0.2.RELEASE + 1.0.3.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb From 1be1297ef9ffa42578c2cacf9c4100256c7adfc3 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 22 Jun 2012 15:14:37 +0200 Subject: [PATCH 16/49] DATAMONGO-466 - QueryMapper now only tries id conversion for top level document. So far the QueryMapper has tried to map id properties of nested documents to ObjectIds which it shouldn't do actually. --- .../data/mongodb/core/QueryMapper.java | 6 +++- .../core/query/QueryMapperUnitTests.java | 29 +++++++++++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java index cefb06821f..62305d6e31 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java @@ -141,7 +141,11 @@ private Object convertSimpleOrDBObject(Object source, MongoPersistentEntity e */ private boolean isIdKey(String key, MongoPersistentEntity entity) { - if (null != entity && entity.getIdProperty() != null) { + if (entity == null) { + return false; + } + + if (entity.getIdProperty() != null) { MongoPersistentProperty idProperty = entity.getIdProperty(); return idProperty.getName().equals(key) || idProperty.getFieldName().equals(key); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java index 37adfee426..a461f5339a 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java @@ -83,7 +83,7 @@ public void translatesIdPropertyIntoIdKey() { public void convertsStringIntoObjectId() { DBObject query = new BasicDBObject("_id", new ObjectId().toString()); - DBObject result = mapper.getMappedObject(query, null); + DBObject result = mapper.getMappedObject(query, context.getPersistentEntity(IdWrapper.class)); assertThat(result.get("_id"), is(instanceOf(ObjectId.class))); } @@ -91,7 +91,7 @@ public void convertsStringIntoObjectId() { public void handlesBigIntegerIdsCorrectly() { DBObject dbObject = new BasicDBObject("id", new BigInteger("1")); - DBObject result = mapper.getMappedObject(dbObject, null); + DBObject result = mapper.getMappedObject(dbObject, context.getPersistentEntity(IdWrapper.class)); assertThat(result.get("_id"), is((Object) "1")); } @@ -100,7 +100,7 @@ public void handlesObjectIdCapableBigIntegerIdsCorrectly() { ObjectId id = new ObjectId(); DBObject dbObject = new BasicDBObject("id", new BigInteger(id.toString(), 16)); - DBObject result = mapper.getMappedObject(dbObject, null); + DBObject result = mapper.getMappedObject(dbObject, context.getPersistentEntity(IdWrapper.class)); assertThat(result.get("_id"), is((Object) id)); } @@ -198,6 +198,29 @@ public void transformsArraysCorrectly() { assertThat(result, is(query.getQueryObject())); } + @Test + public void doesNotHandleNestedFieldsWithDefaultIdNames() { + + BasicDBObject dbObject = new BasicDBObject("id", new ObjectId().toString()); + dbObject.put("nested", new BasicDBObject("id", new ObjectId().toString())); + + MongoPersistentEntity entity = context.getPersistentEntity(ClassWithDefaultId.class); + + 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))); + } + + class IdWrapper { + Object id; + } + + class ClassWithDefaultId { + + String id; + ClassWithDefaultId nested; + } + class Sample { @Id From 43dee69fe0301ef6609f1962af97333c15913a1b Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 25 Jun 2012 11:16:31 +0200 Subject: [PATCH 17/49] DATAMONGO-464 - Fixed resource synchronization in MongoDbUtils. MongoDbUtils now correctly returns DB instances for others than the first one bound. So far the lookup for an alternate database resulted in the first one bound to be returned. --- .../data/mongodb/core/MongoDbUtils.java | 11 ++-- .../mongodb/core/MongoDbUtilsUnitTests.java | 65 +++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoDbUtilsUnitTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java index 6dfdc09916..0826e25f42 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java @@ -15,14 +15,15 @@ */ package org.springframework.data.mongodb.core; -import com.mongodb.DB; -import com.mongodb.Mongo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.data.mongodb.CannotGetMongoDbConnectionException; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; +import com.mongodb.DB; +import com.mongodb.Mongo; + /** * Helper class featuring helper methods for internal MongoDb classes. *

@@ -78,7 +79,7 @@ public static DB doGetDB(Mongo mongo, String databaseName, String username, char DB db = null; if (TransactionSynchronizationManager.isSynchronizationActive() && dbHolder.doesNotHoldNonDefaultDB()) { // Spring transaction management is active -> - db = dbHolder.getDB(); + db = dbHolder.getDB(databaseName); if (db != null && !dbHolder.isSynchronizedWithTransaction()) { LOGGER.debug("Registering Spring transaction synchronization for existing Mongo DB"); TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(dbHolder, mongo)); @@ -110,9 +111,9 @@ public static DB doGetDB(Mongo mongo, String databaseName, String username, char LOGGER.debug("Registering Spring transaction synchronization for new Hibernate Session"); DbHolder holderToUse = dbHolder; if (holderToUse == null) { - holderToUse = new DbHolder(db); + holderToUse = new DbHolder(databaseName, db); } else { - holderToUse.addDB(db); + holderToUse.addDB(databaseName, db); } TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo)); holderToUse.setSynchronizedWithTransaction(true); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoDbUtilsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoDbUtilsUnitTests.java new file mode 100644 index 0000000000..571e82b92b --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoDbUtilsUnitTests.java @@ -0,0 +1,65 @@ +/* + * 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.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import com.mongodb.DB; +import com.mongodb.Mongo; + +/** + * Unit tests for {@link MongoDbUtils}. + * + * @author Oliver Gierke + */ +public class MongoDbUtilsUnitTests { + + Mongo mongo; + + @Before + public void setUp() throws Exception { + this.mongo = new Mongo(); + TransactionSynchronizationManager.initSynchronization(); + } + + @After + public void tearDown() { + + for (Object key : TransactionSynchronizationManager.getResourceMap().keySet()) { + TransactionSynchronizationManager.unbindResource(key); + } + + TransactionSynchronizationManager.clearSynchronization(); + } + + @Test + public void returnsNewInstanceForDifferentDatabaseName() { + + DB first = MongoDbUtils.getDB(mongo, "first"); + assertThat(first, is(notNullValue())); + assertThat(MongoDbUtils.getDB(mongo, "first"), is(first)); + + DB second = MongoDbUtils.getDB(mongo, "second"); + assertThat(second, is(not(first))); + assertThat(MongoDbUtils.getDB(mongo, "second"), is(second)); + } +} From ba81f21aba589d1124abb2bdf713969dd031299c Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 25 Jun 2012 13:07:10 +0200 Subject: [PATCH 18/49] DATAMONGO-467 - Fix identifier handling for Querydsl. As we try to massage the value of the id property into an ObjectId if possible we need to do so as well when mapping the Querydsl query. Adapted SpringDataMongoDbSerializer accordingly. --- .../support/QueryDslMongoRepository.java | 7 ++++++ .../SpringDataMongodbSerializerUnitTests.java | 23 ++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QueryDslMongoRepository.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QueryDslMongoRepository.java index 8980ddabf1..4370c31f6a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QueryDslMongoRepository.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QueryDslMongoRepository.java @@ -28,6 +28,7 @@ import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.QueryMapper; import org.springframework.data.mongodb.core.convert.MongoConverter; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; @@ -235,6 +236,7 @@ static class SpringDataMongodbSerializer extends MongodbSerializer { private final MongoConverter converter; private final MappingContext, MongoPersistentProperty> mappingContext; + private final QueryMapper mapper; /** * Creates a new {@link SpringDataMongodbSerializer} for the given {@link MappingContext}. @@ -244,6 +246,7 @@ static class SpringDataMongodbSerializer extends MongodbSerializer { public SpringDataMongodbSerializer(MongoConverter converter) { this.mappingContext = converter.getMappingContext(); this.converter = converter; + this.mapper = new QueryMapper(converter); } @Override @@ -258,6 +261,10 @@ protected String getKeyForPath(Path expr, PathMetadata metadata) { @Override protected DBObject asDBObject(String key, Object value) { + if ("_id".equals(key)) { + return super.asDBObject(key, mapper.convertId(value)); + } + return super.asDBObject(key, value instanceof Pattern ? value : converter.convertToMongoType(value)); } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializerUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializerUnitTests.java index db2d8ed99d..56505eb54c 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializerUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializerUnitTests.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. @@ -18,6 +18,7 @@ import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; +import org.bson.types.ObjectId; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,6 +35,8 @@ import com.mongodb.BasicDBObject; import com.mongodb.DBObject; +import com.mysema.query.types.expr.BooleanOperation; +import com.mysema.query.types.path.PathBuilder; import com.mysema.query.types.path.StringPath; /** @@ -98,7 +101,25 @@ public void returnsEmptyStringIfNoPathExpressionIsGiven() { assertThat(serializer.getKeyForPath(address, address.getMetadata()), is("")); } + /** + * @see DATAMONGO-467 + */ + @Test + public void convertsIdPropertyCorrectly() { + + ObjectId id = new ObjectId(); + + PathBuilder

builder = new PathBuilder
(Address.class, "address"); + StringPath idPath = builder.getString("id"); + + DBObject result = (DBObject) serializer.visit((BooleanOperation) idPath.eq(id.toString()), (Void) null); + assertThat(result.get("_id"), is(notNullValue())); + assertThat(result.get("_id"), is(instanceOf(ObjectId.class))); + assertThat(result.get("_id"), is((Object) id)); + } + class Address { + String id; String street; @Field("zip_code") String zipCode; From 0aacb887de55eb4a85376ff0d8f0e96be66f88b0 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 26 Jun 2012 13:30:00 +0200 Subject: [PATCH 19/49] =?UTF-8?q?DATAMONGO-470=20-=20Implemented=20equals(?= =?UTF-8?q?=E2=80=A6)=20and=20hashCode()=20for=20Query=20and=20Criteria.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/mongodb/core/query/Criteria.java | 70 +++++++++++++++++-- .../data/mongodb/core/query/Query.java | 47 +++++++++++++ 2 files changed, 112 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 4ce58f14a9..14e0c16554 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 @@ -15,6 +15,8 @@ */ package org.springframework.data.mongodb.core.query; +import static org.springframework.util.ObjectUtils.*; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -29,6 +31,7 @@ import org.springframework.data.mongodb.core.geo.Point; import org.springframework.data.mongodb.core.geo.Shape; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; @@ -429,11 +432,9 @@ public String getKey() { } /* - * (non-Javadoc) - * - * @see org.springframework.datastore.document.mongodb.query.Criteria# - * getCriteriaObject(java.lang.String) - */ + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.query.CriteriaDefinition#getCriteriaObject() + */ public DBObject getCriteriaObject() { if (this.criteriaChain.size() == 1) { return criteriaChain.get(0).getSingleCriteriaObject(); @@ -496,4 +497,63 @@ private void setValue(DBObject dbo, String key, Object value) { } } + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + + if (obj == null || !getClass().equals(obj.getClass())) { + return false; + } + + 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); + + return keyEqual && criteriaEqual && valueEqual; + } + + /** + * Checks the given objects for equality. Handles {@link Pattern} and arrays correctly. + * + * @param left + * @param right + * @return + */ + private boolean isEqual(Object left, Object right) { + + if (left == null) { + return right == null; + } + + if (left instanceof Pattern) { + return right instanceof Pattern ? ((Pattern) left).pattern().equals(((Pattern) right).pattern()) : false; + } + + return ObjectUtils.nullSafeEquals(left, right); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + + int result = 17; + + result += nullSafeHashCode(key); + result += criteria.hashCode(); + result += nullSafeHashCode(isValue); + + return result; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java index 58798acaf9..b24015bf20 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java @@ -16,6 +16,7 @@ package org.springframework.data.mongodb.core.query; import static org.springframework.data.mongodb.core.SerializationUtils.*; +import static org.springframework.util.ObjectUtils.*; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -152,4 +153,50 @@ public String toString() { return String.format("Query: %s, Fields: %s, Sort: %s", serializeToJsonSafely(getQueryObject()), serializeToJsonSafely(getFieldsObject()), serializeToJsonSafely(getSortObject())); } + + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + + if (obj == null || !getClass().equals(obj.getClass())) { + return false; + } + + Query that = (Query) obj; + + boolean criteriaEqual = this.criteria.equals(that.criteria); + boolean fieldsEqual = this.fieldSpec == null ? that.fieldSpec == null : this.fieldSpec.equals(that.fieldSpec); + boolean sortEqual = this.sort == null ? that.sort == null : this.sort.equals(that.sort); + boolean hintEqual = this.hint == null ? that.hint == null : this.hint.equals(that.hint); + boolean skipEqual = this.skip == that.skip; + boolean limitEqual = this.limit == that.limit; + + return criteriaEqual && fieldsEqual && sortEqual && hintEqual && skipEqual && limitEqual; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + + int result = 17; + + result += 31 * criteria.hashCode(); + result += 31 * nullSafeHashCode(fieldSpec); + result += 31 * nullSafeHashCode(sort); + result += 31 * nullSafeHashCode(hint); + result += 31 * skip; + result += 31 * limit; + + return result; + } } From 5cf7a86023ab153901575d5722c16ae175e31c26 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 26 Jun 2012 13:44:22 +0200 Subject: [PATCH 20/49] DATAMONGO-469 - Fixed parsing of And keyword in derived queries. --- .../repository/query/MongoQueryCreator.java | 8 +--- .../query/MongoQueryCreatorUnitTests.java | 41 +++++++++++-------- 2 files changed, 27 insertions(+), 22 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 1fe9bd706c..4b47696c39 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 @@ -116,13 +116,9 @@ protected Criteria and(Part part, Criteria base, Iterator iterator) { return create(part, iterator); } - PersistentPropertyPath path2 = context.getPersistentPropertyPath(part.getProperty()); - - Criteria criteria = from(part.getType(), - where(path2.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)), + PersistentPropertyPath path = context.getPersistentPropertyPath(part.getProperty()); + return from(part.getType(), where(path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)), (PotentiallyConvertingIterator) iterator); - - return criteria.andOperator(criteria); } /* diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java index e5a2216104..29e9f48306 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java @@ -82,12 +82,22 @@ public void createsQueryCorrectly() throws Exception { PartTree tree = new PartTree("findByFirstName", Person.class); MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "Oliver"), context); + Query query = creator.createQuery(); + assertThat(query, is(query(where("firstName").is("Oliver")))); + } - creator.createQuery(); + /** + * @see DATAMONGO-469 + */ + @Test + public void createsAndQueryCorrectly() { + + Person person = new Person(); + MongoQueryCreator creator = new MongoQueryCreator(new PartTree("findByFirstNameAndFriend", Person.class), + getAccessor(converter, "Oliver", person), context); + Query query = creator.createQuery(); - creator = new MongoQueryCreator(new PartTree("findByFirstNameAndFriend", Person.class), getAccessor(converter, - "Oliver", new Person()), context); - creator.createQuery(); + assertThat(query, is(query(where("firstName").is("Oliver").and("friend").is(person)))); } @Test @@ -96,7 +106,7 @@ public void createsNotNullQueryCorrectly() { PartTree tree = new PartTree("findByFirstNameNotNull", Person.class); Query query = new MongoQueryCreator(tree, getAccessor(converter), context).createQuery(); - assertThat(query.getQueryObject(), is(new Query(Criteria.where("firstName").ne(null)).getQueryObject())); + assertThat(query, is(new Query(Criteria.where("firstName").ne(null)))); } @Test @@ -105,7 +115,7 @@ public void createsIsNullQueryCorrectly() { PartTree tree = new PartTree("findByFirstNameIsNull", Person.class); Query query = new MongoQueryCreator(tree, getAccessor(converter), context).createQuery(); - assertThat(query.getQueryObject(), is(new Query(Criteria.where("firstName").is(null)).getQueryObject())); + assertThat(query, is(new Query(Criteria.where("firstName").is(null)))); } @Test @@ -137,7 +147,7 @@ public void createsLessThanEqualQueryCorrectly() throws Exception { MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, 18), context); Query reference = query(where("age").lte(18)); - assertThat(creator.createQuery().getQueryObject(), is(reference.getQueryObject())); + assertThat(creator.createQuery(), is(reference)); } @Test @@ -147,7 +157,7 @@ public void createsGreaterThanEqualQueryCorrectly() throws Exception { MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, 18), context); Query reference = query(where("age").gte(18)); - assertThat(creator.createQuery().getQueryObject(), is(reference.getQueryObject())); + assertThat(creator.createQuery(), is(reference)); } /** @@ -160,7 +170,7 @@ public void honoursMappingInformationForPropertyPaths() { MongoQueryCreator creator = new MongoQueryCreator(partTree, getAccessor(converter, "Oliver"), context); Query reference = query(where("foo").is("Oliver")); - assertThat(creator.createQuery().getQueryObject(), is(reference.getQueryObject())); + assertThat(creator.createQuery(), is(reference)); } /** @@ -172,7 +182,7 @@ public void createsExistsClauseCorrectly() { PartTree tree = new PartTree("findByAgeExists", Person.class); MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, true), context); Query query = query(where("age").exists(true)); - assertThat(creator.createQuery().getQueryObject(), is(query.getQueryObject())); + assertThat(creator.createQuery(), is(query)); } /** @@ -184,7 +194,7 @@ public void createsRegexClauseCorrectly() { PartTree tree = new PartTree("findByFirstNameRegex", Person.class); MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, ".*"), context); Query query = query(where("firstName").regex(".*")); - assertThat(creator.createQuery().getQueryObject(), is(query.getQueryObject())); + assertThat(creator.createQuery(), is(query)); } /** @@ -196,7 +206,7 @@ public void createsTrueClauseCorrectly() { PartTree tree = new PartTree("findByActiveTrue", Person.class); MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter), context); Query query = query(where("active").is(true)); - assertThat(creator.createQuery().getQueryObject(), is(query.getQueryObject())); + assertThat(creator.createQuery(), is(query)); } /** @@ -208,7 +218,7 @@ public void createsFalseClauseCorrectly() { PartTree tree = new PartTree("findByActiveFalse", Person.class); MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter), context); Query query = query(where("active").is(false)); - assertThat(creator.createQuery().getQueryObject(), is(query.getQueryObject())); + assertThat(creator.createQuery(), is(query)); } /** @@ -221,8 +231,7 @@ public void createsOrQueryCorrectly() { MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "Dave", 42), context); Query query = creator.createQuery(); - assertThat(query.getQueryObject(), - is(query(new Criteria().orOperator(where("firstName").is("Dave"), where("age").is(42))).getQueryObject())); + assertThat(query, is(query(new Criteria().orOperator(where("firstName").is("Dave"), where("age").is(42))))); } private void assertBindsDistanceToQuery(Point point, Distance distance, Query reference) throws Exception { @@ -240,7 +249,7 @@ private void assertBindsDistanceToQuery(Point point, Distance distance, Query re Query query = new MongoQueryCreator(tree, new ConvertingParameterAccessor(converter, accessor), context) .createQuery(); - assertThat(query.getQueryObject(), is(query.getQueryObject())); + assertThat(query, is(query)); } interface PersonRepository extends Repository { From e41299ff38adcf4ee0605f7043d3d9367440d861 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 16 Jul 2012 14:55:32 +0200 Subject: [PATCH 21/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 438829518d..0aa615e8dc 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 @@ -334,11 +334,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); @@ -1015,8 +1016,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); @@ -1067,7 +1070,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 134e7762a764e620dc37bbeb783c8ef057e83385 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 16 Jul 2012 16:33:18 +0200 Subject: [PATCH 22/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 0aa615e8dc..5a3fa9660e 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 @@ -998,22 +998,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]", @@ -1044,7 +1032,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 @@ -1073,18 +1061,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 + "]"); @@ -1556,6 +1535,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 7a9ba3fe3e8fbefe77a7d55245006a40d62f1335 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 16 Jul 2012 17:42:37 +0200 Subject: [PATCH 23/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 883db5e1bf..8fd34cea33 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 a82fbade951bd36b9406c26489b06d9028ad33e7 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 16 Jul 2012 18:22:11 +0200 Subject: [PATCH 24/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 a2f739fd3b..32cb73ae73 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..b8c8c65332 --- /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.afterPropertiesSet(); + + 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 2e6a9a6ee7afd654a89d85093572be1134f74b81 Mon Sep 17 00:00:00 2001 From: Amol Nayak Date: Wed, 11 Jul 2012 00:18:12 +0530 Subject: [PATCH 25/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 | 116 +++++++++++++++++- 2 files changed, 143 insertions(+), 21 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 5a3fa9660e..e427962cc4 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 @@ -109,6 +109,7 @@ * @author Graeme Rocher * @author Mark Pollack * @author Oliver Gierke + * @author Amol Nayak */ public class MongoTemplate implements MongoOperations, ApplicationContextAware { @@ -734,11 +735,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); } }); @@ -757,11 +760,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; } }); @@ -788,11 +793,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); } }); @@ -880,7 +887,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 */ @@ -1171,7 +1178,7 @@ protected void maybeEmitEvent(MongoMappingEvent event) { /** * Create the specified collection using the provided options - * + * * @param collectionName * @param collectionOptions * @return the collection that was created @@ -1193,7 +1200,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 @@ -1218,7 +1225,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 @@ -1248,7 +1255,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 @@ -1287,7 +1294,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. @@ -1334,7 +1341,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 */ @@ -1387,7 +1394,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 @@ -1510,9 +1517,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 dad91857f2..293529c121 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. @@ -39,6 +39,7 @@ import org.springframework.beans.factory.annotation.Autowired; 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; @@ -71,6 +72,7 @@ * * @author Oliver Gierke * @author Thomas Risberg + * @author Amol Nayak */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:infrastructure.xml") @@ -160,6 +162,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 { @@ -190,7 +298,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)); @@ -932,7 +1040,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 { @@ -1095,7 +1203,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 c7995eb462dcd33ee90d61d7beb20585d2e8d181 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 17 Jul 2012 12:46:34 +0200 Subject: [PATCH 26/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 451b4d12ef..49b05d912f 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 @@ -1059,6 +1059,42 @@ public void writesURLsAsStringsByDefault() throws Exception { assertThat(sink.get("url"), is((Object) "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)); + } + static class GenericType { T content; } @@ -1194,6 +1230,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 09ed4aaf240125b247f22840a7356ba3e97c92e1 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 23 Jul 2012 16:41:28 +0200 Subject: [PATCH 27/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 | 4 ++-- .../MappingMongoConverterUnitTests.java | 22 +++++++++++++++++++ 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 da069ad6f1..759d2f74ea 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 @@ -728,7 +728,7 @@ protected Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, St * @return the converted {@link Collections}, will never be {@literal null}. */ @SuppressWarnings("unchecked") - private Collection readCollectionOrArray(TypeInformation targetType, BasicDBList sourceValue) { + private Object readCollectionOrArray(TypeInformation targetType, BasicDBList sourceValue) { Assert.notNull(targetType); @@ -750,7 +750,7 @@ private Collection readCollectionOrArray(TypeInformation targetType, Basic } } - return items; + return getPotentiallyConvertedSimpleRead(items, targetType.getType()); } /** 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 49b05d912f..5c31cec921 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 @@ -1095,6 +1095,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))); + } + static class GenericType { T content; } @@ -1156,6 +1177,7 @@ static class ClassWithMapProperty { Map map; Map> mapOfLists; Map mapOfObjects; + Map mapOfStrings; } static class ClassWithNestedMaps { From 356e6acd431d33f6c0514148727d1324af357e91 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 24 Jul 2012 13:30:04 +0200 Subject: [PATCH 28/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 | 44 ++++++++++++++++--- 2 files changed, 39 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 e427962cc4..d4e9d4c7db 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 @@ -1362,7 +1362,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 42853ab727..23413fbfa9 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 @@ -20,6 +20,7 @@ import static org.mockito.Mockito.*; import java.math.BigInteger; +import java.util.regex.Pattern; import org.bson.types.ObjectId; import org.junit.Before; @@ -136,6 +137,31 @@ public void autogeneratesIdForEntityWithAutogeneratableId() { assertThat(entity.id, is(notNullValue())); } + /** + * @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 @@ -146,6 +172,10 @@ class NotAutogenerateableId { @Id Integer id; + + public Pattern getId() { + return Pattern.compile("."); + } } /** @@ -161,9 +191,10 @@ private MongoTemplate mockOutGetDb() { return template; } - /* (non-Javadoc) - * @see org.springframework.data.mongodb.core.core.MongoOperationsUnitTests#getOperations() - */ + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.MongoOperationsUnitTests#getOperationsForExceptionHandling() + */ @Override protected MongoOperations getOperationsForExceptionHandling() { MongoTemplate template = spy(this.template); @@ -171,9 +202,10 @@ protected MongoOperations getOperationsForExceptionHandling() { return template; } - /* (non-Javadoc) - * @see org.springframework.data.mongodb.core.core.MongoOperationsUnitTests#getOperations() - */ + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.MongoOperationsUnitTests#getOperations() + */ @Override protected MongoOperations getOperations() { return this.template; From 30a4682369c8b943a8206ce1fd5e009c16e0985c Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 24 Jul 2012 15:34:33 +0200 Subject: [PATCH 29/49] DATAMONGO-492 - Prepare changelog for 1.0.3.RELEASE. --- src/main/resources/changelog.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/resources/changelog.txt b/src/main/resources/changelog.txt index 74b93ac765..dc587108ac 100644 --- a/src/main/resources/changelog.txt +++ b/src/main/resources/changelog.txt @@ -1,6 +1,23 @@ Spring Data Document Changelog ============================================= +** 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 MongoDB (2012-06-20) ----------------------------------------------------- ** Bug From 9375e7b9818c06f38429c5f9c0cd18d0d430551b Mon Sep 17 00:00:00 2001 From: Spring Buildmaster Date: Tue, 24 Jul 2012 07:01:21 -0700 Subject: [PATCH 30/49] DATAMONGO-492 - Release 1.0.3.RELEASE. --- pom.xml | 2 +- spring-data-mongodb-cross-store/pom.xml | 2 +- spring-data-mongodb-log4j/pom.xml | 2 +- spring-data-mongodb-parent/pom.xml | 4 ++-- spring-data-mongodb/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 9818c57504..5f8cc63fd1 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Distribution Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.3.BUILD-SNAPSHOT + 1.0.3.RELEASE pom spring-data-mongodb diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index de608054ba..2fc2911a51 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.0.3.BUILD-SNAPSHOT + 1.0.3.RELEASE ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-cross-store diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index 5b927bc833..b4daaf2051 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.0.3.BUILD-SNAPSHOT + 1.0.3.RELEASE ../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 fcae5f57a8..5fb0b2bbe9 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Parent Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.3.BUILD-SNAPSHOT + 1.0.3.RELEASE pom UTF-8 @@ -198,7 +198,7 @@ org.springframework.data spring-data-mongodb - 1.0.3.BUILD-SNAPSHOT + 1.0.3.RELEASE diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 5646e7822b..900ccfaa90 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.0.3.BUILD-SNAPSHOT + 1.0.3.RELEASE ../spring-data-mongodb-parent/pom.xml spring-data-mongodb From 2c2bbf415b79a9e15b2f89cfb23613ca6e37416c Mon Sep 17 00:00:00 2001 From: Spring Buildmaster Date: Tue, 24 Jul 2012 07:01:24 -0700 Subject: [PATCH 31/49] DATAMONGO-492 - Prepare next development iteration. --- pom.xml | 2 +- spring-data-mongodb-cross-store/pom.xml | 2 +- spring-data-mongodb-log4j/pom.xml | 2 +- spring-data-mongodb-parent/pom.xml | 4 ++-- spring-data-mongodb/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 5f8cc63fd1..eb5d2f9971 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Distribution Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.3.RELEASE + 1.0.4.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 2fc2911a51..7d72c7aabd 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.0.3.RELEASE + 1.0.4.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-cross-store diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index b4daaf2051..4753fb5c98 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.0.3.RELEASE + 1.0.4.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 5fb0b2bbe9..b28ebf9537 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Parent Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.3.RELEASE + 1.0.4.BUILD-SNAPSHOT pom UTF-8 @@ -198,7 +198,7 @@ org.springframework.data spring-data-mongodb - 1.0.3.RELEASE + 1.0.4.BUILD-SNAPSHOT diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 900ccfaa90..28e6d953ce 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.0.3.RELEASE + 1.0.4.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb From 594ddbd1c1f5c0b16956e910e823f483fb704db3 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 26 Jul 2012 10:19:58 +0200 Subject: [PATCH 32/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 | 42 +++++++++---------- 1 file changed, 20 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 d4e9d4c7db..9bed73396e 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 @@ -1,15 +1,11 @@ /* - * Copyright 2010-2011 the original author or authors. + * Copyright 2010-2012 the original author or authors. * - * Licensed under t -import org.springframework.util.ResourceUtils; - -import org.springframework.data.convert.EntityReader; -he Apache License, Version 2.0 (the "License"); + * 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 +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; @@ -340,7 +337,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); @@ -887,7 +884,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 */ @@ -1011,8 +1008,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); @@ -1065,8 +1061,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()); @@ -1178,7 +1173,7 @@ protected void maybeEmitEvent(MongoMappingEvent event) { /** * Create the specified collection using the provided options - * + * * @param collectionName * @param collectionOptions * @return the collection that was created @@ -1200,7 +1195,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 @@ -1225,7 +1220,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 @@ -1242,11 +1237,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); } @@ -1255,7 +1253,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 @@ -1294,7 +1292,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. @@ -1341,7 +1339,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 */ @@ -1394,7 +1392,7 @@ private DBCollection getAndPrepareCollection(DB db, String collectionName) { *

    1. Execute the given {@link ConnectionCallback} for a {@link DBObject}.
    2. *
    3. Apply the given {@link DbObjectCallback} to each of the {@link DBObject}s to obtain the result.
    4. *
        - * + * * @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 From 48cb155f6cd81051ede285555baecb40dd433a79 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 24 Jul 2012 20:13:50 +0200 Subject: [PATCH 33/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/QueryMapper.java | 4 +-- .../core/query/QueryMapperUnitTests.java | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java index 62305d6e31..5bbee983d8 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java @@ -86,6 +86,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); } @@ -102,8 +104,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/query/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java index a461f5339a..8135412676 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/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; @@ -211,6 +213,25 @@ public void doesNotHandleNestedFieldsWithDefaultIdNames() { assertThat(((DBObject) result.get("nested")).get("id"), is(instanceOf(String.class))); } + /** + * @see DATAMONGO-493 + */ + @Test + public void doesNotTranslateNonIdPropertiesFor$NeCriteria() { + + 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"), is(instanceOf(DBObject.class))); + + DBObject publishers = (DBObject) dbObject.get("publishers"); + assertThat(publishers.containsField("$ne"), is(true)); + assertThat(publishers.get("$ne"), is(instanceOf(String.class))); + } + class IdWrapper { Object id; } @@ -236,4 +257,9 @@ class BigIntegerId { enum Enum { INSTANCE; } + + class UserEntity { + String id; + List publishers = new ArrayList(); + } } From 58f12b8d8fc21b12ad057192128633b466cf918b Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 27 Jul 2012 10:39:31 +0200 Subject: [PATCH 34/49] DATAMONGO-494 - QueryMapper now forwards entity metadata into nested $(n)or criterias. Introduced helper class to ease assertions on DBObjects as well. --- .../data/mongodb/core/QueryMapper.java | 2 +- .../data/mongodb/core/DBObjectUtils.java | 81 +++++++++++++++++++ .../core/query/QueryMapperUnitTests.java | 22 ++++- 3 files changed, 103 insertions(+), 2 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/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java index 5bbee983d8..0aea53dd10 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java @@ -101,7 +101,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/query/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java index 8135412676..e631f843e6 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java @@ -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; @@ -50,7 +51,6 @@ * @author Oliver Gierke */ @RunWith(MockitoJUnitRunner.class) -@SuppressWarnings("unused") public class QueryMapperUnitTests { QueryMapper mapper; @@ -232,6 +232,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 323de58efce0abfb5d6dcf31e4528324d4d544dd Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 31 Jul 2012 10:39:03 +0200 Subject: [PATCH 35/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 22872f97dc9e03e8df24551920c676bd3c7fd7fb Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 24 Aug 2012 10:43:54 +0200 Subject: [PATCH 36/49] DATAMONGO-514 - Prepare changelog for 1.0.4.RELEASE. --- src/main/resources/changelog.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/resources/changelog.txt b/src/main/resources/changelog.txt index dc587108ac..e3b7f155bf 100644 --- a/src/main/resources/changelog.txt +++ b/src/main/resources/changelog.txt @@ -1,6 +1,20 @@ Spring Data Document Changelog ============================================= +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.0.3.RELEASE MongoDB (2012-07-23) +----------------------------------------------------- ** 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 From beeed68873c50c3dca4fb40723ec6904de450c44 Mon Sep 17 00:00:00 2001 From: Spring Buildmaster Date: Fri, 24 Aug 2012 01:54:26 -0700 Subject: [PATCH 37/49] DATAMONGO-514 - Release 1.0.4.RELEASE. --- pom.xml | 2 +- spring-data-mongodb-cross-store/pom.xml | 2 +- spring-data-mongodb-log4j/pom.xml | 2 +- spring-data-mongodb-parent/pom.xml | 4 ++-- spring-data-mongodb/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index eb5d2f9971..0abdbdbc03 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Distribution Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.4.BUILD-SNAPSHOT + 1.0.4.RELEASE pom spring-data-mongodb diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index 7d72c7aabd..ff1cc10432 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.0.4.BUILD-SNAPSHOT + 1.0.4.RELEASE ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-cross-store diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index 4753fb5c98..69a06e9833 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.0.4.BUILD-SNAPSHOT + 1.0.4.RELEASE ../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 b28ebf9537..139221c350 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Parent Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.4.BUILD-SNAPSHOT + 1.0.4.RELEASE pom UTF-8 @@ -198,7 +198,7 @@ org.springframework.data spring-data-mongodb - 1.0.4.BUILD-SNAPSHOT + 1.0.4.RELEASE diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 28e6d953ce..d88b4f0a19 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.0.4.BUILD-SNAPSHOT + 1.0.4.RELEASE ../spring-data-mongodb-parent/pom.xml spring-data-mongodb From e4adc0ce23d6de18c2ffcb4475f4e63d3e411794 Mon Sep 17 00:00:00 2001 From: Spring Buildmaster Date: Fri, 24 Aug 2012 01:54:30 -0700 Subject: [PATCH 38/49] DATAMONGO-514 - Prepare next development iteration. --- pom.xml | 2 +- spring-data-mongodb-cross-store/pom.xml | 2 +- spring-data-mongodb-log4j/pom.xml | 2 +- spring-data-mongodb-parent/pom.xml | 4 ++-- spring-data-mongodb/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 0abdbdbc03..3dcbc3b244 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Distribution Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.4.RELEASE + 1.0.5.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 ff1cc10432..f5db5b081e 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.0.4.RELEASE + 1.0.5.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb-cross-store diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index 69a06e9833..c5bedea827 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.0.4.RELEASE + 1.0.5.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 139221c350..359654e677 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -6,7 +6,7 @@ Spring Data MongoDB Parent Spring Data project for MongoDB http://www.springsource.org/spring-data/mongodb - 1.0.4.RELEASE + 1.0.5.BUILD-SNAPSHOT pom UTF-8 @@ -198,7 +198,7 @@ org.springframework.data spring-data-mongodb - 1.0.4.RELEASE + 1.0.5.BUILD-SNAPSHOT diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index d88b4f0a19..825778673e 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.0.4.RELEASE + 1.0.5.BUILD-SNAPSHOT ../spring-data-mongodb-parent/pom.xml spring-data-mongodb From 2a8f13d5d59534059d336092e99921d3ec5c4f97 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 3 Sep 2012 18:31:57 +0200 Subject: [PATCH 39/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 14e0c16554..e1ac523fd8 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 cfe0cc1609..8f2b8fc79b 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,10 +15,10 @@ */ 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.core.query.Criteria; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; @@ -51,4 +51,14 @@ public void testChainedCriteria() { Criteria c = new Criteria("name").is("Bubba").and("age").lt(21); assertEquals("{ \"name\" : \"Bubba\" , \"age\" : { \"$lt\" : 21}}", c.getCriteriaObject().toString()); } + + @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 c1030abe968b207edef04d0a72b1b29bdd646e81 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 3 Sep 2012 16:55:07 +0200 Subject: [PATCH 40/49] DATAMONGO-512 - Fixed broken handling of AND in query methods. Apparently the fix fof DATAMONGO-469 was messed up later on. --- .../repository/query/MongoQueryCreator.java | 9 ++++++--- ...tractPersonRepositoryIntegrationTests.java | 19 ++++++++++++++++++- .../mongodb/repository/PersonRepository.java | 2 ++ .../PersonRepositoryIntegrationTests.java | 2 +- .../query/MongoQueryCreatorUnitTests.java | 5 +++-- 5 files changed, 30 insertions(+), 7 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 4b47696c39..b3ea64e8df 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 @@ -117,8 +117,11 @@ protected Criteria and(Part part, Criteria base, Iterator iterator) { } PersistentPropertyPath path = context.getPersistentPropertyPath(part.getProperty()); - return from(part.getType(), where(path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)), - (PotentiallyConvertingIterator) iterator); + + return new Criteria().andOperator( + base, + from(part.getType(), where(path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)), + (PotentiallyConvertingIterator) iterator)); } /* @@ -265,4 +268,4 @@ private String toLikeRegex(String source) { return source.replaceAll("\\*", ".*"); } -} \ No newline at end of file +} 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 97a46f6e6f..bc2b2e80a8 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 @@ -432,4 +432,21 @@ public void bindsDateParameterForManuallyDefinedQueryCorrectly() { List result = repository.findByCreatedAtLessThanManually(boyd.createdAt); assertThat(result.isEmpty(), is(false)); } -} \ No newline at end of file + + /** + * @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 8c9d84f783..ca5fc4d24d 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. diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java index 29e9f48306..25ed96b1e7 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java @@ -97,7 +97,8 @@ public void createsAndQueryCorrectly() { getAccessor(converter, "Oliver", person), context); Query query = creator.createQuery(); - assertThat(query, is(query(where("firstName").is("Oliver").and("friend").is(person)))); + Criteria criteria = new Criteria().andOperator(where("firstName").is("Oliver"), where("friend").is(person)); + assertThat(query, is(query(criteria))); } @Test @@ -222,7 +223,7 @@ public void createsFalseClauseCorrectly() { } /** - * @see DATAMONGO + * @see DATAMONGO-413 */ @Test public void createsOrQueryCorrectly() { From 4ce8da7ebf694fe2a6fd2eb628670c6da1947d2f Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 11 Sep 2012 17:40:17 +0200 Subject: [PATCH 41/49] DATAMONGO-536 - Fixed package cycle introduced by SerializationUtils. --- .../org/springframework/data/mongodb/core/MongoTemplate.java | 2 +- .../org/springframework/data/mongodb/core/query/Query.java | 2 +- .../data/mongodb/core/{ => query}/SerializationUtils.java | 2 +- .../data/mongodb/core/SerializationUtilsUnitTests.java | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) rename spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/{ => query}/SerializationUtils.java (98%) 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 9bed73396e..055590447a 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,8 +15,8 @@ */ package org.springframework.data.mongodb.core; -import static org.springframework.data.mongodb.core.SerializationUtils.*; import static org.springframework.data.mongodb.core.query.Criteria.*; +import static org.springframework.data.mongodb.core.query.SerializationUtils.*; import java.io.IOException; import java.lang.reflect.InvocationTargetException; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java index b24015bf20..c92fa335d6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java @@ -15,7 +15,7 @@ */ package org.springframework.data.mongodb.core.query; -import static org.springframework.data.mongodb.core.SerializationUtils.*; +import static org.springframework.data.mongodb.core.query.SerializationUtils.*; import static org.springframework.util.ObjectUtils.*; import java.util.ArrayList; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SerializationUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/SerializationUtils.java similarity index 98% rename from spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SerializationUtils.java rename to spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/SerializationUtils.java index d21098843e..b11948220c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SerializationUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/SerializationUtils.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.mongodb.core; +package org.springframework.data.mongodb.core.query; import java.util.Collection; import java.util.Iterator; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SerializationUtilsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SerializationUtilsUnitTests.java index 883729bb6f..78ef19c037 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SerializationUtilsUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SerializationUtilsUnitTests.java @@ -17,12 +17,13 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; -import static org.springframework.data.mongodb.core.SerializationUtils.*; +import static org.springframework.data.mongodb.core.query.SerializationUtils.*; import java.util.Arrays; import org.hamcrest.Matcher; import org.junit.Test; +import org.springframework.data.mongodb.core.query.SerializationUtils; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; From d5f8285d51915c601a91e3eaff0d705b4254db2c Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 3 Sep 2012 16:56:13 +0200 Subject: [PATCH 42/49] DATAMONGO-529 - Update Querydsl setup to use 1.0.4. Raised Maven compiler plugin version to 2.5.1. --- spring-data-mongodb-parent/pom.xml | 6 +++++- spring-data-mongodb/pom.xml | 22 ++++++++-------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml index 359654e677..6c44f8a7ad 100644 --- a/spring-data-mongodb-parent/pom.xml +++ b/spring-data-mongodb-parent/pom.xml @@ -297,7 +297,7 @@ org.apache.maven.plugins maven-compiler-plugin - 2.4 + 2.5.1 1.5 1.5 @@ -378,6 +378,10 @@ spring-plugins-release http://repo.springsource.org/plugins-release + + querydsl + http://source.mysema.com/maven2/releases + diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 825778673e..eb923eb582 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -69,19 +69,6 @@ querydsl-mongodb ${querydsl.version} true - - - com.google.code.morphia - morphia - - - - - - com.mysema.querydsl - querydsl-apt - ${querydsl.version} - provided @@ -131,7 +118,14 @@ com.mysema.maven maven-apt-plugin - 1.0.2 + 1.0.4 + + + com.mysema.querydsl + querydsl-apt + ${querydsl.version} + + generate-test-sources From e0b0792643cfe9dd7fe7c68bb1bd0b79907216f0 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 12 Sep 2012 10:11:26 +0200 Subject: [PATCH 43/49] DATAMONGO-537 - Guard index creation tests against changing method orders. --- .../RepositoryIndexCreationIntegrationTests.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests.java index 8682399e5a..425c6031fa 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests.java @@ -44,11 +44,9 @@ @ContextConfiguration public class RepositoryIndexCreationIntegrationTests { - @Autowired - MongoOperations operations; + @Autowired MongoOperations operations; - @Autowired - PersonRepository repository; + @Autowired PersonRepository repository; @After public void tearDown() { @@ -72,12 +70,13 @@ public Void doInCollection(DBCollection collection) throws MongoException, DataA public void testname() { operations.execute(Person.class, new CollectionCallback() { + @SuppressWarnings("unchecked") public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException { List indexInfo = collection.getIndexInfo(); assertThat(indexInfo.isEmpty(), is(false)); assertThat(indexInfo.size(), is(greaterThan(2))); - assertThat(getIndexNamesFrom(indexInfo), hasItems("findByLastnameLike", "findByFirstnameLike")); + assertThat(getIndexNamesFrom(indexInfo), hasItems(startsWith("findByLastname"), startsWith("findByFirstname"))); return null; } From 1d9ee9a28feb81a72f15d05380cf894b38b7eca9 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 12 Sep 2012 10:40:19 +0200 Subject: [PATCH 44/49] DATAMONGO-537 - Work around compiler issues with generics. --- .../RepositoryIndexCreationIntegrationTests.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests.java index 425c6031fa..a3a20e1513 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/RepositoryIndexCreationIntegrationTests.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.List; +import org.hamcrest.Matcher; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -76,8 +77,12 @@ public Void doInCollection(DBCollection collection) throws MongoException, DataA assertThat(indexInfo.isEmpty(), is(false)); assertThat(indexInfo.size(), is(greaterThan(2))); - assertThat(getIndexNamesFrom(indexInfo), hasItems(startsWith("findByLastname"), startsWith("findByFirstname"))); + Matcher lastnameIndex = startsWith("findByLastname"); + Matcher firstnameIndex = startsWith("findByFirstname"); + Matcher> hasItems = hasItems(lastnameIndex, firstnameIndex); + + assertThat(getIndexNamesFrom(indexInfo), hasItems); return null; } }); From eabd47ae8dc0f5228ed3f14db8c54c1bbe535ec2 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 12 Sep 2012 13:00:46 +0200 Subject: [PATCH 45/49] DATAMONGO-532 - Synchronize DB authentication. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In multithreaded environments Mongo database authentication can be triggered twice if two or more threads refer to the same db instance. This is now prevented by synchronizing calls to db.authenticate(…). --- .../data/mongodb/core/MongoDbUtils.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java index 0826e25f42..679cece9c1 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java @@ -97,10 +97,12 @@ public static DB doGetDB(Mongo mongo, String databaseName, String username, char boolean credentialsGiven = username != null && password != null; if (credentialsGiven && !db.isAuthenticated()) { // Note, can only authenticate once against the same com.mongodb.DB object. - if (!db.authenticate(username, password)) { - throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName - + "], username = [" + username + "], password = [" + new String(password) + "]", databaseName, username, - password); + synchronized (db) { + if (!db.authenticate(username, password)) { + throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + + "], username = [" + username + "], password = [" + new String(password) + "]", databaseName, username, + password); + } } } @@ -144,7 +146,7 @@ public static boolean isDBTransactional(DB db, Mongo mongo) { return false; } DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo); - return (dbHolder != null && dbHolder.containsDB(db)); + return dbHolder != null && dbHolder.containsDB(db); } /** From aef493fdb87a47afeb16cf58b48f22e69da22a63 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 13 Sep 2012 17:24:27 +0200 Subject: [PATCH 46/49] DATAMONGO-539 - Added test case to show removing entity from explicit collection works. --- .../data/mongodb/core/MongoTemplateTests.java | 17 +++++++++++++++++ 1 file changed, 17 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 293529c121..64d4ea31b2 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 @@ -1226,6 +1226,23 @@ public void storesAndRemovesTypeWithComplexId() { template.remove(query(where("id").is(id)), TypeWithMyId.class); } + /** + * @see DATAMONGO-539 + */ + @Test + public void removesObjectFromExplicitCollection() { + + String collectionName = "explicit"; + template.remove(new Query(), collectionName); + + Person person = new Person("Dave"); + template.save(person, collectionName); + assertThat(template.findAll(Person.class, collectionName).isEmpty(), is(false)); + + template.remove(person, collectionName); + assertThat(template.findAll(Person.class, collectionName).isEmpty(), is(true)); + } + static class MyId { String first; From bf89cce43cabd950186dcada705951f13dd6c3cb Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 17 Sep 2012 11:44:30 +0200 Subject: [PATCH 47/49] DATAMONGO-539 - Fixed MongoTemplate.remove(object, collectionName). If the entity being removed using MongoTemplate.remove(object, collectionName) contained an id that could be converted into an ObjectID it wasn't removed correctly currently. This was caused by the fact that the intermediate call didn't hand over the entity type and thus the id conversion failed. This in turn caused the query not to match the previous saved object. --- .../data/mongodb/core/MongoTemplate.java | 4 ++-- .../data/mongodb/core/MongoTemplateTests.java | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 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 055590447a..22b7ef043f 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 @@ -456,7 +456,7 @@ public T findOne(Query query, Class entityClass, String collectionName) { } else { query.limit(1); List results = find(query, entityClass, collectionName); - return (results.isEmpty() ? null : results.get(0)); + return results.isEmpty() ? null : results.get(0); } } @@ -879,7 +879,7 @@ public void remove(Object object, String collection) { return; } - remove(getIdQueryFor(object), collection); + doRemove(collection, getIdQueryFor(object), object.getClass()); } /** 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 64d4ea31b2..fd18323e8b 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 @@ -1235,12 +1235,13 @@ public void removesObjectFromExplicitCollection() { String collectionName = "explicit"; template.remove(new Query(), collectionName); - Person person = new Person("Dave"); + PersonWithConvertedId person = new PersonWithConvertedId(); + person.name = "Dave"; template.save(person, collectionName); - assertThat(template.findAll(Person.class, collectionName).isEmpty(), is(false)); + assertThat(template.findAll(PersonWithConvertedId.class, collectionName).isEmpty(), is(false)); template.remove(person, collectionName); - assertThat(template.findAll(Person.class, collectionName).isEmpty(), is(true)); + assertThat(template.findAll(PersonWithConvertedId.class, collectionName).isEmpty(), is(true)); } static class MyId { @@ -1272,6 +1273,12 @@ static class TestClass { } } + static class PersonWithConvertedId { + + String id; + String name; + } + static enum DateTimeToDateConverter implements Converter { INSTANCE; From 1b3d49e4661a98ca4a63432ecba88eebadafd533 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 17 Sep 2012 12:07:52 +0200 Subject: [PATCH 48/49] DATAMONGO-457 - Fixed links in reference documentation. --- src/docbkx/introduction/introduction.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/docbkx/introduction/introduction.xml b/src/docbkx/introduction/introduction.xml index 3ff9b07d94..5d9eb2bca3 100644 --- a/src/docbkx/introduction/introduction.xml +++ b/src/docbkx/introduction/introduction.xml @@ -12,17 +12,17 @@ Knowing Spring Spring Data uses Spring framework's core + url="http://static.springframework.org/spring/docs/3.0.x/reference/html/spring-core.html">core functionality, such as the IoC + url="http://static.springframework.org/spring/docs/3.0.x/reference/html/beans.html">IoC container, type - conv ersion system, expression + url="http://static.springsource.org/spring/docs/3.0.x/reference/html/validation.html#core-convert">type + conversion system, expression language, JMX + url="http://static.springsource.org/spring/docs/3.0.x/reference/html/jmx.html">JMX integration, and portable DAO + url="http://static.springsource.org/spring/docs/3.0.x/reference/html/dao.html#dao-exceptions">DAO exception hierarchy. While it is not important to know the Spring APIs, understanding the concepts behind them is. At a minimum, the idea behind IoC should be familiar for whatever IoC container you From 4ca16f8d15203857c6f70353e43c707d1033e986 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 17 Sep 2012 12:20:52 +0200 Subject: [PATCH 49/49] DATAMONGO-456 - Fixed element documentation in XSD. --- .../springframework/data/mongodb/config/spring-mongo-1.0.xsd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 a027962ae9..ff053fde54 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 @@ -44,8 +44,9 @@ The name of the mongo definition (by default "mongoDbFactory").]]> - - The reference to a Mongo. Will default to 'mongo'. +