Class BeCPGHashCodeBuilder
Assists in implementing Object.hashCode() methods.
This class enables a good hashCode method to be built for any
class. It follows the rules laid out in the book
Effective
Java by Joshua Bloch. Writing a good hashCode method is
actually quite difficult. This class aims to simplify the process.
The following is the approach taken. When appending a data field, the current total is multiplied by the multiplier then a relevant value for that data type is added. For example, if the current hashCode is 17, and the multiplier is 37, then appending the integer 45 will create a hashcode of 674, namely 17 * 37 + 45.
All relevant fields from the object should be included in the
hashCode method. Derived fields may be excluded. In general, any
field used in the equals method must be used in the
hashCode method.
To use this class write code as follows:
public class Person {
String name;
int age;
boolean smoker;
...
public int hashCode() {
// you pick a hard-coded, randomly chosen, non-zero, odd number
// ideally different for each class
return new BeCPGHashCodeBuilder(17, 37).
append(name).
append(age).
append(smoker).
toHashCode();
}
}
If required, the superclass hashCode() can be added using appendSuper.
Alternatively, there is a method that uses reflection to determine the fields
to test. Because these fields are usually private, the method,
reflectionHashCode, uses
AccessibleObject.setAccessible to change the visibility of the
fields. This will fail under a security manager, unless the appropriate
permissions are set up correctly. It is also slower than testing explicitly.
A typical invocation for this method would look like:
public int hashCode() {
return BeCPGHashCodeBuilder.reflectionHashCode(this);
}
- Since:
- 1.0
- Version:
- $Id: BeCPGHashCodeBuilder.java 1057009 2011-01-09 19:48:06Z niallp $ beCPG FIX when Integer, Float or Double is null give same hashCode as when egal 0
- Author:
- Apache Software Foundation, Gary Gregory, Pete Gieser, Matthieu L
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate static final intConstant to use in building the hashCode.private static org.apache.commons.logging.Logprivate static final int -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprivate longappend(long total, boolean value) Append ahashCodefor aboolean.private longappend(long total, boolean[] array) Append ahashCodefor abooleanarray.private longappend(long total, byte value) Append ahashCodefor abyte.private longappend(long total, byte[] array) Append ahashCodefor abytearray.private longappend(long total, char value) Append ahashCodefor achar.private longappend(long total, char[] array) Append ahashCodefor achararray.private longappend(long total, double value) Append ahashCodefor adouble.private longappend(long total, double[] array) Append ahashCodefor adoublearray.private longappend(long total, float value) Append ahashCodefor afloat.private longappend(long total, float[] array) Append ahashCodefor afloatarray.private longappend(long total, int value) Append ahashCodefor anint.private longappend(long total, int[] array) Append ahashCodefor anintarray.private longappend(long total, long value) Append ahashCodefor along.private longappend(long total, long[] array) Append ahashCodefor alongarray.private longappend(long total, short value) Append ahashCodefor ashort.private longappend(long total, short[] array) Append ahashCodefor ashortarray.longappend(long total, Object[] array, Set<RepositoryEntity> visited) Append ahashCodefor anObjectarray.private longappend(long total, Object object, Set<RepositoryEntity> visited) Append ahashCodefor anObject.private longappendArray(long total, Object object, Set<RepositoryEntity> visited) Optimized array handlingprivate longappendAspects(long total, AspectAwareDataItem aspectAwareDataItem, Set<RepositoryEntity> visited) Optimized aspect handlingprivate static voidappendAspectsDiff(StringBuilder ret, RepositoryEntity obj1, RepositoryEntity obj2) Extract aspects diff logicprivate static voidappendDiffDetails(StringBuilder ret, Object fieldValue, Object fieldValue2, RepositoryEntity obj1, RepositoryEntity obj2) Extract diff details logic for better readabilityprivate static voidappendListDiff(StringBuilder ret, List<?> list1, List<?> list2) Extract list diff logicprivate static voidappendNodeRefDiff(StringBuilder ret, RepositoryEntity obj1, RepositoryEntity obj2) Extract nodeRef diff logicprivate static intCalculate aspects hash for diff comparisongetCachedMethods(Class<?> clazz) Extract method caching logic for better readabilityprivate booleanisAnnotatedMethod(Method method) Check if method has relevant annotationsstatic StringprintDiff(RepositoryEntity obj1, RepositoryEntity obj2) printDiff.private longreflectionAppend(RepositoryEntity object, Set<RepositoryEntity> visited) static longreflectionHashCode(RepositoryEntity object) This method uses reflection to build a valid hash code.
-
Field Details
-
iConstant
private static final int iConstantConstant to use in building the hashCode.- See Also:
-
NULL_MULTIPLIER
private static final int NULL_MULTIPLIER- See Also:
-
annotatedMethodsCache
-
logger
private static org.apache.commons.logging.Log logger
-
-
Constructor Details
-
BeCPGHashCodeBuilder
public BeCPGHashCodeBuilder()
-
-
Method Details
-
reflectionAppend
-
getCachedMethods
Extract method caching logic for better readability -
isAnnotatedMethod
Check if method has relevant annotations -
appendAspects
private long appendAspects(long total, AspectAwareDataItem aspectAwareDataItem, Set<RepositoryEntity> visited) Optimized aspect handling -
printDiff
printDiff.
- Parameters:
obj1- aRepositoryEntityobject.obj2- aRepositoryEntityobject.- Returns:
- a
Stringobject.
-
appendDiffDetails
private static void appendDiffDetails(StringBuilder ret, Object fieldValue, Object fieldValue2, RepositoryEntity obj1, RepositoryEntity obj2) Extract diff details logic for better readability -
appendListDiff
Extract list diff logic -
appendNodeRefDiff
private static void appendNodeRefDiff(StringBuilder ret, RepositoryEntity obj1, RepositoryEntity obj2) Extract nodeRef diff logic -
appendAspectsDiff
private static void appendAspectsDiff(StringBuilder ret, RepositoryEntity obj1, RepositoryEntity obj2) Extract aspects diff logic -
calculateAspectsHash
Calculate aspects hash for diff comparison -
reflectionHashCode
This method uses reflection to build a valid hash code.
This constructor uses two hard coded choices for the constants needed to build a hash code.
It uses
AccessibleObject.setAccessibleto gain access to private fields. This means that it will throw a security exception if run under a security manager, if the permissions are not set up correctly. It is also not as efficient as testing explicitly.Transient members will be not be used, as they are likely derived fields, and not part of the value of the
Object.Static fields will not be tested. Superclass fields will be included.
- Parameters:
object- the Object to create ahashCodefor- Returns:
- int hash code
- Throws:
IllegalArgumentException- if the object isnull
-
append
private long append(long total, boolean value) Append a
hashCodefor aboolean.This adds
1when true, and0when false to thehashCode.This is in contrast to the standard
java.lang.Boolean.hashCodehandling, which computes ahashCodevalue of1231forjava.lang.Booleaninstances that representtrueor1237forjava.lang.Booleaninstances that representfalse.This is in accordance with the
Effective Java
design.- Parameters:
value- the boolean to add to thehashCode- Returns:
- this
-
append
private long append(long total, boolean[] array) Append a
hashCodefor abooleanarray.- Parameters:
array- the array to add to thehashCode- Returns:
- this
-
append
private long append(long total, byte value) Append a
hashCodefor abyte.- Parameters:
value- the byte to add to thehashCode- Returns:
- this
-
append
private long append(long total, byte[] array) Append a
hashCodefor abytearray.- Parameters:
array- the array to add to thehashCode- Returns:
- this
-
append
private long append(long total, char value) Append a
hashCodefor achar.- Parameters:
value- the char to add to thehashCode- Returns:
- this
-
append
private long append(long total, char[] array) Append a
hashCodefor achararray.- Parameters:
array- the array to add to thehashCode- Returns:
- this
-
append
private long append(long total, double value) Append a
hashCodefor adouble.- Parameters:
value- the double to add to thehashCode- Returns:
- this
-
append
private long append(long total, double[] array) Append a
hashCodefor adoublearray.- Parameters:
array- the array to add to thehashCode- Returns:
- this
-
append
private long append(long total, float value) Append a
hashCodefor afloat.- Parameters:
value- the float to add to thehashCode- Returns:
- this
-
append
private long append(long total, float[] array) Append a
hashCodefor afloatarray.- Parameters:
array- the array to add to thehashCode- Returns:
- this
-
append
private long append(long total, int value) Append a
hashCodefor anint.- Parameters:
value- the int to add to thehashCode- Returns:
- this
-
append
private long append(long total, int[] array) Append a
hashCodefor anintarray.- Parameters:
array- the array to add to thehashCode- Returns:
- this
-
append
private long append(long total, long value) Append a
hashCodefor along.- Parameters:
value- the long to add to thehashCode- Returns:
- this
-
append
private long append(long total, long[] array) Append a
hashCodefor alongarray.- Parameters:
array- the array to add to thehashCode- Returns:
- this
-
append
Append a
hashCodefor anObject.- Parameters:
object- the Object to add to thehashCode- Returns:
- this
-
appendArray
Optimized array handling -
append
Append a
hashCodefor anObjectarray.- Parameters:
array- the array to add to thehashCodetotal- a long.visited- aSetobject.- Returns:
- this
-
append
private long append(long total, short value) Append a
hashCodefor ashort.- Parameters:
value- the short to add to thehashCode- Returns:
- this
-
append
private long append(long total, short[] array) Append a
hashCodefor ashortarray.- Parameters:
array- the array to add to thehashCode- Returns:
- this
-