/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.lang3.builder; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Comparator; import java.util.HashSet; import java.util.Set; import org.apache.commons.lang3.ArraySorter; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.Validate; /** *
* Assists in implementing {@link Object#hashCode()} methods. *
* ** This class enables a good {@code 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 {@code 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 hash code of 674, namely 17 * 37 + 45. *
* ** All relevant fields from the object should be included in the {@code hashCode} method. Derived fields may be * excluded. In general, any field used in the {@code equals} method must be used in the {@code 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 HashCodeBuilder(17, 37). * append(name). * append(age). * append(smoker). * toHashCode(); * } * } ** *
* If required, the superclass {@code hashCode()} can be added using {@link #appendSuper}. *
* ** Alternatively, there is a method that uses reflection to determine the fields to test. Because these fields are * usually private, the method, {@code reflectionHashCode}, uses {@code 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 HashCodeBuilder.reflectionHashCode(this); * } ** *
The {@link HashCodeExclude} annotation can be used to exclude fields from being * used by the {@code reflectionHashCode} methods.
* * @since 1.0 */ public class HashCodeBuilder implements Builder* A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops. *
* * @since 2.3 */ private static final ThreadLocal* Returns the registry of objects being traversed by the reflection methods in the current thread. *
* * @return Set the registry of objects being traversed * @since 2.3 */ static Set* Returns {@code true} if the registry contains the given object. Used by the reflection methods to avoid * infinite loops. *
* * @param value * The object to lookup in the registry. * @return boolean {@code true} if the registry contains the given object. * @since 2.3 */ static boolean isRegistered(final Object value) { final Set* Appends the fields and values defined by the given object of the given {@code Class}. *
* * @param object * the object to append details of * @param clazz * the class to append details of * @param builder * the builder to append to * @param useTransients * whether to use transient fields * @param excludeFields * Collection of String field names to exclude from use in calculation of hash code */ private static void reflectionAppend(final Object object, final Class> clazz, final HashCodeBuilder builder, final boolean useTransients, final String[] excludeFields) { if (isRegistered(object)) { return; } try { register(object); // The elements in the returned array are not sorted and are not in any particular order. final Field[] fields = ArraySorter.sort(clazz.getDeclaredFields(), Comparator.comparing(Field::getName)); AccessibleObject.setAccessible(fields, true); for (final Field field : fields) { if (!ArrayUtils.contains(excludeFields, field.getName()) && !field.getName().contains("$") && (useTransients || !Modifier.isTransient(field.getModifiers())) && !Modifier.isStatic(field.getModifiers()) && !field.isAnnotationPresent(HashCodeExclude.class)) { try { final Object fieldValue = field.get(object); builder.append(fieldValue); } catch (final IllegalAccessException e) { // this can't happen. Would get a Security exception instead // throw a runtime exception in case the impossible happens. throw new InternalError("Unexpected IllegalAccessException"); } } } } finally { unregister(object); } } /** ** Uses reflection to build a valid hash code from the fields of {@code object}. *
* ** It uses {@code AccessibleObject.setAccessible} to 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 * {@code Object}. *
* ** Static fields will not be tested. Superclass fields will be included. *
* ** Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, * however this is not vital. Prime numbers are preferred, especially for the multiplier. *
* * @param initialNonZeroOddNumber * a non-zero, odd number used as the initial value. This will be the returned * value if no fields are found to include in the hash code * @param multiplierNonZeroOddNumber * a non-zero, odd number used as the multiplier * @param object * the Object to create a {@code hashCode} for * @return int hash code * @throws IllegalArgumentException * if the Object is {@code null} * @throws IllegalArgumentException * if the number is zero or even * * @see HashCodeExclude */ public static int reflectionHashCode(final int initialNonZeroOddNumber, final int multiplierNonZeroOddNumber, final Object object) { return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null); } /** ** Uses reflection to build a valid hash code from the fields of {@code object}. *
* ** It uses {@code AccessibleObject.setAccessible} to 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. *
* ** If the TestTransients parameter is set to {@code true}, transient members will be tested, otherwise they * are ignored, as they are likely derived fields, and not part of the value of the {@code Object}. *
* ** Static fields will not be tested. Superclass fields will be included. *
* ** Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, * however this is not vital. Prime numbers are preferred, especially for the multiplier. *
* * @param initialNonZeroOddNumber * a non-zero, odd number used as the initial value. This will be the returned * value if no fields are found to include in the hash code * @param multiplierNonZeroOddNumber * a non-zero, odd number used as the multiplier * @param object * the Object to create a {@code hashCode} for * @param testTransients * whether to include transient fields * @return int hash code * @throws IllegalArgumentException * if the Object is {@code null} * @throws IllegalArgumentException * if the number is zero or even * * @see HashCodeExclude */ public static int reflectionHashCode(final int initialNonZeroOddNumber, final int multiplierNonZeroOddNumber, final Object object, final boolean testTransients) { return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null); } /** ** Uses reflection to build a valid hash code from the fields of {@code object}. *
* ** It uses {@code AccessibleObject.setAccessible} to 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. *
* ** If the TestTransients parameter is set to {@code true}, transient members will be tested, otherwise they * are ignored, as they are likely derived fields, and not part of the value of the {@code Object}. *
* ** Static fields will not be included. Superclass fields will be included up to and including the specified * superclass. A null superclass is treated as java.lang.Object. *
* ** Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, * however this is not vital. Prime numbers are preferred, especially for the multiplier. *
* * @param* Uses reflection to build a valid hash code from the fields of {@code object}. *
* ** This constructor uses two hard coded choices for the constants needed to build a hash code. *
* ** It uses {@code AccessibleObject.setAccessible} to 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. *
* ** If the TestTransients parameter is set to {@code true}, transient members will be tested, otherwise they * are ignored, as they are likely derived fields, and not part of the value of the {@code Object}. *
* ** Static fields will not be tested. Superclass fields will be included. If no fields are found to include * in the hash code, the result of this method will be constant. *
* * @param object * the Object to create a {@code hashCode} for * @param testTransients * whether to include transient fields * @return int hash code * @throws IllegalArgumentException * if the object is {@code null} * * @see HashCodeExclude */ public static int reflectionHashCode(final Object object, final boolean testTransients) { return reflectionHashCode(DEFAULT_INITIAL_VALUE, DEFAULT_MULTIPLIER_VALUE, object, testTransients, null); } /** ** Uses reflection to build a valid hash code from the fields of {@code object}. *
* ** This constructor uses two hard coded choices for the constants needed to build a hash code. *
* ** It uses {@code AccessibleObject.setAccessible} to 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 * {@code Object}. *
* ** Static fields will not be tested. Superclass fields will be included. If no fields are found to include * in the hash code, the result of this method will be constant. *
* * @param object * the Object to create a {@code hashCode} for * @param excludeFields * Collection of String field names to exclude from use in calculation of hash code * @return int hash code * @throws IllegalArgumentException * if the object is {@code null} * * @see HashCodeExclude */ public static int reflectionHashCode(final Object object, final Collection* Uses reflection to build a valid hash code from the fields of {@code object}. *
* ** This constructor uses two hard coded choices for the constants needed to build a hash code. *
* ** It uses {@code AccessibleObject.setAccessible} to 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 * {@code Object}. *
* ** Static fields will not be tested. Superclass fields will be included. If no fields are found to include * in the hash code, the result of this method will be constant. *
* * @param object * the Object to create a {@code hashCode} for * @param excludeFields * array of field names to exclude from use in calculation of hash code * @return int hash code * @throws IllegalArgumentException * if the object is {@code null} * * @see HashCodeExclude */ public static int reflectionHashCode(final Object object, final String... excludeFields) { return reflectionHashCode(DEFAULT_INITIAL_VALUE, DEFAULT_MULTIPLIER_VALUE, object, false, null, excludeFields); } /** ** Registers the given object. Used by the reflection methods to avoid infinite loops. *
* * @param value * The object to register. */ private static void register(final Object value) { Set* Unregisters the given object. *
* *
* Used by the reflection methods to avoid infinite loops.
*
* @param value
* The object to unregister.
* @since 2.3
*/
private static void unregister(final Object value) {
final Set
* Uses two hard coded choices for the constants needed to build a {@code hashCode}.
*
* Two randomly chosen, odd numbers must be passed in. Ideally these should be different for each class,
* however this is not vital.
*
* Prime numbers are preferred, especially for the multiplier.
*
* Append a {@code hashCode} for a {@code boolean}.
*
* This adds {@code 1} when true, and {@code 0} when false to the {@code hashCode}.
*
* This is in contrast to the standard {@code java.lang.Boolean.hashCode} handling, which computes
* a {@code hashCode} value of {@code 1231} for {@code java.lang.Boolean} instances
* that represent {@code true} or {@code 1237} for {@code java.lang.Boolean} instances
* that represent {@code false}.
*
* This is in accordance with the Effective Java design.
*
* Append a {@code hashCode} for a {@code boolean} array.
*
* Append a {@code hashCode} for a {@code byte}.
*
* Append a {@code hashCode} for a {@code byte} array.
*
* Append a {@code hashCode} for a {@code char}.
*
* Append a {@code hashCode} for a {@code char} array.
*
* Append a {@code hashCode} for a {@code double}.
*
* Append a {@code hashCode} for a {@code double} array.
*
* Append a {@code hashCode} for a {@code float}.
*
* Append a {@code hashCode} for a {@code float} array.
*
* Append a {@code hashCode} for an {@code int}.
*
* Append a {@code hashCode} for an {@code int} array.
*
* Append a {@code hashCode} for a {@code long}.
*
* Append a {@code hashCode} for a {@code long} array.
*
* Append a {@code hashCode} for an {@code Object}.
*
* Append a {@code hashCode} for an array.
*
* Append a {@code hashCode} for an {@code Object} array.
*
* Append a {@code hashCode} for a {@code short}.
*
* Append a {@code hashCode} for a {@code short} array.
*
* Adds the result of super.hashCode() to this builder.
*
* Returns the computed {@code hashCode}.
*
* The computed {@code hashCode} from toHashCode() is returned due to the likelihood
* of bugs in mis-calling toHashCode() and the unlikeliness of it mattering what the hashCode for
* HashCodeBuilder itself is.