diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml
index 94363c698..f9fa823df 100644
--- a/spring-data-mongodb/pom.xml
+++ b/spring-data-mongodb/pom.xml
@@ -18,11 +18,12 @@
1.0.0.GA
1.3
+ 1.5
-
+
org.springframework
spring-tx
@@ -50,7 +51,7 @@
spring-expression
-
+
${project.groupId}
spring-data-commons
@@ -144,6 +145,12 @@
test
+
+ nl.jqno.equalsverifier
+ equalsverifier
+ ${equalsverifier}
+ test
+
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/BasicQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/BasicQuery.java
index d278ec46b..ac36d0de7 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/BasicQuery.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/BasicQuery.java
@@ -15,6 +15,8 @@
*/
package org.springframework.data.mongodb.core.query;
+import static org.springframework.util.ObjectUtils.*;
+
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;
@@ -25,6 +27,7 @@ import com.mongodb.util.JSON;
* @author Thomas Risberg
* @author Oliver Gierke
* @author Christoph Strobl
+ * @author Thomas Darimont
*/
public class BasicQuery extends Query {
@@ -97,4 +100,42 @@ public class BasicQuery extends Query {
protected void setFieldsObject(DBObject fieldsObject) {
this.fieldsObject = fieldsObject;
}
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.Query#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object o) {
+
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof BasicQuery)) {
+ return false;
+ }
+
+ BasicQuery that = (BasicQuery) o;
+
+ return querySettingsEquals(that) && //
+ nullSafeEquals(fieldsObject, that.fieldsObject) && //
+ nullSafeEquals(queryObject, that.queryObject) && //
+ nullSafeEquals(sortObject, that.sortObject);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.Query#hashCode()
+ */
+ @Override
+ public int hashCode() {
+
+ int result = super.hashCode();
+ result = 31 * result + nullSafeHashCode(queryObject);
+ result = 31 * result + nullSafeHashCode(fieldsObject);
+ result = 31 * result + nullSafeHashCode(sortObject);
+
+ 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 9156a342a..f400baefe 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
@@ -385,12 +385,21 @@ public class Query {
return false;
}
- Query that = (Query) obj;
+ return querySettingsEquals((Query) obj);
+ }
+
+ /**
+ * Tests whether the settings of the given {@link Query} are equal to this query.
+ *
+ * @param that
+ * @return
+ */
+ protected boolean querySettingsEquals(Query that) {
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 fieldsEqual = nullSafeEquals(this.fieldSpec, that.fieldSpec);
+ boolean sortEqual = nullSafeEquals(this.sort, that.sort);
+ boolean hintEqual = nullSafeEquals(this.hint, that.hint);
boolean skipEqual = this.skip == that.skip;
boolean limitEqual = this.limit == that.limit;
boolean metaEqual = nullSafeEquals(this.meta, that.meta);
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/BasicQueryUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/BasicQueryUnitTests.java
index 5e4f3317e..1890267c3 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/BasicQueryUnitTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/BasicQueryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2012 the original author or authors.
+ * Copyright 2011-2014 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,8 @@ package org.springframework.data.mongodb.core.query;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.core.query.Criteria.*;
+import nl.jqno.equalsverifier.EqualsVerifier;
+import nl.jqno.equalsverifier.Warning;
import org.junit.Test;
import org.springframework.data.domain.Sort.Direction;
@@ -29,6 +31,7 @@ import com.mongodb.DBObject;
* Unit tests for {@link BasicQuery}.
*
* @author Oliver Gierke
+ * @author Thomas Darimont
*/
public class BasicQueryUnitTests {
@@ -58,4 +61,80 @@ public class BasicQueryUnitTests {
sortReference.put("lastname", 1);
assertThat(query.getSortObject(), is(sortReference));
}
+
+ /**
+ * @see DATAMONGO-1093
+ */
+ @Test
+ public void equalsContract() {
+
+ BasicQuery query1 = new BasicQuery("{ \"name\" : \"Thomas\"}", "{\"name\":1, \"age\":1}");
+ query1.setSortObject(new BasicDBObject("name", -1));
+
+ BasicQuery query2 = new BasicQuery("{ \"name\" : \"Oliver\"}", "{\"name\":1, \"address\":1}");
+ query2.setSortObject(new BasicDBObject("name", 1));
+
+ EqualsVerifier.forExamples(query1, query2) //
+ .withRedefinedSuperclass() //
+ .suppress(Warning.NONFINAL_FIELDS, Warning.NULL_FIELDS, Warning.STRICT_INHERITANCE) //
+ .verify();
+ }
+
+ /**
+ * @see DATAMONGO-1093
+ */
+ @Test
+ public void handlesEqualsAndHashCodeCorrectlyForExactCopies() {
+
+ String qry = "{ \"name\" : \"Thomas\"}";
+ String fields = "{\"name\":1, \"age\":1}";
+
+ BasicQuery query1 = new BasicQuery(qry, fields);
+ query1.setSortObject(new BasicDBObject("name", -1));
+
+ BasicQuery query2 = new BasicQuery(qry, fields);
+ query2.setSortObject(new BasicDBObject("name", -1));
+
+ assertThat(query1, is(equalTo(query1)));
+ assertThat(query1, is(equalTo(query2)));
+ assertThat(query1.hashCode(), is(query2.hashCode()));
+ }
+
+ /**
+ * @see DATAMONGO-1093
+ */
+ @Test
+ public void handlesEqualsAndHashCodeCorrectlyWhenBasicQuerySettingsDiffer() {
+
+ String qry = "{ \"name\" : \"Thomas\"}";
+ String fields = "{\"name\":1, \"age\":1}";
+
+ BasicQuery query1 = new BasicQuery(qry, fields);
+ query1.setSortObject(new BasicDBObject("name", -1));
+
+ BasicQuery query2 = new BasicQuery(qry, fields);
+ query2.setSortObject(new BasicDBObject("name", 1));
+
+ assertThat(query1, is(not(equalTo(query2))));
+ assertThat(query1.hashCode(), is(not(query2.hashCode())));
+ }
+
+ /**
+ * @see DATAMONGO-1093
+ */
+ @Test
+ public void handlesEqualsAndHashCodeCorrectlyWhenQuerySettingsDiffer() {
+
+ String qry = "{ \"name\" : \"Thomas\"}";
+ String fields = "{\"name\":1, \"age\":1}";
+
+ BasicQuery query1 = new BasicQuery(qry, fields);
+ query1.getMeta().setComment("foo");
+
+ BasicQuery query2 = new BasicQuery(qry, fields);
+ query2.getMeta().setComment("bar");
+
+ assertThat(query1, is(not(equalTo(query2))));
+ assertThat(query1.hashCode(), is(not(query2.hashCode())));
+ }
}