Compare commits

..

15 Commits

Author SHA1 Message Date
Spring Buildmaster
b17ec47003 DATAMONGO-751 - Release version 1.3.1.RELEASE. 2013-09-09 23:27:13 -07:00
Oliver Gierke
8c7b558d39 DATAMONGO-751 - Prepare 1.3.1.RELEASE. 2013-09-09 23:12:40 -07:00
Spring Buildmaster
a3faabf718 DATAMONGO-740 - Prepare next development iteration. 2013-09-09 15:58:43 -07:00
Spring Buildmaster
1a46abfbb9 DATAMONGO-740 - Release version 1.3.0.RELEASE. 2013-09-09 15:56:20 -07:00
Thomas Darimont
61284228dd DATAMONGO-740 - Prepare 1.3.0 RELEASE. 2013-09-09 15:50:04 -07:00
Thomas Darimont
8cb92de1ee DATAMONGO-445 - Allow to skip unnecessary elements in NearQuery.
Added support for skipping elements for NearQuery in MongoTemplate. As mongodb currently (2.4.4) doesn't support he skipping of elements in geoNear-Queries we skip the unnecessary elements ourselves. We use the limit & skip information from the given query or an explicitly passed Pageable.

Original pull request: #64.
2013-08-22 09:20:19 +02:00
Oliver Gierke
5d3cc3fa04 DATAMONGO-743 - Added DBObjectToStringConverter.
Added a reading converter to dump DBObject instances into a String directly to enable executing queries against MongoDB into a String version of the query result without marshaling the DBObject into a Map first.
2013-08-22 08:55:07 +02:00
Thomas Darimont
c0b99740dc DATAMONGO-742 - Document CDI integration in reference documentation.
Added chapter for CDI Integration under the new chapter Miscellaneous.

Original pull request: #63.
2013-08-13 12:20:58 +02:00
Randy Watler
595bbd3aa7 DATAMONGO-737 - Register TransactionSynchronization holder once per Mongo instance.
Original pull request: #62.
2013-08-12 09:51:02 +02:00
Chuong Ngo
5d2fc31164 DATAMONGO-738 - Allow to pass collectionName along with entityClass as parameter to update methods in MongoTemplate.
Added appropriate overloaded methods to MongoOperations and MongoTemplate. Applied pull request from Chuong Ngo <chuong.h.ngo.ctr@mail.mil>.
Original pull request: #57.
2013-08-09 15:30:00 +02:00
Thomas Darimont
a9dc0fae69 DATAMONGO-725 - Improve configurability and documentation of TypeMapper on MappingMongoConverter.
Added new attribute type-mapper-ref to the mapping-converter element in spring-mongo-1.3.xsd in order to support the configuration of custom-type-mappers. Removed the unsupported attributes "mongo-ref" and "mongo-template-ref" from the mapping-converter element in spring-mongo-1.3.xsd because they are not considered anymore.

Updated MappingMongoConverterParser to be aware of the new attribute. Added examples for configuring a custom MongoTypeMapper the usage of @TypeAlias to the reference documentation.

Original pull request: #61.
2013-08-09 13:44:53 +02:00
Thomas Darimont
0605c7b753 DATAMONGO-507 - Reject incorrect usage of Criteria#not().
Added a guard to Criteria#(and|or|nor)Operator to prevent wrapping $and, $or or $nor expressions in a $not expression as mongodb currently doesn't support this. Added test case to CriteriaTests to verify that not() works as specified.

Original pull request: #60.
2013-08-09 12:23:25 +02:00
Thomas Darimont
21352a8829 DATAMONGO-602 - Added test case to MongoTemplate tests to verify that querying by BigInteger ids work.
Original pull request: #59.
2013-08-07 18:58:32 +02:00
Oliver Gierke
58e1d2dbd9 DATAMONGO-741 - Fixed check for nested property references in aggregation framework.
Fixed using the actual field reference instead of the field name on resolving. Added equals(…) and hashCode() methods to value objects. Added unit tests for TypeBasedAggregationOperationContext.
2013-08-07 10:21:48 +02:00
Spring Buildmaster
4f7821e3c2 DATAMONGO-732 - Prepare next development iteration. 2013-08-05 08:48:22 -07:00
44 changed files with 1053 additions and 70 deletions

View File

