DATAMONGO-1778 - Fix equals() and hashCode() for Update.

We now include the entire update document with its modifiers and the isolation flag when computing the hash code and comparing for object equality.

Original pull request: #503.
This commit is contained in:
Christoph Strobl
2017-09-21 14:55:04 +02:00
committed by Mark Paluch
parent dbd38a8e82
commit c05f8f056c
2 changed files with 103 additions and 65 deletions

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.mongodb.core.query;
import static org.springframework.util.ObjectUtils.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -34,6 +32,7 @@ import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -465,7 +464,7 @@ public class Update {
*/
@Override
public int hashCode() {
return getUpdateObject().hashCode();
return Objects.hash(getUpdateObject(), isolated);
}
/*
@@ -484,6 +483,10 @@ public class Update {
}
Update that = (Update) obj;
if (this.isolated != that.isolated) {
return false;
}
return Objects.equals(this.getUpdateObject(), that.getUpdateObject());
}
@@ -539,7 +542,7 @@ public class Update {
*/
@Override
public int hashCode() {
return nullSafeHashCode(modifiers);
return Objects.hashCode(modifiers);
}
/*
@@ -558,7 +561,6 @@ public class Update {
}
Modifiers that = (Modifiers) obj;
return Objects.equals(this.modifiers, that.modifiers);
}
@@ -594,13 +596,63 @@ public class Update {
}
}
/**
* Abstract {@link Modifier} implementation with defaults for {@link Object#equals(Object)}, {@link Object#hashCode()}
* and {@link Object#toString()}.
*
* @author Christoph Strobl
* @since 2.0
*/
private static abstract class AbstractModifier implements Modifier {
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(getKey()) + ObjectUtils.nullSafeHashCode(getValue());
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null || getClass() != that.getClass()) {
return false;
}
if (!Objects.equals(getKey(), ((Modifier) that).getKey())) {
return false;
}
return Objects.deepEquals(getValue(), ((Modifier) that).getValue());
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return toJsonString();
}
}
/**
* Implementation of {@link Modifier} representing {@code $each}.
*
* @author Christoph Strobl
* @author Thomas Darimont
*/
private static class Each implements Modifier {
private static class Each extends AbstractModifier {
private Object[] values;
@@ -638,38 +690,6 @@ public class Update {
public Object getValue() {
return this.values;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return nullSafeHashCode(values);
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null || getClass() != that.getClass()) {
return false;
}
return nullSafeEquals(values, ((Each) that).values);
}
@Override
public String toString() {
return toJsonString();
}
}
/**
@@ -678,7 +698,7 @@ public class Update {
* @author Christoph Strobl
* @since 1.7
*/
private static class PositionModifier implements Modifier {
private static class PositionModifier extends AbstractModifier {
private final int position;
@@ -695,11 +715,6 @@ public class Update {
public Object getValue() {
return position;
}
@Override
public String toString() {
return toJsonString();
}
}
/**
@@ -708,7 +723,7 @@ public class Update {
* @author Mark Paluch
* @since 1.10
*/
private static class Slice implements Modifier {
private static class Slice extends AbstractModifier {
private int count;
@@ -733,11 +748,6 @@ public class Update {
public Object getValue() {
return this.count;
}
@Override
public String toString() {
return toJsonString();
}
}
/**
@@ -747,7 +757,7 @@ public class Update {
* @author Mark Paluch
* @since 1.10
*/
private static class SortModifier implements Modifier {
private static class SortModifier extends AbstractModifier {
private final Object sort;
@@ -799,11 +809,6 @@ public class Update {
public Object getValue() {
return this.sort;
}
@Override
public String toString() {
return toJsonString();
}
}
/**
@@ -940,14 +945,7 @@ public class Update {
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * result + getOuterType().hashCode();
result += 31 * result + nullSafeHashCode(key);
result += 31 * result + nullSafeHashCode(modifiers);
return result;
return Objects.hash(getOuterType(), key, modifiers);
}
/*
@@ -971,7 +969,7 @@ public class Update {
return false;
}
return nullSafeEquals(this.key, that.key) && nullSafeEquals(this.modifiers, that.modifiers);
return Objects.equals(this.key, that.key) && Objects.equals(this.modifiers, that.modifiers);
}
private Update getOuterType() {

View File

@@ -485,4 +485,44 @@ public class UpdateTests {
assertThat(new Update().set("key", "value").isolated().toString(),
is(equalTo("{ \"$set\" : { \"key\" : \"value\" }, \"$isolated\" : 1 }")));
}
@Test // DATAMONGO-1778
public void equalsShouldConsiderModifiers() {
Update update1 = new Update().inc("version", 1).push("someField").slice(-10).each("test");
Update update2 = new Update().inc("version", 1).push("someField").slice(-10).each("test");
Update update3 = new Update().inc("version", 1).push("someField").slice(10).each("test");
assertThat(update1, is(equalTo(update2)));
assertThat(update1, is(not(equalTo(update3))));
}
@Test // DATAMONGO-1778
public void equalsShouldConsiderIsolated() {
Update update1 = new Update().inc("version", 1).isolated();
Update update2 = new Update().inc("version", 1).isolated();
assertThat(update1, is(equalTo(update2)));
}
@Test // DATAMONGO-1778
public void hashCodeShouldConsiderModifiers() {
Update update1 = new Update().inc("version", 1).push("someField").slice(-10).each("test");
Update update2 = new Update().inc("version", 1).push("someField").slice(-10).each("test");
Update update3 = new Update().inc("version", 1).push("someField").slice(10).each("test");
assertThat(update1.hashCode(), is(equalTo(update2.hashCode())));
assertThat(update1.hashCode(), is(not(equalTo(update3.hashCode()))));
}
@Test // DATAMONGO-1778
public void hashCodeShouldConsiderIsolated() {
Update update1 = new Update().inc("version", 1).isolated();
Update update2 = new Update().inc("version", 1);
assertThat(update1.hashCode(), is(not(equalTo(update2.hashCode()))));
}
}