1 | package fr.sii.ogham.core.util; | |
2 | ||
3 | /** | |
4 | * <p> | |
5 | * Assists in implementing Object.hashCode() methods. | |
6 | * </p> | |
7 | * | |
8 | * <p> | |
9 | * This class enables a good hashCode method to be built for any class. It | |
10 | * follows the rules laid out in the book Effective Java by Joshua Bloch. | |
11 | * Writing a good hashCode method is actually quite difficult. This class aims | |
12 | * to simplify the process. | |
13 | * </p> | |
14 | * | |
15 | * <p> | |
16 | * The following is the approach taken. When appending a data field, the current | |
17 | * total is multiplied by the multiplier then a relevant value for that data | |
18 | * type is added. For example, if the current hashCode is 17, and the multiplier | |
19 | * is 37, then appending the integer 45 will create a hashcode of 674, namely 17 | |
20 | * * 37 + 45. | |
21 | * </p> | |
22 | * | |
23 | * <p> | |
24 | * All relevant fields from the object should be included in the hashCode | |
25 | * method. Derived fields may be excluded. In general, any field used in the | |
26 | * equals method must be used in the hashCode method. | |
27 | * </p> | |
28 | * | |
29 | * <p> | |
30 | * To use this class write code as follows: | |
31 | * </p> | |
32 | * | |
33 | * <pre> | |
34 | * public class Person { | |
35 | * String name; | |
36 | * int age; | |
37 | * boolean smoker; | |
38 | * ... | |
39 | * | |
40 | * public int hashCode() { | |
41 | * // you pick a hard-coded, randomly chosen, non-zero, odd number | |
42 | * // ideally different for each class | |
43 | * return new HashCodeBuilder(17, 37). | |
44 | * append(name). | |
45 | * append(age). | |
46 | * append(smoker). | |
47 | * hashCode(); | |
48 | * } | |
49 | * } | |
50 | * </pre> | |
51 | * <p> | |
52 | * If required, the superclass hashCode() can be added using appendSuper. | |
53 | * </p> | |
54 | * | |
55 | * <p> | |
56 | * Alternatively, there is a method that uses reflection to determine the fields | |
57 | * to test. Because these fields are usually private, the method, | |
58 | * reflectionHashCode, uses AccessibleObject.setAccessible to change the | |
59 | * visibility of the fields. This will fail under a security manager, unless the | |
60 | * appropriate permissions are set up correctly. It is also slower than testing | |
61 | * explicitly. | |
62 | * </p> | |
63 | * | |
64 | * <p> | |
65 | * A typical invocation for this method would look like: | |
66 | * </p> | |
67 | * | |
68 | * <pre> | |
69 | * public int hashCode() { | |
70 | * return HashCodeBuilder.reflectionHashCode(this); | |
71 | * } | |
72 | * </pre> | |
73 | * | |
74 | * @author Aurélien Baudet | |
75 | * | |
76 | */ | |
77 | public class HashCodeBuilder { | |
78 | private org.apache.commons.lang3.builder.HashCodeBuilder delegate; | |
79 | ||
80 | /** | |
81 | * <p> | |
82 | * Two randomly chosen, odd numbers must be passed in. Ideally these should | |
83 | * be different for each class, however this is not vital. | |
84 | * </p> | |
85 | * | |
86 | * <p> | |
87 | * Prime numbers are preferred, especially for the multiplier. | |
88 | * </p> | |
89 | * | |
90 | * @param initialOddNumber | |
91 | * an odd number used as the initial value | |
92 | * @param multiplierOddNumber | |
93 | * an odd number used as the multiplier | |
94 | * @throws IllegalArgumentException | |
95 | * if the number is even | |
96 | */ | |
97 | public HashCodeBuilder(int initialOddNumber, int multiplierOddNumber) { | |
98 | super(); | |
99 | delegate = new org.apache.commons.lang3.builder.HashCodeBuilder(initialOddNumber, multiplierOddNumber); | |
100 | } | |
101 | ||
102 | /** | |
103 | * Uses two hard coded choices for the constants needed to build a hashCode. | |
104 | */ | |
105 | public HashCodeBuilder() { | |
106 | super(); | |
107 | delegate = new org.apache.commons.lang3.builder.HashCodeBuilder(); | |
108 | } | |
109 | ||
110 | /** | |
111 | * Append a hashCode for an Object. | |
112 | * | |
113 | * @param objectValue | |
114 | * the Object to add to the hashCode | |
115 | * @return used to chain calls | |
116 | */ | |
117 | public HashCodeBuilder append(Object objectValue) { | |
118 | delegate.append(objectValue); | |
119 |
3
1. append : replaced return value with null for fr/sii/ogham/core/util/HashCodeBuilder::append → SURVIVED 2. append : replaced return value with null for fr/sii/ogham/core/util/HashCodeBuilder::append → NO_COVERAGE 3. append : replaced return value with null for fr/sii/ogham/core/util/HashCodeBuilder::append → KILLED |
return this; |
120 | } | |
121 | ||
122 | /** | |
123 | * Append a hashCode for an Object. | |
124 | * | |
125 | * @param objectValues | |
126 | * array of Object to add to the hashCode | |
127 | * @return used to chain calls | |
128 | */ | |
129 | public HashCodeBuilder append(Object... objectValues) { | |
130 | for(Object objectValue : objectValues) { | |
131 | append(objectValue); | |
132 | } | |
133 |
4
1. append : replaced return value with null for fr/sii/ogham/core/util/HashCodeBuilder::append → SURVIVED 2. append : replaced return value with null for fr/sii/ogham/core/util/HashCodeBuilder::append → NO_COVERAGE 3. append : replaced return value with null for fr/sii/ogham/core/util/HashCodeBuilder::append → KILLED 4. append : replaced return value with null for fr/sii/ogham/core/util/HashCodeBuilder::append → KILLED |
return this; |
134 | } | |
135 | ||
136 | /** | |
137 | * Adds the result of super.hashCode() to this builder. | |
138 | * | |
139 | * @param superHashCode | |
140 | * the result of calling super.hashCode() | |
141 | * @return used to chain calls | |
142 | */ | |
143 | public HashCodeBuilder appendSuper(int superHashCode) { | |
144 | delegate.appendSuper(superHashCode); | |
145 |
1
1. appendSuper : replaced return value with null for fr/sii/ogham/core/util/HashCodeBuilder::appendSuper → NO_COVERAGE |
return this; |
146 | } | |
147 | ||
148 | /** | |
149 | * The generated hash code | |
150 | * | |
151 | * @return the generated hashcode | |
152 | */ | |
153 | public int hashCode() { | |
154 |
3
1. hashCode : replaced int return with 0 for fr/sii/ogham/core/util/HashCodeBuilder::hashCode → SURVIVED 2. hashCode : replaced int return with 0 for fr/sii/ogham/core/util/HashCodeBuilder::hashCode → NO_COVERAGE 3. hashCode : replaced int return with 0 for fr/sii/ogham/core/util/HashCodeBuilder::hashCode → KILLED |
return delegate.hashCode(); |
155 | } | |
156 | | |
157 | @Override | |
158 | public boolean equals(Object obj) { | |
159 |
2
1. equals : replaced boolean return with false for fr/sii/ogham/core/util/HashCodeBuilder::equals → NO_COVERAGE 2. equals : replaced boolean return with true for fr/sii/ogham/core/util/HashCodeBuilder::equals → NO_COVERAGE |
return delegate.equals(obj); |
160 | } | |
161 | | |
162 | /** | |
163 | * <p> | |
164 | * Uses reflection to build a valid hash code from the fields of object. | |
165 | * </p> | |
166 | * | |
167 | * <p> | |
168 | * This constructor uses two hard coded choices for the constants needed to | |
169 | * build a hash code. | |
170 | * </p> | |
171 | * | |
172 | * <p> | |
173 | * It uses AccessibleObject.setAccessible to gain access to private fields. | |
174 | * This means that it will throw a security exception if run under a | |
175 | * security manager, if the permissions are not set up correctly. It is also | |
176 | * not as efficient as testing explicitly. | |
177 | * </p> | |
178 | * | |
179 | * <p> | |
180 | * Transient members will be not be used, as they are likely derived fields, | |
181 | * and not part of the value of the Object. | |
182 | * </p> | |
183 | * | |
184 | * <p> | |
185 | * Static fields will not be tested. Superclass fields will be included. If | |
186 | * no fields are found to include in the hash code, the result of this | |
187 | * method will be constant. | |
188 | * </p> | |
189 | * | |
190 | * @param object | |
191 | * the Object to create a hashCode for | |
192 | * @param excludeFields | |
193 | * array of field names to exclude from use in calculation of | |
194 | * hash code | |
195 | * @return hash code | |
196 | * @throws IllegalArgumentException | |
197 | * if the object is null | |
198 | */ | |
199 | public static int reflectionsHashCode(Object object, String... excludeFields) { | |
200 |
1
1. reflectionsHashCode : replaced int return with 0 for fr/sii/ogham/core/util/HashCodeBuilder::reflectionsHashCode → NO_COVERAGE |
return org.apache.commons.lang3.builder.HashCodeBuilder.reflectionHashCode(object, excludeFields); |
201 | } | |
202 | ||
203 | } | |
Mutations | ||
119 |
1.1 2.2 3.3 |
|
133 |
1.1 2.2 3.3 4.4 |
|
145 |
1.1 |
|
154 |
1.1 2.2 3.3 |
|
159 |
1.1 2.2 |
|
200 |
1.1 |