@@ -26,7 +26,7 @@ Add the Maven dependency:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.2.3.RELEASE</version>
<version>1.3.1.RELEASE</version>
</dependency>
```
@@ -36,7 +36,7 @@ If you'd rather like the latest snapshots of the upcoming major version, use our
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.3.0.BUILD-SNAPSHOT</version>
<version>1.4.0.BUILD-SNAPSHOT</version>
</dependency>
<repository>

10
pom.xml
View File

@@ -5,7 +5,7 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.3.0.RC1</version>
<version>1.3.1.RELEASE</version>
<packaging>pom</packaging>
<name>Spring Data MongoDB</name>
@@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.1.1.RELEASE</version>
<version>1.2.0.RELEASE</version>
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
</parent>
@@ -29,7 +29,7 @@
<properties>
<project.type>multi</project.type>
<dist.id>spring-data-mongodb</dist.id>
<springdata.commons>1.6.0.RC1</springdata.commons>
<springdata.commons>1.6.1.RELEASE</springdata.commons>
<mongo>2.10.1</mongo>
</properties>
@@ -91,8 +91,8 @@
<repositories>
<repository>
<id>spring-lib-milestone</id>
<url>http://repo.springsource.org/libs-milestone-local</url>
<id>spring-lib-release</id>
<url>http://repo.springsource.org/libs-release-local</url>
</repository>
</repositories>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.3.0.RC1</version>
<version>1.3.1.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -52,7 +52,7 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.3.0.RC1</version>
<version>1.3.1.RELEASE</version>
</dependency>
<dependency>

View File

@@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.3.0.RC1</version>
<version>1.3.1.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.3.0.RC1</version>
<version>1.3.1.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -11,7 +11,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.3.0.RC1</version>
<version>1.3.1.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -70,6 +70,7 @@ import org.w3c.dom.Element;
* @author Jon Brisbin
* @author Oliver Gierke
* @author Maciej Walkowiak
* @author Thomas Darimont
*/
public class MappingMongoConverterParser implements BeanDefinitionParser {
@@ -105,6 +106,11 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
converterBuilder.addConstructorArgReference(dbFactoryRef);
converterBuilder.addConstructorArgReference(ctxRef);
String typeMapperRef = element.getAttribute("type-mapper-ref");
if (StringUtils.hasText(typeMapperRef)) {
converterBuilder.addPropertyReference("typeMapper", typeMapperRef);
}
if (conversionsDefinition != null) {
converterBuilder.addPropertyValue("customConversions", conversionsDefinition);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2013 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,14 +26,13 @@ import com.mongodb.DB;
import com.mongodb.Mongo;
/**
* Helper class featuring helper methods for internal MongoDb classes.
* <p/>
* <p>
* Mainly intended for internal use within the framework.
* Helper class featuring helper methods for internal MongoDb classes. Mainly intended for internal use within the
* framework.
*
* @author Thomas Risberg
* @author Graeme Rocher
* @author Oliver Gierke
* @author Randy Watler
* @since 1.0
*/
public abstract class MongoDbUtils {
@@ -131,8 +130,11 @@ public abstract class MongoDbUtils {
holderToUse.addDB(databaseName, db);
}
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo));
holderToUse.setSynchronizedWithTransaction(true);
// synchronize holder only if not yet synchronized
if (!holderToUse.isSynchronizedWithTransaction()) {
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo));
holderToUse.setSynchronizedWithTransaction(true);
}
if (holderToUse != dbHolder) {
TransactionSynchronizationManager.bindResource(mongo, holderToUse);

View File

@@ -49,6 +49,7 @@ import com.mongodb.WriteResult;
* @author Mark Pollack
* @author Oliver Gierke
* @author Tobias Trelle
* @author Chuong Ngo
*/
public interface MongoOperations {
@@ -703,6 +704,18 @@ public interface MongoOperations {
*/
WriteResult upsert(Query query, Update update, String collectionName);
/**
* Performs an upsert. If no document is found that matches the query, a new document is created and inserted by
* combining the query document and the update document.
*
* @param query the query document that specifies the criteria used to select a record to be upserted
* @param update the update document that contains the updated object or $ operators to manipulate the existing object
* @param entityClass class of the pojo to be operated on
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult upsert(Query query, Update update, Class<?> entityClass, String collectionName);
/**
* Updates the first object that is found in the collection of the entity class that matches the query document with
* the provided update document.
@@ -727,6 +740,19 @@ public interface MongoOperations {
*/
WriteResult updateFirst(Query query, Update update, String collectionName);
/**
* Updates the first object that is found in the specified collection that matches the query document criteria with
* the provided updated document.
*
* @param query the query document that specifies the criteria used to select a record to be updated
* @param update the update document that contains the updated object or $ operators to manipulate the existing
* object.
* @param entityClass class of the pojo to be operated on
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult updateFirst(Query query, Update update, Class<?> entityClass, String collectionName);
/**
* Updates all objects that are found in the collection for the entity class that matches the query document criteria
* with the provided updated document.
@@ -751,6 +777,19 @@ public interface MongoOperations {
*/
WriteResult updateMulti(Query query, Update update, String collectionName);
/**
* Updates all objects that are found in the collection for the entity class that matches the query document criteria
* with the provided updated document.
*
* @param query the query document that specifies the criteria used to select a record to be updated
* @param update the update document that contains the updated object or $ operators to manipulate the existing
* object.
* @param entityClass class of the pojo to be operated on
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult updateMulti(final Query query, final Update update, Class<?> entityClass, String collectionName);
/**
* Remove the given object from the collection by id.
*

View File

@@ -123,6 +123,7 @@ import com.mongodb.util.JSONParseException;
* @author Tobias Trelle
* @author Sebastian Herold
* @author Thomas Darimont
* @author Chuong Ngo
*/
public class MongoTemplate implements MongoOperations, ApplicationContextAware {
@@ -565,8 +566,26 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
mongoConverter, entityClass), near.getMetric());
List<GeoResult<T>> result = new ArrayList<GeoResult<T>>(results.size());
int index = 0;
int elementsToSkip = near.getSkip() != null ? near.getSkip() : 0;
for (Object element : results) {
result.add(callback.doWith((DBObject) element));
/*
* As MongoDB currently (2.4.4) doesn't support the skipping of elements in near queries
* we skip the elements ourselves to avoid at least the document 2 object mapping overhead.
*
* @see https://jira.mongodb.org/browse/SERVER-3925
*/
if (index >= elementsToSkip) {
result.add(callback.doWith((DBObject) element));
}
index++;
}
if (elementsToSkip > 0) {
// as we skipped some elements we have to calculate the averageDistance ourselves:
return new GeoResults<T>(result, near.getMetric());
}
DBObject stats = (DBObject) commandResult.get("stats");
@@ -928,6 +947,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
return doUpdate(collectionName, query, update, null, true, false);
}
public WriteResult upsert(Query query, Update update, Class<?> entityClass, String collectionName) {
return doUpdate(collectionName, query, update, entityClass, true, false);
}
public WriteResult updateFirst(Query query, Update update, Class<?> entityClass) {
return doUpdate(determineCollectionName(entityClass), query, update, entityClass, false, false);
}
@@ -936,6 +959,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
return doUpdate(collectionName, query, update, null, false, false);
}
public WriteResult updateFirst(Query query, Update update, Class<?> entityClass, String collectionName) {
return doUpdate(collectionName, query, update, entityClass, false, false);
}
public WriteResult updateMulti(Query query, Update update, Class<?> entityClass) {
return doUpdate(determineCollectionName(entityClass), query, update, entityClass, false, true);
}
@@ -944,6 +971,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
return doUpdate(collectionName, query, update, null, false, true);
}
public WriteResult updateMulti(final Query query, final Update update, Class<?> entityClass, String collectionName) {
return doUpdate(collectionName, query, update, entityClass, false, true);
}
protected WriteResult doUpdate(final String collectionName, final Query query, final Update update,
final Class<?> entityClass, final boolean upsert, final boolean multi) {

View File

@@ -242,6 +242,41 @@ public class ExposedFields implements Iterable<ExposedField> {
public String toString() {
return String.format("AggregationField: %s, synthetic: %s", field, synthetic);
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ExposedField)) {
return false;
}
ExposedField that = (ExposedField) obj;
return this.field.equals(that.field) && this.synthetic == that.synthetic;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * field.hashCode();
result += 31 * (synthetic ? 0 : 1);
return result;
}
}
/**
@@ -282,5 +317,34 @@ public class ExposedFields implements Iterable<ExposedField> {
public String toString() {
return String.format("$%s", getRaw());
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof FieldReference)) {
return false;
}
FieldReference that = (FieldReference) obj;
return this.field.equals(that.field);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return field.hashCode();
}
}
}

View File

@@ -44,7 +44,7 @@ public abstract class ExposedFieldsAggregationOperationContext implements Aggreg
*/
@Override
public FieldReference getReference(Field field) {
return getReference(field.getName());
return getReference(field.getTarget());
}
/*

View File

@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -231,5 +232,40 @@ public class Fields implements Iterable<Field> {
public String toString() {
return String.format("AggregationField - name: %s, target: %s", name, target);
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof AggregationField)) {
return false;
}
AggregationField that = (AggregationField) obj;
return this.name.equals(that.name) && ObjectUtils.nullSafeEquals(this.target, that.target);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * name.hashCode();
result += 31 * ObjectUtils.nullSafeHashCode(target);
return result;
}
}
}

View File

@@ -78,7 +78,7 @@ public class TypeBasedAggregationOperationContext implements AggregationOperatio
@Override
public FieldReference getReference(Field field) {
PropertyPath.from(field.getName(), type);
PropertyPath.from(field.getTarget(), type);
return getReferenceFor(field);
}

View File

@@ -39,6 +39,7 @@ import org.springframework.data.convert.WritingConverter;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.mongodb.core.convert.MongoConverters.BigDecimalToStringConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.BigIntegerToStringConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToStringConverter;
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;
@@ -98,6 +99,7 @@ public class CustomConversions {
this.converters.add(StringToBigIntegerConverter.INSTANCE);
this.converters.add(URLToStringConverter.INSTANCE);
this.converters.add(StringToURLConverter.INSTANCE);
this.converters.add(DBObjectToStringConverter.INSTANCE);
this.converters.addAll(JodaTimeConverters.getConvertersToRegister());
this.converters.addAll(converters);

View File

@@ -24,8 +24,11 @@ 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.data.convert.ReadingConverter;
import org.springframework.util.StringUtils;
import com.mongodb.DBObject;
/**
* Wrapper class to contain useful converters for the usage with Mongo.
*
@@ -147,4 +150,15 @@ abstract class MongoConverters {
}
}
}
@ReadingConverter
public static enum DBObjectToStringConverter implements Converter<DBObject, String> {
INSTANCE;
@Override
public String convert(DBObject source) {
return source == null ? null : source.toString();
}
}
}

View File

@@ -131,7 +131,7 @@ public class GeoResults<T> implements Iterable<GeoResult<T>> {
private static Distance calculateAverageDistance(List<? extends GeoResult<?>> results, Metric metric) {
if (results.isEmpty()) {
return new Distance(0, null);
return new Distance(0, metric);
}
double averageDistance = 0;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2013 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,10 @@ import com.mongodb.DBObject;
/**
* Central class for creating queries. It follows a fluent API style so that you can easily chain together multiple
* criteria. Static import of the 'Criteria.where' method will improve readability.
*
* @author Thomas Risberg
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class Criteria implements CriteriaDefinition {
@@ -396,34 +400,54 @@ public class Criteria implements CriteriaDefinition {
/**
* Creates an 'or' criteria using the $or operator for all of the provided criteria
* <p>
* Note that mongodb doesn't support an $or operator to be wrapped in a $not operator.
* <p>
*
* @throws IllegalArgumentException if {@link #orOperator(Criteria...)} follows a not() call directly.
* @param criteria
*/
public Criteria orOperator(Criteria... criteria) {
BasicDBList bsonList = createCriteriaList(criteria);
criteriaChain.add(new Criteria("$or").is(bsonList));
return this;
return registerCriteriaChainElement(new Criteria("$or").is(bsonList));
}
/**
* Creates a 'nor' criteria using the $nor operator for all of the provided criteria
* Creates a 'nor' criteria using the $nor operator for all of the provided criteria.
* <p>
* Note that mongodb doesn't support an $nor operator to be wrapped in a $not operator.
* <p>
*
* @throws IllegalArgumentException if {@link #norOperator(Criteria...)} follows a not() call directly.
* @param criteria
*/
public Criteria norOperator(Criteria... criteria) {
BasicDBList bsonList = createCriteriaList(criteria);
criteriaChain.add(new Criteria("$nor").is(bsonList));
return this;
return registerCriteriaChainElement(new Criteria("$nor").is(bsonList));
}
/**
* Creates an 'and' criteria using the $and operator for all of the provided criteria
* Creates an 'and' criteria using the $and operator for all of the provided criteria.
* <p>
* Note that mongodb doesn't support an $and operator to be wrapped in a $not operator.
* <p>
*
* @throws IllegalArgumentException if {@link #andOperator(Criteria...)} follows a not() call directly.
* @param criteria
*/
public Criteria andOperator(Criteria... criteria) {
BasicDBList bsonList = createCriteriaList(criteria);
criteriaChain.add(new Criteria("$and").is(bsonList));
return registerCriteriaChainElement(new Criteria("$and").is(bsonList));
}
private Criteria registerCriteriaChainElement(Criteria criteria) {
if (lastOperatorWasNot()) {
throw new IllegalArgumentException("operator $not is not allowed around criteria chain element: "
+ criteria.getCriteriaObject());
} else {
criteriaChain.add(criteria);
}
return this;
}
@@ -468,6 +492,7 @@ public class Criteria implements CriteriaDefinition {
}
}
}
DBObject queryCriteria = new BasicDBObject();
if (isValue != NOT_SET) {
queryCriteria.put(this.key, this.isValue);

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.core.query;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.geo.CustomMetric;
import org.springframework.data.mongodb.core.geo.Distance;
import org.springframework.data.mongodb.core.geo.Metric;
@@ -29,6 +30,7 @@ import com.mongodb.DBObject;
* Builder class to build near-queries.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class NearQuery {
@@ -38,6 +40,7 @@ public class NearQuery {
private Metric metric;
private boolean spherical;
private Integer num;
private Integer skip;
/**
* Creates a new {@link NearQuery}.
@@ -116,7 +119,7 @@ public class NearQuery {
}
/**
* Configures the number of results to return.
* Configures the maximum number of results to return.
*
* @param num
* @return
@@ -126,6 +129,29 @@ public class NearQuery {
return this;
}
/**
* Configures the number of results to skip.
*
* @param skip
* @return
*/
public NearQuery skip(int skip) {
this.skip = skip;
return this;
}
/**
* Configures the {@link Pageable} to use.
*
* @param pageable
* @return
*/
public NearQuery with(Pageable pageable) {
this.num = pageable.getOffset() + pageable.getPageSize();
this.skip = pageable.getOffset();
return this;
}
/**
* Sets the max distance results shall have from the configured origin. If a {@link Metric} was set before the given
* value will be interpreted as being a value in that metric. E.g.
@@ -290,9 +316,18 @@ public class NearQuery {
*/
public NearQuery query(Query query) {
this.query = query;
this.skip = query.getSkip();
this.num = query.getLimit();
return this;
}
/**
* @return the number of elements to skip.
*/
public Integer getSkip() {
return skip;
}
/**
* Returns the {@link DBObject} built by the {@link NearQuery}.
*

View File

@@ -38,6 +38,7 @@ import org.springframework.util.Assert;
* Base class for {@link RepositoryQuery} implementations for Mongo.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public abstract class AbstractMongoQuery implements RepositoryQuery {
@@ -287,6 +288,11 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
nearQuery.maxDistance(maxDistance).in(maxDistance.getMetric());
}
Pageable pageable = accessor.getPageable();
if (pageable != null) {
nearQuery.with(pageable);
}
MongoEntityMetadata<?> metadata = method.getEntityInformation();
return (GeoResults<Object>) operations.geoNear(nearQuery, metadata.getJavaType(), metadata.getCollectionName());
}

View File

@@ -181,10 +181,10 @@ The base package in which to scan for entities annotated with @Document
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mongo-ref" type="mongoRef" use="optional">
<xsd:attribute name="type-mapper-ref" type="typeMapperRef" use="optional">
<xsd:annotation>
<xsd:documentation>
The reference to a Mongo. Will default to 'mongo'.
The reference to a MongoTypeMapper to be used by this MappingMongoConverter.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -195,13 +195,6 @@ The base package in which to scan for entities annotated with @Document
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mongo-template-ref" type="mongoTemplateRef" use="optional">
<xsd:annotation>
<xsd:documentation source="org.springframework.data.mongodb.core.core.MongoTemplate">
The reference to a MongoTemplate. Will default to 'mongoTemplate'.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="disable-validation" use="optional">
<xsd:annotation>
<xsd:documentation source="org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener">
@@ -257,6 +250,17 @@ The name of the Mongo object that determines what server to monitor. (by default
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="typeMapperRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.data.mongodb.core.convert.MongoTypeMapper"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string"/>
</xsd:simpleType>
<xsd:simpleType name="mappingContextRef">
<xsd:annotation>
<xsd:appinfo>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2013 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.
@@ -23,8 +23,11 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoTypeMapper;
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
@@ -37,6 +40,7 @@ import com.mongodb.Mongo;
* Unit tests for {@link AbstractMongoConfiguration}.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class AbstractMongoConfigurationUnitTests {
@@ -113,6 +117,20 @@ public class AbstractMongoConfigurationUnitTests {
assertThat(spElContext.getBeanResolver(), is(notNullValue()));
}
/**
* @see DATAMONGO-725
*/
@Test
public void shouldBeAbleToConfigureCustomTypeMapperViaJavaConfig() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SampleMongoConfiguration.class);
MongoTypeMapper typeMapper = context.getBean(CustomMongoTypeMapper.class);
MappingMongoConverter mmc = context.getBean(MappingMongoConverter.class);
assertThat(mmc, is(notNullValue()));
assertThat(mmc.getTypeMapper(), is(typeMapper));
}
private static void assertScanningDisabled(final String value) throws ClassNotFoundException {
AbstractMongoConfiguration configuration = new SampleMongoConfiguration() {
@@ -138,6 +156,19 @@ public class AbstractMongoConfigurationUnitTests {
public Mongo mongo() throws Exception {
return new Mongo();
}
@Bean
@Override
public MappingMongoConverter mappingMongoConverter() throws Exception {
MappingMongoConverter mmc = super.mappingMongoConverter();
mmc.setTypeMapper(typeMapper());
return mmc;
}
@Bean
public MongoTypeMapper typeMapper() {
return new CustomMongoTypeMapper();
}
}
@Document

View File

@@ -0,0 +1,23 @@
/*
* Copyright 2013 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 org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
/**
* @author Thomas Darimont
*/
class CustomMongoTypeMapper extends DefaultMongoTypeMapper {}

View File

@@ -31,6 +31,8 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoTypeMapper;
import org.springframework.data.mongodb.core.mapping.Account;
import org.springframework.data.mongodb.core.mapping.CamelCaseAbbreviatingFieldNamingStrategy;
import org.springframework.data.mongodb.repository.Person;
@@ -42,6 +44,7 @@ import com.mongodb.DBObject;
* Integration tests for {@link MappingMongoConverterParser}.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class MappingMongoConverterParserIntegrationTests {
@@ -61,6 +64,15 @@ public class MappingMongoConverterParserIntegrationTests {
factory.getBean("converter");
}
@Test
public void hasCustomTypeMapper() {
MappingMongoConverter converter = factory.getBean("converter", MappingMongoConverter.class);
MongoTypeMapper customMongoTypeMapper = factory.getBean(CustomMongoTypeMapper.class);
assertThat(converter.getTypeMapper(), is(customMongoTypeMapper));
}
@Test
public void scansForConverterAndSetsUpCustomConversionsAccordingly() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2013 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.
@@ -33,6 +33,7 @@ import org.springframework.core.io.ClassPathResource;
*
* @see DATAMONGO-36
* @author Maciej Walkowiak
* @author Thomas Darimont
*/
public class MappingMongoConverterParserValidationIntegrationTests {
@@ -65,4 +66,11 @@ public class MappingMongoConverterParserValidationIntegrationTests {
reader.loadBeanDefinitions(new ClassPathResource("namespace/converter-validation-disabled.xml"));
factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER);
}
@Test
public void validatingEventListenerCreatedWithCustomTypeMapperConfig() {
reader.loadBeanDefinitions(new ClassPathResource("namespace/converter-custom-typeMapper.xml"));
assertThat(factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER), is(not(nullValue())));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2013 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.
@@ -20,6 +20,8 @@ import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -28,7 +30,9 @@ import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionSynchronizationUtils;
import com.mongodb.DB;
import com.mongodb.Mongo;
@@ -37,12 +41,12 @@ import com.mongodb.Mongo;
* Unit tests for {@link MongoDbUtils}.
*
* @author Oliver Gierke
* @author Randy Watler
*/
@RunWith(MockitoJUnitRunner.class)
public class MongoDbUtilsUnitTests {
@Mock
Mongo mongo;
@Mock Mongo mongo;
@Before
public void setUp() throws Exception {
@@ -81,4 +85,94 @@ public class MongoDbUtilsUnitTests {
assertThat(first, is(notNullValue()));
assertThat(MongoDbUtils.getDB(mongo, "first"), is(sameInstance(first)));
}
/**
* @see DATAMONGO-737
*/
@Test
public void handlesTransactionSynchronizationLifecycle() {
// ensure transaction synchronization manager has no registered
// transaction synchronizations or bound resources at start of test
assertThat(TransactionSynchronizationManager.getSynchronizations().isEmpty(), is(true));
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(true));
// access database for one mongo instance, (registers transaction
// synchronization and binds transaction resource)
MongoDbUtils.getDB(mongo, "first");
// ensure transaction synchronization manager has registered
// transaction synchronizations and bound resources
assertThat(TransactionSynchronizationManager.getSynchronizations().isEmpty(), is(false));
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(false));
// simulate transaction completion, (unbinds transaction resource)
try {
simulateTransactionCompletion();
} catch (Exception e) {
fail("Unexpected exception thrown during transaction completion: " + e);
}
// ensure transaction synchronization manager has no bound resources
// at end of test
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(true));
}
/**
* @see DATAMONGO-737
*/
@Test
public void handlesTransactionSynchronizationsLifecycle() {
// ensure transaction synchronization manager has no registered
// transaction synchronizations or bound resources at start of test
assertThat(TransactionSynchronizationManager.getSynchronizations().isEmpty(), is(true));
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(true));
// access multiple databases for one mongo instance, (registers
// transaction synchronizations and binds transaction resources)
MongoDbUtils.getDB(mongo, "first");
MongoDbUtils.getDB(mongo, "second");
// ensure transaction synchronization manager has registered
// transaction synchronizations and bound resources
assertThat(TransactionSynchronizationManager.getSynchronizations().isEmpty(), is(false));
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(false));
// simulate transaction completion, (unbinds transaction resources)
try {
simulateTransactionCompletion();
} catch (Exception e) {
fail("Unexpected exception thrown during transaction completion: " + e);
}
// ensure transaction synchronization manager has no bound
// transaction resources at end of test
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(true));
}
/**
* Simulate transaction rollback/commit completion protocol on managed transaction synchronizations which will unbind
* managed transaction resources. Does not swallow exceptions for testing purposes.
*
* @see TransactionSynchronizationUtils#triggerBeforeCompletion()
* @see TransactionSynchronizationUtils#triggerAfterCompletion(int)
*/
private void simulateTransactionCompletion() {
// triggerBeforeCompletion() implementation without swallowed exceptions
List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
for (TransactionSynchronization synchronization : synchronizations) {
synchronization.beforeCompletion();
}
// triggerAfterCompletion() implementation without swallowed exceptions
List<TransactionSynchronization> remainingSynchronizations = TransactionSynchronizationManager
.getSynchronizations();
if (remainingSynchronizations != null) {
for (TransactionSynchronization remainingSynchronization : remainingSynchronizations) {
remainingSynchronization.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
}
}
}
}

View File

@@ -22,6 +22,7 @@ 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.query.Update.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@@ -112,8 +113,8 @@ public class MongoTemplateTests {
mappingContext.setInitialEntitySet(new HashSet<Class<?>>(Arrays.asList(PersonWith_idPropertyOfTypeObjectId.class,
PersonWith_idPropertyOfTypeString.class, PersonWithIdPropertyOfTypeObjectId.class,
PersonWithIdPropertyOfTypeString.class, PersonWithIdPropertyOfTypeInteger.class,
PersonWithIdPropertyOfPrimitiveInt.class, PersonWithIdPropertyOfTypeLong.class,
PersonWithIdPropertyOfPrimitiveLong.class)));
PersonWithIdPropertyOfTypeBigInteger.class, PersonWithIdPropertyOfPrimitiveInt.class,
PersonWithIdPropertyOfTypeLong.class, PersonWithIdPropertyOfPrimitiveLong.class)));
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
mappingContext.initialize();
@@ -142,6 +143,7 @@ public class MongoTemplateTests {
template.dropCollection(PersonWithIdPropertyOfTypeObjectId.class);
template.dropCollection(PersonWithIdPropertyOfTypeString.class);
template.dropCollection(PersonWithIdPropertyOfTypeInteger.class);
template.dropCollection(PersonWithIdPropertyOfTypeBigInteger.class);
template.dropCollection(PersonWithIdPropertyOfPrimitiveInt.class);
template.dropCollection(PersonWithIdPropertyOfTypeLong.class);
template.dropCollection(PersonWithIdPropertyOfPrimitiveLong.class);
@@ -478,6 +480,25 @@ public class MongoTemplateTests {
assertThat(p9q.getId(), is(p9.getId()));
checkCollectionContents(PersonWithIdPropertyOfTypeInteger.class, 1);
/*
* @see DATAMONGO-602
*/
// BigInteger id - provided
PersonWithIdPropertyOfTypeBigInteger p9bi = new PersonWithIdPropertyOfTypeBigInteger();
p9bi.setFirstName("Sven_9bi");
p9bi.setAge(22);
p9bi.setId(BigInteger.valueOf(12345));
// insert
mongoTemplate.insert(p9bi);
// also try save
mongoTemplate.save(p9bi);
assertThat(p9bi.getId(), notNullValue());
PersonWithIdPropertyOfTypeBigInteger p9qbi = mongoTemplate.findOne(new Query(where("id").in(p9bi.getId())),
PersonWithIdPropertyOfTypeBigInteger.class);
assertThat(p9qbi, notNullValue());
assertThat(p9qbi.getId(), is(p9bi.getId()));
checkCollectionContents(PersonWithIdPropertyOfTypeBigInteger.class, 1);
// int id - provided
PersonWithIdPropertyOfPrimitiveInt p10 = new PersonWithIdPropertyOfPrimitiveInt();
p10.setFirstName("Sven_10");
@@ -702,6 +723,47 @@ public class MongoTemplateTests {
assertThat(results3.size(), is(2));
}
/**
* @see DATAMONGO-602
*/
@Test
public void testUsingAnInQueryWithBigIntegerId() throws Exception {
template.remove(new Query(), PersonWithIdPropertyOfTypeBigInteger.class);
PersonWithIdPropertyOfTypeBigInteger p1 = new PersonWithIdPropertyOfTypeBigInteger();
p1.setFirstName("Sven");
p1.setAge(11);
p1.setId(new BigInteger("2666666666666666665069473312490162649510603601"));
template.insert(p1);
PersonWithIdPropertyOfTypeBigInteger p2 = new PersonWithIdPropertyOfTypeBigInteger();
p2.setFirstName("Mary");
p2.setAge(21);
p2.setId(new BigInteger("2666666666666666665069473312490162649510603602"));
template.insert(p2);
PersonWithIdPropertyOfTypeBigInteger p3 = new PersonWithIdPropertyOfTypeBigInteger();
p3.setFirstName("Ann");
p3.setAge(31);
p3.setId(new BigInteger("2666666666666666665069473312490162649510603603"));
template.insert(p3);
PersonWithIdPropertyOfTypeBigInteger p4 = new PersonWithIdPropertyOfTypeBigInteger();
p4.setFirstName("John");
p4.setAge(41);
p4.setId(new BigInteger("2666666666666666665069473312490162649510603604"));
template.insert(p4);
Query q1 = new Query(Criteria.where("age").in(11, 21, 41));
List<PersonWithIdPropertyOfTypeBigInteger> results1 = template.find(q1, PersonWithIdPropertyOfTypeBigInteger.class);
Query q2 = new Query(Criteria.where("firstName").in("Ann", "Mary"));
List<PersonWithIdPropertyOfTypeBigInteger> results2 = template.find(q2, PersonWithIdPropertyOfTypeBigInteger.class);
Query q3 = new Query(Criteria.where("id").in(new BigInteger("2666666666666666665069473312490162649510603601"),
new BigInteger("2666666666666666665069473312490162649510603604")));
List<PersonWithIdPropertyOfTypeBigInteger> results3 = template.find(q3, PersonWithIdPropertyOfTypeBigInteger.class);
assertThat(results1.size(), is(3));
assertThat(results2.size(), is(2));
assertThat(results3.size(), is(2));
}
@Test
public void testUsingAnInQueryWithPrimitiveIntId() throws Exception {

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2010-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import java.math.BigInteger;
public class PersonWithIdPropertyOfTypeBigInteger {
private BigInteger id;
private String firstName;
private int age;
public BigInteger getId() {
return id;
}
public void setId(BigInteger id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "PersonWithIdPropertyOfTypeInteger [id=" + id + ", firstName=" + firstName + ", age=" + age + "]";
}
}

View File

@@ -16,10 +16,10 @@
package org.springframework.data.mongodb.core.aggregation;
import org.junit.Test;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
/**
* Unit tests for {@link Aggregation}.
*
* @author Oliver Gierke
*/
public class AggregationUnitTests {

View File

@@ -59,17 +59,6 @@ public class GroupOperationUnitTests {
assertThat(idClause.get("b"), is((Object) "$c"));
}
@Test
public void shouldCreateComplexIdForGroupOperationWithSingleComplexIdField() {
// Fields fields = fields().and("a", 42);
// GroupOperation groupOperation = new GroupOperation(fields());
//
// assertThat(groupOperation.toDBObject(Aggregation.DEFAULT_CONTEXT), is(notNullValue()));
// assertThat(groupOperation.id, is(notNullValue()));
// assertThat(groupOperation.id, is((Object) new BasicDBObject("a", 42)));
}
@Test
public void groupFactoryMethodWithMultipleFieldsAndSumOperation() {

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2013 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.aggregation;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
/**
* Unit tests for {@link TypeBasedAggregationOperationContext}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class TypeBasedAggregationOperationContextUnitTests {
MongoMappingContext context;
MappingMongoConverter converter;
QueryMapper mapper;
@Mock MongoDbFactory dbFactory;
@Before
public void setUp() {
this.context = new MongoMappingContext();
this.converter = new MappingMongoConverter(dbFactory, context);
this.mapper = new QueryMapper(converter);
}
@Test
public void findsSimpleReference() {
assertThat(getContext(Foo.class).getReference("bar"), is(notNullValue()));
}
@Test(expected = PropertyReferenceException.class)
public void rejectsInvalidFieldReference() {
getContext(Foo.class).getReference("foo");
}
/**
* @see DATAMONGO-741
*/
@Test
public void returnsReferencesToNestedFieldsCorrectly() {
AggregationOperationContext context = getContext(Foo.class);
Field field = Fields.field("bar.name");
assertThat(context.getReference("bar.name"), is(notNullValue()));
assertThat(context.getReference(field), is(notNullValue()));
assertThat(context.getReference(field), is(context.getReference("bar.name")));
}
private TypeBasedAggregationOperationContext getContext(Class<?> type) {
return new TypeBasedAggregationOperationContext(type, context, mapper);
}
static class Foo {
Bar bar;
}
static class Bar {
String name;
}
}

View File

@@ -1415,6 +1415,16 @@ public class MappingMongoConverterUnitTests {
assertThat(((Person) value).lastname, is("converter"));
}
/**
* @see DATAMONGO-743
*/
@Test
public void readsIntoStringsOutOfTheBox() {
DBObject dbObject = new BasicDBObject("firstname", "Dave");
assertThat(converter.read(String.class, dbObject), is("{ \"firstname\" : \"Dave\"}"));
}
@Document
class MapDBRef {
@org.springframework.data.mongodb.core.mapping.DBRef Map<String, MapDBRefVal> map;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2013 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.
@@ -24,6 +24,10 @@ import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class CriteriaTests {
@Test
@@ -68,4 +72,50 @@ public class CriteriaTests {
assertThat(left, is(not(right)));
assertThat(right, is(not(left)));
}
/**
* @see DATAMONGO-507
*/
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionWhenTryingToNegateAndOperation() {
new Criteria() //
.not() //
.andOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
}
/**
* @see DATAMONGO-507
*/
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionWhenTryingToNegateOrOperation() {
new Criteria() //
.not() //
.orOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
}
/**
* @see DATAMONGO-507
*/
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionWhenTryingToNegateNorOperation() {
new Criteria() //
.not() //
.norOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
}
/**
* @see DATAMONGO-507
*/
@Test
public void shouldNegateFollowingSimpleExpression() {
Criteria c = Criteria.where("age").not().gt(18).and("status").is("student");
DBObject co = c.getCriteriaObject();
assertThat(co, is(notNullValue()));
assertThat(co.toString(), is("{ \"age\" : { \"$not\" : { \"$gt\" : 18}} , \"status\" : \"student\"}"));
}
}

View File

@@ -19,14 +19,18 @@ import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.geo.Distance;
import org.springframework.data.mongodb.core.geo.Metric;
import org.springframework.data.mongodb.core.geo.Metrics;
import org.springframework.data.mongodb.core.geo.Point;
/**
* Unit tests for {@link NearQuery}.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class NearQueryUnitTests {
@@ -75,4 +79,48 @@ public class NearQueryUnitTests {
query = query.maxDistance(new Distance(200, Metrics.KILOMETERS));
assertThat(query.getMetric(), is((Metric) Metrics.MILES));
}
/**
* @see DATAMONGO-445
*/
@Test
public void shouldTakeSkipAndLimitSettingsFromGivenPageable() {
Pageable pageable = new PageRequest(3, 5);
NearQuery query = NearQuery.near(new Point(1, 1)).with(pageable);
assertThat(query.getSkip(), is(pageable.getPageNumber() * pageable.getPageSize()));
assertThat((Integer) query.toDBObject().get("num"), is((pageable.getPageNumber() + 1) * pageable.getPageSize()));
}
/**
* @see DATAMONGO-445
*/
@Test
public void shouldTakeSkipAndLimitSettingsFromGivenQuery() {
int limit = 10;
int skip = 5;
NearQuery query = NearQuery.near(new Point(1, 1)).query(
Query.query(Criteria.where("foo").is("bar")).limit(limit).skip(skip));
assertThat(query.getSkip(), is(skip));
assertThat((Integer) query.toDBObject().get("num"), is(limit));
}
/**
* @see DATAMONGO-445
*/
@Test
public void shouldTakeSkipAndLimitSettingsFromPageableEvenIfItWasSpecifiedOnQuery() {
int limit = 10;
int skip = 5;
Pageable pageable = new PageRequest(3, 5);
NearQuery query = NearQuery.near(new Point(1, 1))
.query(Query.query(Criteria.where("foo").is("bar")).limit(limit).skip(skip)).with(pageable);
assertThat(query.getSkip(), is(pageable.getPageNumber() * pageable.getPageSize()));
assertThat((Integer) query.toDBObject().get("num"), is((pageable.getPageNumber() + 1) * pageable.getPageSize()));
}
}

View File

@@ -590,4 +590,94 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
assertThat(result, hasSize(2));
assertThat(result, hasItems(dave, oliver));
}
/**
* @see DATAMONGO-445
*/
@Test
public void executesGeoPageQueryForWithPageRequestForPageInBetween() {
Point farAway = new Point(-73.9, 40.7);
Point here = new Point(-73.99, 40.73);
dave.setLocation(farAway);
oliver.setLocation(here);
carter.setLocation(here);
boyd.setLocation(here);
leroi.setLocation(here);
repository.save(Arrays.asList(dave, oliver, carter, boyd, leroi));
GeoPage<Person> results = repository.findByLocationNear(new Point(-73.99, 40.73), new Distance(2000,
Metrics.KILOMETERS), new PageRequest(1, 2));
assertThat(results.getContent().isEmpty(), is(false));
assertThat(results.getNumberOfElements(), is(2));
assertThat(results.isFirstPage(), is(false));
assertThat(results.isLastPage(), is(false));
assertThat(results.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
assertThat(results.getAverageDistance().getNormalizedValue(), is(0.0));
}
/**
* @see DATAMONGO-445
*/
@Test
public void executesGeoPageQueryForWithPageRequestForPageAtTheEnd() {
Point point = new Point(-73.99171, 40.738868);
dave.setLocation(point);
oliver.setLocation(point);
carter.setLocation(point);
repository.save(Arrays.asList(dave, oliver, carter));
GeoPage<Person> results = repository.findByLocationNear(new Point(-73.99, 40.73), new Distance(2000,
Metrics.KILOMETERS), new PageRequest(1, 2));
assertThat(results.getContent().isEmpty(), is(false));
assertThat(results.getNumberOfElements(), is(1));
assertThat(results.isFirstPage(), is(false));
assertThat(results.isLastPage(), is(true));
assertThat(results.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
}
/**
* @see DATAMONGO-445
*/
@Test
public void executesGeoPageQueryForWithPageRequestForJustOneElement() {
Point point = new Point(-73.99171, 40.738868);
dave.setLocation(point);
repository.save(dave);
GeoPage<Person> results = repository.findByLocationNear(new Point(-73.99, 40.73), new Distance(2000,
Metrics.KILOMETERS), new PageRequest(0, 2));
assertThat(results.getContent().isEmpty(), is(false));
assertThat(results.getNumberOfElements(), is(1));
assertThat(results.isFirstPage(), is(true));
assertThat(results.isLastPage(), is(true));
assertThat(results.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
}
/**
* @see DATAMONGO-445
*/
@Test
public void executesGeoPageQueryForWithPageRequestForJustOneElementEmptyPage() {
dave.setLocation(new Point(-73.99171, 40.738868));
repository.save(dave);
GeoPage<Person> results = repository.findByLocationNear(new Point(-73.99, 40.73), new Distance(2000,
Metrics.KILOMETERS), new PageRequest(1, 2));
assertThat(results.getContent().isEmpty(), is(true));
assertThat(results.getNumberOfElements(), is(0));
assertThat(results.isFirstPage(), is(false));
assertThat(results.isLastPage(), is(true));
assertThat(results.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<mongo:mapping-converter type-mapper-ref="customMongoTypeMapper"/>
<bean name="customMongoTypeMapper" class="org.springframework.data.mongodb.config.CustomMongoTypeMapper"/>
</beans>

View File

@@ -5,12 +5,14 @@
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<mongo:mapping-converter id="converter" db-factory-ref="factory">
<mongo:mapping-converter id="converter" db-factory-ref="factory" type-mapper-ref="customMongoTypeMapper">
<mongo:custom-converters base-package="org.springframework.data.mongodb.config" />
</mongo:mapping-converter>
<mongo:db-factory id="factory" />
<mongo:mapping-converter id="abbreviatingConverter" abbreviate-field-names="true" />
<bean name="customMongoTypeMapper" class="org.springframework.data.mongodb.config.CustomMongoTypeMapper"/>
</beans>

View File

@@ -35,8 +35,7 @@
<constructor-arg name="mongoConverter" ref="mappingConverter1"/>
</bean>
<mongo:mapping-converter id="mappingConverter2" base-package="org.springframework.data.mongodb.core.mapping"
mongo-template-ref="mongoTemplate2">
<mongo:mapping-converter id="mappingConverter2" base-package="org.springframework.data.mongodb.core.mapping">
<mongo:custom-converters>
<mongo:converter>
<bean class="org.springframework.data.mongodb.core.PersonReadConverter"/>

View File

@@ -56,7 +56,7 @@
<xi:include href="introduction/why-sd-doc.xml"/>
<xi:include href="introduction/requirements.xml"/>
<xi:include href="introduction/getting-started.xml"/>
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.6.0.RC1/src/docbkx/repositories.xml">
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.6.0.RELEASE/src/docbkx/repositories.xml">
<xi:fallback href="../../../spring-data-commons/src/docbkx/repositories.xml" />
</xi:include>
</part>
@@ -76,10 +76,10 @@
<part id="appendix">
<title>Appendix</title>
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.6.0.RC1/src/docbkx/repository-namespace-reference.xml">
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.6.1.RELEASE/src/docbkx/repository-namespace-reference.xml">
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-namespace-reference.xml" />
</xi:include>
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.6.0.RC1/src/docbkx/repository-query-keywords-reference.xml">
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.6.1.RELEASE/src/docbkx/repository-query-keywords-reference.xml">
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-query-keywords-reference.xml" />
</xi:include>
</part>

View File

@@ -542,4 +542,52 @@ Page&lt;Person&gt; page = repository.findAll(person.lastname.contains("a"),
MongoDB queries.</para>
</section>
</section>
<section>
<title>Miscellaneous</title>
<para/>
<section>
<title>CDI Integration</title>
<para>Instances of the repository interfaces are usually created by a
container, which Spring is the most natural choice when working with
Spring Data. As of version 1.3.0 Spring Data MongoDB ships with a custom
CDI extension that allows using the repository abstraction in CDI
environments. The extension is part of the JAR so all you need to do to
activate it is dropping the Spring Data MongoDB JAR into your classpath.
You can now set up the infrastructure by implementing a CDI Producer for
the <classname>MongoTemplate</classname>:</para>
<programlisting language="java">class MongoTemplateProducer {
@Produces
@ApplicationScoped
public MongoOperations createMongoTemplate() throws UnknownHostException, MongoException {
MongoDbFactory factory = new SimpleMongoDbFactory(new Mongo(), "database");
return new MongoTemplate(factory);
}
}</programlisting>
<para>The Spring Data MongoDB CDI extension will pick up the
<classname>MongoTemplate</classname> available as CDI bean and create a
proxy for a Spring Data repository whenever an bean of a repository type
is requested by the container. Thus obtaining an instance of a Spring
Data repository is a matter of declaring an <code>@Inject</code>-ed
property:</para>
<programlisting language="java">class RepositoryClient {
@Inject
PersonRepository repository;
public void businessMethod() {
List&lt;Person&gt; people = repository.findAll();
}
}</programlisting>
</section>
</section>
</chapter>

View File

@@ -1057,6 +1057,77 @@ mongoTemplate.save(sample);
instance of that interface can be configured at the
<classname>DefaultMongoTypeMapper</classname> which can be configured
in turn on <classname>MappingMongoConverter</classname>.</para>
<example>
<title>Defining a TypeAlias for an Entity</title>
<programlisting language="java">@TypeAlias("pers")
class Person {
}</programlisting>
<para>Note that the resulting document will contain
<code>"pers"</code> as the value in the <code>_class</code>
Field.</para>
</example>
</simplesect>
<simplesect>
<title>Configuring custom type mapping</title>
<para>The following example demonstrates how to configure a custom
<classname>MongoTypeMapper</classname> in
<classname>MappingMongoConverter</classname>.</para>
<example>
<title>Configuring a custom MongoTypeMapper via Spring Java
Config</title>
<programlisting language="java">class CustomMongoTypeMapper extends DefaultMongoTypeMapper {
//implement custom type mapping here
}</programlisting>
<programlisting language="java">@Configuration
class SampleMongoConfiguration extends AbstractMongoConfiguration {
@Override
protected String getDatabaseName() {
return "database";
}
@Override
public Mongo mongo() throws Exception {
return new Mongo();
}
@Bean
@Override
public MappingMongoConverter mappingMongoConverter() throws Exception {
MappingMongoConverter mmc = super.mappingMongoConverter();
mmc.setTypeMapper(customTypeMapper());
return mmc;
}
@Bean
public MongoTypeMapper customTypeMapper() {
return new CustomMongoTypeMapper();
}
}</programlisting>
<para>Note that we are extending the
<classname>AbstractMongoConfiguration</classname> class and override
the bean definition of the
<classname>MappingMongoConverter</classname> where we configure our
custom <classname>MongoTypeMapper</classname>. </para>
</example>
<example>
<title>Configuring a custom MongoTypeMapper via XML</title>
<programlisting language="xml">&lt;mongo:mapping-converter type-mapper-ref="customMongoTypeMapper"/&gt;
&lt;bean name="customMongoTypeMapper" class="com.bubu.mongo.CustomMongoTypeMapper"/&gt;</programlisting>
</example>
</simplesect>
</section>

View File

@@ -1,6 +1,28 @@
Spring Data MongoDB Changelog
=============================
Changes in version 1.3.1.RELEASE (2013-09-09)
---------------------------------------------
** Task
* [DATAMONGO-751] Upgraded to Spring Data Commons 1.6.1.
Changes in version 1.3.0.RELEASE (2013-09-09)
---------------------------------------------
** Bug
* [DATAMONGO-540] MongoTemplate upsert and findOne handle id queries differently.
* [DATAMONGO-445] GeoNear Query Doesn't Work with Pageable.
* [DATAMONGO-507] Criteria not() is not working.
* [DATAMONGO-602] Querying with $in operator on the id field of type BigInteger returns zero results.
** Improvement
* [DATAMONGO-725] Improve configurability and documentation of TypeMapper on MappingMongoConverter.
* [DATAMONGO-738] Add methods to MongoTemplate and MongoOperations to allow calling class to pass both the entityClass and the collectionName for the update and upsert methods.
* [DATAMONGO-737] Extra MongoSynchronizations cause TransactionSynchronizationManager to throw IllegalStateException on transaction complete.
* [DATAMONGO-743] Support returning raw json from a query.
** Task
* [DATAMONGO-742] Document CDI integration in reference documentation.
Changes in version 1.3.0.RC1 (2013-08-05)
-----------------------------------------
** Bug

View File

@@ -1,4 +1,4 @@
Spring Data Document 1.3 RC1
Spring Data Document 1.3.1 RELEASE
Copyright (c) [2010-2013] Pivotal Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").

View File

@@ -1,4 +1,4 @@
SPRING DATA MongoDB 1.3.0.RC1
SPRING DATA MongoDB 1.3.0.RELEASE
-----------------------------
Spring Data MongoDB is released under the terms of the Apache Software License Version 2.0 (see license.txt).