Reputation: 694
Basic information: I have a MyCustomObjectGenerator that generates MyCustomObject . This object (should be) is always created with identical values. This object contains mutch code, interfaces, enums, sub-classes ..., so I keep it simple here. All objects or implementations of interfaces override the equals & hashCode method (hopefully in a correct way).
This MyCustomObject is serialized to JSON with Jackson with custom serializers (MyCustomObject does not contain any Jackson dependencies like Jackson annotations!).
Each JSON gets an ID calculated based on the hashCode of MyCustomObject (see code below). This id is just used as checksum to identify same jsons very fast. There is another ID based on UUID, that identifies the job itself, so I know that 2 jobs can have the same checksum!
The problem: There are two JUnit-Tests (minimal & maximal method in one Junit-Testclass), that generate a JSON and check this JSON with a predefined JSON from File. If I run both tests/methods the JSON matches with the one from the file, but if i just run the testMaximal() method the assertion fails, due to the fact that the generated id is not the same. So the hashCode seems to differ. If I start the two test-methods again, jsons match again with the one from file , so the generated object does not contain any random content like ZonedDateTime.now(). The other JSON values are always the same, only the ID differs. The HashCode seems to be the same if the execution (2 methods/1 method) condition is the same, but differs if this execution condition is changed. This is really strange for me.
Now I have to evaluate, what class does not correctly override(or produces different hashCode) the hashCode method (the id is based on hashCodes of all contained objects). Does someone have any good idea to print the hashCode of each object, variable, subclass, interface ... of MyCustomObject via Reflection? I already tried
ReflectionToStringBuilder.toString(myCustomObject, ToStringStyle.DEFAULT_STYLE)
but this does not print the hashCode of each sub-sub-element of myCustomObject.
If I could print the exact object values incl. hashValue, then I could compare it.
I already found one object that differs with ReflectionToStringBuilder.toString(), but this object itself contains mutch interface,variables and so on, but all values in this BlablaObject@4fb64261[...] are the same, and there the hashCode is missing
On top question: Are there known cases, that hashCode() behaves strange like "If you use enum as key in a HashMap, then hashCode depends on java stack or JVM version" or sth. like that.
CODE
MyCustomObjectGenerator .java
public class MyCustomObjectGenerator {
private MyCustomObject(){};
public static MyCustomObject generate(boolean isMinimal){
//if minimal then create minimal object
//if minimal == false then create maximized object**strong text**
MyCustomObject myCustomObject = new MyCustomObject(...);
myCustomObject.setXY(...)
...
return myCustomObject;
}
}
MyCustomObject.java
import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
public class MyCustomObject {
//variables, enums, interface ... here
...
public MyCustomObject(...){...}
//mutch code here
...
public String getChecksum() {
String id = Integer.toString(hashCode());
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(id.getBytes("UTF-8"));
id = DatatypeConverter.printHexBinary(digest);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
// do nothing here
}
return new id;
}
@Override
public int hashCode() {
return new HashCodeBuilder(-1013166723, 372138085)
//if needed in extended classes: .appendSuper(super.hashCode())
.append(...)
....
.toHashCode();
}
@Override
public boolean equals(
final Object other) {
if (!(other instanceof MyCustomObject)) {
return false;
}
MyCustomObject castOther = (MyCustomObject) other;
return new EqualsBuilder()
// if needed in extended classes: .appendSuper(super.hashCode())
.append(..., ...)
....
.isEquals();
}
}
Upvotes: 0
Views: 1594
Reputation: 718946
There are lots of types in which the value returned by hashCode()
will vary from one application run to the next. This includes:
enum
typesObject
,Class
, Thread
, StringBuilder
, and StringBuffer
.As a general rule, if a class defined as by Java SE is not documented as having an equals
method that differs in semantics from Object.equals(Object)
, then you should assume that it also uses Object.hashCode()
... and that the hashcodes will vary from one run to the next.
Upvotes: 3
Reputation: 73558
You're not supposed to use hashCode()
except for bucket choosing in a hash based data structure. It certainly has no place in validation, as you've found out.
Upvotes: 1