I'm new in Mockito.
I have
Map<String, Object> expectedFilter = new HashMap<String, Object>()
expectedFilter.put("ids", new Integer[]{22});
expectedFilter.put("codes", new Integer[]{1});
and write stubbing with using this map as argument. Why does mockito call Object's equals while the real type of value in the map is Integer?
Thanks!
You're putting Integer[] into the map, not Integers. Integer[] does not override Objects equals, so it will be called. To get around this you could write a wrapper class that calls equals on the contents of the array like this:
public class ArrayWrapper<E> {
private E[] data;
public ArrayWrapper(E[] data) {
this.data = Arrays.copyOf(data, data.length);
}
#Override public boolean equals(Object other) {
if (this == other) return true;
if (!(other instanceof ArrayWrapper)) return false;
ArrayWrapper o = (ArrayWrapper)other;
if (this.data.size != o.data.size) return false;
for (int i = 0; i < this.data.size; i++)
if (!this.data[i].equals(o.data[i]) return false;
return true;
}
}
and add instances of this class to the map instead of Integer[]'s, so this classes equals will be called.
Related
I'm trying to make a generic tuple class. It stores its elements as an ArrayList. Of course, this class should override hashcode and equals methods.
How could I make hashcode method for this class? You see, in the code, I am having trouble.
Also, for the equals method, why does the compiler force me to use the '?'. Why couldn't I just use the T?
public static class Tuple<T> {
ArrayList<T> tuple = new ArrayList<>();
public Tuple(ArrayList<T> items) {
for (T item : items) {
tuple.add(item);
}
}
#Override
public int hashCode() {
T sum = ???;
for (T item : tuple) {
sum += item.hashCode();
}
return sum;
}
#Override
public boolean equals(Object o) {
if (o instanceof Tuple<?>) {
Tuple<?> tup= (Tuple<?>) o;
if (tup.tuple.size() != this.tuple.size()) {
return false;
}
for (int i = 0; i < this.tuple.size(); i++) {
if (this.tuple.get(i) != tup.tuple.get(i)) {
return false;
}
}
return true;
} else {
return false;
}
}
}
As mentioned in the comments, we should delegate the hashCode and the equals methods to the ArrayList<T> tuple instance variable. For the hashCode it's trivial. For the equals it's just a little more complicated than that because we don't want our custom Tuple to be equals with an ArrayList. So here it is:
public class Tuple<T> {
// I made this private because I'm pedantric ;)
private final ArrayList<T> tuple = new ArrayList<>();
// this does the same as your code, it's just easier to read
public Tuple(ArrayList<T> items) {
tuple.addAll(items);
}
#Override
public int hashCode() {
return tuple.hashCode();
}
// generated by eclipse
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Tuple other = (Tuple) obj;
if (tuple == null) {
if (other.tuple != null)
return false;
} else if (!tuple.equals(other.tuple))
return false;
return true;
}
}
If you want to deal with the case when the tuple can be null, then you can use a slightly more complex hashCode:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((tuple == null) ? 0 : tuple.hashCode());
return tuple.hashCode();
}
In general, I don't like to write these methods myself. Usually, I make my IDE to generate the stuff. All I need to take care of is to re-generate it when I add new fields. Apache HashCodeBuilder and EqualsBuilder are also great alternatives.
I am trying to override the mentioned methods for my HashSet:
Set<MyObject> myObjectSet = new HashSet<MyObject>();
MyObject:
public class MyObject implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
String name;
int number;
Map<String,String> myMap;
public MyObject(String name, int number, Map<String,String> myMap) {
this.name = name;
this.number = number;
this.myMap = myMap;
}
[...]
}
How do I override the hashcode(), equals() and compareTo() method?
Currently I have the following:
public int hashCode () {
return id.hashCode();
}
// override the equals method.
public boolean equals(MyObject s) {
return id.equals(s.id);
}
// override compareTo
public int compareTo(MyObject s) {
return id.compareTo(s.id);
}
I read that comparing by id is not enough this is object is a persistent entity for the DB (see here).
The name and number aren't unique across all objects of this type.
So how should I override it?
Do I also need to compare the hashMap inside it?
I am confused. The only unique thing about the object is the the map myMap which gets populated later in the lifecycle.
How do I check for its equality?
Based on all the responses I have changed the methods to the following
#Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final MyComplexObj myComplexObj = (MyComplexObj) o;
return myMap != null ? myMap.equals(myComplexObj.myMap) : myComplexObj.myMap == null;
}
#Override
public int hashCode() {
return myMap != null ? myMap.hashCode() : 0;
}
public int compareTo(MyComplexObj o) {
return myMap.compareTo(o.getMyMap()));
}
This fails at the compareTo method, "this method is undefined for the type Map
The basic question here is "How can you determine if two objects are equal to each other?"
This is a simple question for simple objects. However, it becomes increasingly difficult with even slightly more complex objects.
As stated in the original question:
The only unique thing about the object is the the map myMap which gets populated later in the lifecycle.
Given two instances of the type MyObject, the member variables myMap must be compared with each other. This map is of type Map<String, String>. A few questions immediately come to mind:
How do the keys & values define equality?
(does a key=value pair need to be compared as a unit?)
(or should only the values be compared to each other?)
How does the order of the keys in the map affect equality?
(should keys in the list be sorted, so that A-B-C is equivalent to B-C-A?)
(or does 1-2-3 mean something different than 3-2-1?)
Does upper/lower case make any different to the equality of the values?
Will these objects ever be stored in some kind of Java HashSet or Java TreeSet?
(do you need to store the same object several times in the same collection?)
(or should objects with equal hashcodes only be stored once?)
Will these objects ever require sorting as part of a list or Java Collection?
How should the comparison function arrange non-equal objects in a list?
(how should key order determine if an object will come earlier or later in a list?)
(how should values determine order, especially if several values are different?)
Answers to each of these questions will vary between applications. In order to keep this applicable to a general audience, the following assumptions are being made:
To maintain a deterministic comparison, keys will be sorted
Values will be considered to be case-sensitive
Keys and values are inseparable, and will be compared as a unit
The Map will be flattened into a single String, so results can be compared easily
The beauty of using equals(), hashCode(), and compareTo() is that once hashCode() is implemented properly, the other functions can be defined based on hashCode().
Considering all of that, we have the following implementation:
#Override
public boolean equals(final Object o)
{
if (o instanceof MyObject)
{
return (0 == this.compareTo(((MyObject) o)));
}
return false;
}
#Override
public int hashCode()
{
return getKeyValuePairs(this.myMap).hashCode();
}
// Return a negative integer, zero, or a positive integer
// if this object is less than, equal to, or greater than the other object
public int compareTo(final MyObject o)
{
return this.hashCode() - o.hashCode();
}
// The Map is flattened into a single String for comparison
private static String getKeyValuePairs(final Map<String, String> m)
{
final StringBuilder kvPairs = new StringBuilder();
final String kvSeparator = "=";
final String liSeparator = "^";
if (null != m)
{
final List<String> keys = new ArrayList<>(m.keySet());
Collections.sort(keys);
for (final String key : keys)
{
final String value = m.get(key);
kvPairs.append(liSeparator);
kvPairs.append(key);
kvPairs.append(kvSeparator);
kvPairs.append(null == value ? "" : value);
}
}
return 0 == kvPairs.length() ? "" : kvPairs.substring(liSeparator.length());
}
All the critical work is being done inside of hashCode(). For sorting, the compareTo() function only needs to return a negative/zero/positive number -- a simple hashCode() diff. And the equals() function only needs to return true/false -- a simple check that compareTo() equals zero.
For further reading, there is a famous dialogue by Lewis Carroll on the foundations of logic, which touches on the basic question of equality:
https://en.wikipedia.org/wiki/What_the_Tortoise_Said_to_Achilles
And, in regard to even simple grammatical constructs, there is a fine example of two "equal" sentences at the start of chapter 6, "Pig and Pepper", from Alice in Wonderland:
The Fish-Footman began by producing from under his arm a great letter, and this he handed over to the other, saying, in a solemn tone, "For the Duchess. An invitation from the Queen to play croquet." The Frog-Footman repeated, in the same solemn tone, "From the Queen. An invitation for the Duchess to play croquet." Then they both bowed low and their curls got entangled together.
compareTo() is relevant to sorting. It has no relevance to a HashSet or HashMap.
A properly working equals() and hashCode() are vital for members of hash-based collections. Read their specifications in the Javadoc for Object.
Possibly the definitive recommendations for implementing these are in Joshua Bloch's Effective Java. I recommend reading the relevant chapter -- it's easily Google-able. There's no point in trying to paraphrase it all here.
One thing that may have escaped your notice, is that your field myMap has a working equals() and hashCode() of its own, so you don't have to do anything special with it. If you can guarantee that none of the fields are null, a reasonable hashCode() would be (following Bloch's system):
public int hashCode() {
int result = 44; // arbitrarily chosen
result = 31 * result + (int) (id ^ (id >>> 32));
result = 31 * result + name.hashCode();
result = 31 * result + number;
result = 31 * result + myMap.hashCode();
return result;
}
(You'll need more code if any of these could be null)
Pretty much all IDEs will automatically generate both equals() and hashcode(), using all the fields in the class. They'll use something very similar to Bloch's recommendations. Hunt around the UI. You'll find it.
Another alternative is to use Apache ReflectionUtils, which allows you to simply use:
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
#Override
public boolean equals(final Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
This works out which fields to use at runtime, and applies Bloch's methods.
This is what intellij default option gives
import java.util.Map;
public class MyObject {
String name;
int number;
Map<String,String> myMap;
#Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final MyObject myObject = (MyObject) o;
if (number != myObject.number) return false;
if (name != null ? !name.equals(myObject.name) : myObject.name != null) return false;
return myMap != null ? myMap.equals(myObject.myMap) : myObject.myMap == null;
}
#Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + number;
result = 31 * result + (myMap != null ? myMap.hashCode() : 0);
return result;
}
}
But, since you said
The only unique thing about the object is the the map myMap which gets
populated later in the lifecycle.
I would just keep myMap and skip both name and number (But this begs the question, why would you include a redundant data- name and number in all the elements of your collection?)
Then it becomes
import java.util.Map;
public class MyObject {
String name;
int number;
Map<String,String> myMap;
#Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final MyObject myObject = (MyObject) o;
return myMap != null ? myMap.equals(myObject.myMap) : myObject.myMap == null;
}
#Override
public int hashCode() {
return myMap != null ? myMap.hashCode() : 0;
}
}
Keep in mind that, there are other ways too for the equals and hashcode methods. For example, Here are the options that intelliJ gives for code generation
To Answer Further question about CompareTo
Unlike Equals and Hashcode, here is no contract exist between compareTo and any other behaviors. You don't really need to do anything with compareTo until you want to make use of it for say, sorting. To read more about CompareTo Why should a Java class implement comparable?
If you want to make myMap implements comparable, and any other methods that you want, create decorator that implement comparable interface and delegate all other methods to enclosing myMap instance.
public class ComparableMap implements Map<String, String>, Comparable<Map<String, String>> {
private final Map<String, String> map;
public ComparableMap(Map<String, String> map) {
this.map = map;
}
#Override
public int compareTo(Map<String, String> o) {
int result = 0;
//your implementation based on values on map on you consider one map bigger, less or as same as another
return result;
}
#Override
public boolean equals(Object obj) {
return map.equals(obj);
}
#Override
public int hashCode() {
return map.hashCode();
}
// map implementation methods
#Override
public int size() {
return map.size();
}
#Override
public boolean isEmpty() {
return map.isEmpty();
}
#Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
#Override
public boolean containsValue(Object value) {
return map.containsValue(value);
}
#Override
public String get(Object key) {
return map.get(key);
}
#Override
public String put(String key, String value) {
return map.put(key, value);
}
#Override
public String remove(Object key) {
return map.remove(key);
}
#Override
public void putAll(Map<? extends String, ? extends String> m) {
map.putAll(m);
}
#Override
public void clear() {
map.clear();
}
#Override
public Set<String> keySet() {
return map.keySet();
}
#Override
public Collection<String> values() {
return map.values();
}
#Override
public Set<Entry<String, String>> entrySet() {
return map.entrySet();
}
}
You may use this map in anywhere where you use myMap
public class MyObject implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
String name;
int number;
ComparableMap myMap;
public MyObject(String name, int number, Map<String, String> myMap) {
this.name = name;
this.number = number;
this.myMap = new ComparablemyMap(myMap);
}
#Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final MyComplexObj myComplexObj = (MyComplexObj) o;
return myMap != null ? myMap.equals(myComplexObj.myMap) : myComplexObj.myMap == null;
}
#Override
public int hashCode() {
return myMap != null ? myMap.hashCode() : 0;
}
public int compareTo(MyComplexObj o) {
return myMap.compareTo(o.getMyMap())); //now it works
}
}
I have my object with some feilds.
public class MyObject{
private String a;
private String b;
}
I have a Set contains objects like this :
Set<MyObject> thirdSet = new HashSet<MyObject>();
Set<MyObject> firstSet=getFirstSet();
Set<MyObject> secondSet = getSecondeSet();
for (MyObjectobj : firstSet) {
if (!secondSet.contains(obj)) {
thirdSet.add(obj);
}
}
I need to select all obj that not contains in my secondSet into thridSet (obj with value not by reference)
Is it possible or using collection is more better?
You'll need to override both equals and hashcode methods in your object. I'd recommend using the java 7 Objects utility methods if you can to prevent NullPointerExceptions.
#Override
public boolean equals(Object other) {
if (!(other instanceof MyObject)) {
return false;
}
MyObject that = (MyObject) other;
return Objects.equals(a, that.a) && Objects.equals(b, that.b);
}
#Override
public int hashcode() {
Objects.hash(a, b);
}
I'd also recommend taking a look at the third party library Guava if possible which would simplify your code.
Set<MyObject> thirdSet = new HashSet<>(Sets.difference(firstSet, secondSet));
Note wrapping it in a new HashSet so it can be modified (if you don't need to modify it you can remove that)
You should override Object#equals and Object#hashCode in MyObject.java.
#Override
public boolean equals(Object o) {
if (!(o instanceof MyObject)) {
return false;
}
MyObject m = (MyObject) o;
return a.equals(m.a) && b.equals(m.b);
}
#Override
public int hashCode() {
return Objects.hash(a, b);
}
Also if you're allowed to use external libraries, you should check out Guava's Sets#difference.
I have overridden hashCode() and equals() method in my class Supplier given below.
public class Supplier {
private final String name;
public Supplier(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public int hashCode() {
char[] charArray = name.toCharArray();
int sumOfchars = 0;
for (char element : charArray) {
sumOfchars += element;
}
return 51 * sumOfchars;
}
#Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (getClass() != o.getClass()) {
return false;
}
final Supplier other = (Supplier) o;
return this.name.equals(other.name);
}
}
Objects of this class are added to a HashMap with name field as Key.
Supplier s1 = new Supplier("supplierA");
Supplier s2 = new Supplier("supplierB");
Map<String, Supplier> supplierMap = new HashMap<>();
supplierMap.put(s1.getName(), s1);
supplierMap.put(s2.getName(), s2);
supplierMap.containsKey("supplierA"));
But, when I put() or get() an element my overridden hashCode() method is not called. Same is the case for equals() when I use contains(Key key). I thought HashMap internally calls hashCode() in case of put and get(). And equals is called in case of contains(). Kindly throw some light on this.
When you put something in a HashMap, the hashCode() method is called on the key, not the value. So in this case, it's the hashCode from String that gets called on s1.getName() and s2.getName().
You're using java.lang.String value of 'name' as your key - hence the hashcode method on your object will not be called.
If you were to do Map<Supplier, Object> or something else then it would be called.
I was going through Joshua Bloch's online Chapter on "overridding equals() method".
Here's the link.
The following section confuses me,
Reflexivity—The first requirement says merely that an object must be
equal to itself. It is hard to imagine violating this requirement
unintentionally. If you were to violate it and then add an instance of
your class to a collection, the collection’s contains method would
almost certainly say that the collection did not contain the instance
that you just added.
Question - Is it possible for a collection's contain method to return false on an instance added to it?
I tried but the result returned is always true.
To illustrate the point, have this simple class:
class C {
private int i;
public C(int i) { this.i = i; }
}
Now, if you do:
C c1 = new C(1);
C c2 = new C(1);
List<C> l = new ArrayList<C>();
l.add(c1);
l.contains(c2) will return false, since c2.equals(c1) is false, in spite of the fact that both instances have the same constructor arguments.
This is because class C does not override .equals() nor .hashCode().
In general, each time your class is bound to be used in a Collection of any kind, you had better override both of these methods. In this case:
// Note: final class, final member -- that makes this class immutable
final class C {
private final int i;
public C(int i) { this.i = i; }
#Override
public int hashCode() { return i; }
#Override
public boolean equals(Object o)
{
// no object equals null
if (o == null)
return false;
// an object is always equal to itself
if (this == o)
return true;
// immutable class: if the class of the other is not the same,
// objects are not equal
if (getClass() != o.getClass())
return false;
// Both objects are of the same class: check their members
return i == ((C) o).i;
}
}
Question - Is it possible for a collection's contain method to return false on an instance added to it?
Not unless the added object's equals() violates the contract, as the quote from the book explains.
As suggested by #Karthik T, try this with an object whose equals() unconditionally returns false (thereby violating the contract).
Here is a demonstration of a collection's contains method returning false for an object that has just been added to the collection. I took a normal equals and hashCode, generated by Eclipse, and changed the equals method to be non-reflexive. Specifically, it returns false when comparing an object to itself.
import java.util.LinkedList;
import java.util.List;
public class Test {
int someValue;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + someValue;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
// Bad. Non-reflexive. Should return true.
return false;
}
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Test other = (Test) obj;
if (someValue != other.someValue)
return false;
return true;
}
public static void main(String[] args) {
List<Test> myList = new LinkedList<Test>();
Test myObject = new Test();
myList.add(myObject);
System.out.println(myList.contains(myObject));
}
}