Exclude static fields from reflection based builder

git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137031 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Stephen Colebourne 2002-09-17 22:06:38 +00:00
parent b1ad52a457
commit aea52bdea5
3 changed files with 79 additions and 63 deletions

View File

@ -99,7 +99,7 @@ import org.apache.commons.lang.NumberUtils;
* </pre> * </pre>
* @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a> * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
* @author <a href="mailto:scolebourne@joda.org">Stephen Colebourne</a> * @author <a href="mailto:scolebourne@joda.org">Stephen Colebourne</a>
* @version $Id: CompareToBuilder.java,v 1.1 2002/09/15 10:25:22 scolebourne Exp $ * @version $Id: CompareToBuilder.java,v 1.2 2002/09/17 22:06:37 scolebourne Exp $
*/ */
public class CompareToBuilder { public class CompareToBuilder {
/** /**
@ -128,9 +128,10 @@ public class CompareToBuilder {
* It is also not as efficient as testing explicitly. * It is also not as efficient as testing explicitly.
* Transient members will be not be tested, as they are likely derived * Transient members will be not be tested, as they are likely derived
* fields, and not part of the value of the object. * fields, and not part of the value of the object.
* @param lhs - Left Hand Side * Static fields will not be tested.
* @param rhs - Right Hand Side * @param lhs Left Hand Side
* @return int - a negative integer, zero, or a positive integer as this * @param rhs Right Hand Side
* @return int a negative integer, zero, or a positive integer as this
* object is less than, equal to, or greater than the specified object. * object is less than, equal to, or greater than the specified object.
* @throws ClassCastException - if the specified object's type prevents it * @throws ClassCastException - if the specified object's type prevents it
* from being compared to this Object. * from being compared to this Object.
@ -149,16 +150,18 @@ public class CompareToBuilder {
* If the TestTransients parameter is set to true, transient members will be * If the TestTransients parameter is set to true, transient members will be
* tested, otherwise they are ignored, as they are likely derived fields, and * tested, otherwise they are ignored, as they are likely derived fields, and
* not part of the value of the object. * not part of the value of the object.
* Static fields will not be tested.
* *
* @param lhs - Left Hand Side * @param lhs Left Hand Side
* @param rhs - Right Hand Side * @param rhs Right Hand Side
* @param testTransients - whether to include transient fields * @param testTransients whether to include transient fields
* @return int - a negative integer, zero, or a positive integer as this * @return int - a negative integer, zero, or a positive integer as this
* object is less than, equal to, or greater than the specified object. * object is less than, equal to, or greater than the specified object.
* @throws ClassCastException - if the specified object's type prevents it * @throws ClassCastException - if the specified object's type prevents it
* from being compared to this Object. * from being compared to this Object.
*/ */
public static int reflectionCompare(Object lhs, Object rhs, boolean testTransients) { public static int reflectionCompare(Object lhs, Object rhs,
boolean testTransients) {
if (lhs == rhs) { if (lhs == rhs) {
return 0; return 0;
} }
@ -175,12 +178,14 @@ public class CompareToBuilder {
for (int i = 0; i < fields.length && compareToBuilder.comparison == 0; ++i) { for (int i = 0; i < fields.length && compareToBuilder.comparison == 0; ++i) {
Field f = fields[i]; Field f = fields[i];
if (testTransients || !Modifier.isTransient(f.getModifiers())) { if (testTransients || !Modifier.isTransient(f.getModifiers())) {
try { if ( !Modifier.isStatic(f.getModifiers())) {
compareToBuilder.append(f.get(lhs), f.get(rhs)); try {
} catch (IllegalAccessException e) { compareToBuilder.append(f.get(lhs), f.get(rhs));
//this can't happen. Would get a Security exception instead } catch (IllegalAccessException e) {
//throw a runtime exception in case the impossible happens. //this can't happen. Would get a Security exception instead
throw new InternalError("Unexpected IllegalAccessException"); //throw a runtime exception in case the impossible happens.
throw new InternalError("Unexpected IllegalAccessException");
}
} }
} }
} }

View File

@ -102,7 +102,7 @@ import java.lang.reflect.Modifier;
* *
* @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a> * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
* @author <a href="mailto:scolebourne@joda.org">Stephen Colebourne</a> * @author <a href="mailto:scolebourne@joda.org">Stephen Colebourne</a>
* @version $Id: EqualsBuilder.java,v 1.1 2002/09/12 22:00:00 scolebourne Exp $ * @version $Id: EqualsBuilder.java,v 1.2 2002/09/17 22:06:38 scolebourne Exp $
*/ */
public class EqualsBuilder { public class EqualsBuilder {
/** /**
@ -129,11 +129,12 @@ public class EqualsBuilder {
* that it will throw a security exception if run under a security manger, if * that it will throw a security exception if run under a security manger, if
* the permissions are not set up. * the permissions are not set up.
* It is also not as efficient as testing explicitly. * It is also not as efficient as testing explicitly.
* Transient members will be not be tested, as they are likely derived * Transient members will be not be tested, as they are likely derived
* fields, and not part of the value of the object. * fields, and not part of the value of the object.
* Static fields will not be tested.
* *
* @param lhs - Left Hand Side * @param lhs Left Hand Side
* @param rhs - Right Hand Side * @param rhs Right Hand Side
* @return boolean - if the two objects have tested equals. * @return boolean - if the two objects have tested equals.
*/ */
public static boolean reflectionEquals(Object lhs, Object rhs) { public static boolean reflectionEquals(Object lhs, Object rhs) {
@ -150,13 +151,15 @@ public class EqualsBuilder {
* If the TestTransients parameter is set to true, transient members will be * If the TestTransients parameter is set to true, transient members will be
* tested, otherwise they are ignored, as they are likely derived fields, and * tested, otherwise they are ignored, as they are likely derived fields, and
* not part of the value of the object. * not part of the value of the object.
* Static fields will not be tested.
* *
* @param lhs - Left Hand Side * @param lhs Left Hand Side
* @param rhs - Right Hand Side * @param rhs Right Hand Side
* @param testTransients - whether to include transient fields * @param testTransients whether to include transient fields
* @return boolean - if the two objects have tested equals. * @return boolean - if the two objects have tested equals.
*/ */
public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) { public static boolean reflectionEquals(Object lhs, Object rhs,
boolean testTransients) {
if (lhs == rhs) { if (lhs == rhs) {
return true; return true;
} }
@ -173,12 +176,14 @@ public class EqualsBuilder {
for (int i = 0; i < fields.length && equalsBuilder.isEquals; ++i) { for (int i = 0; i < fields.length && equalsBuilder.isEquals; ++i) {
Field f = fields[i]; Field f = fields[i];
if (testTransients || !Modifier.isTransient(f.getModifiers())) { if (testTransients || !Modifier.isTransient(f.getModifiers())) {
try { if (!Modifier.isStatic(f.getModifiers())) {
equalsBuilder.append(f.get(lhs), f.get(rhs)); try {
} catch (IllegalAccessException e) { equalsBuilder.append(f.get(lhs), f.get(rhs));
//this can't happen. Would get a Security exception instead } catch (IllegalAccessException e) {
//throw a runtime exception in case the impossible happens. //this can't happen. Would get a Security exception instead
throw new InternalError("Unexpected IllegalAccessException"); //throw a runtime exception in case the impossible happens.
throw new InternalError("Unexpected IllegalAccessException");
}
} }
} }
} }

View File

@ -102,7 +102,7 @@ import java.lang.reflect.Modifier;
* </code> * </code>
* *
* @author <a href="mailto:scolebourne@joda.org">Stephen Colebourne</a> * @author <a href="mailto:scolebourne@joda.org">Stephen Colebourne</a>
* @version $Id: HashCodeBuilder.java,v 1.1 2002/09/12 21:59:01 scolebourne Exp $ * @version $Id: HashCodeBuilder.java,v 1.2 2002/09/17 22:06:38 scolebourne Exp $
*/ */
public class HashCodeBuilder { public class HashCodeBuilder {
@ -165,6 +165,7 @@ public class HashCodeBuilder {
* It is also not as efficient as testing explicitly. * It is also not as efficient as testing explicitly.
* Transient members will be not be used, as they are likely derived * Transient members will be not be used, as they are likely derived
* fields, and not part of the value of the object. * fields, and not part of the value of the object.
* Static fields will not be tested.
* This constructor uses two hard coded choices for the constants needed * This constructor uses two hard coded choices for the constants needed
* to build a hash code. * to build a hash code.
* *
@ -176,33 +177,6 @@ public class HashCodeBuilder {
return reflectionHashCode(object, false); return reflectionHashCode(object, false);
} }
/**
* This method uses reflection to build a valid hash code.
* <p>
* It uses Field.setAccessible to gain access to private fields. This means
* that it will throw a security exception if run under a security manger, if
* the permissions are not set up.
* 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.
* <p>
* 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
* @param multiplierNonZeroOddNumber
* @param object the object to create a hash code for
* @return int hash code
* @throws IllegalArgumentException if the object is null
* @throws IllegalArgumentException if the number is zero or even
*/
public static int reflectionHashCode(
int initialNonZeroOddNumber, int multiplierNonZeroOddNumber,
Object object) {
return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object);
}
/** /**
* This method uses reflection to build a valid hash code. * This method uses reflection to build a valid hash code.
* <p> * <p>
@ -213,6 +187,7 @@ public class HashCodeBuilder {
* If the TestTransients parameter is set to true, transient members will be * If the TestTransients parameter is set to true, transient members will be
* tested, otherwise they are ignored, as they are likely derived fields, and * tested, otherwise they are ignored, as they are likely derived fields, and
* not part of the value of the object. * not part of the value of the object.
* Static fields will not be tested.
* This constructor uses two hard coded choices for the constants needed * This constructor uses two hard coded choices for the constants needed
* to build a hash code. * to build a hash code.
* *
@ -225,6 +200,34 @@ public class HashCodeBuilder {
return reflectionHashCode(17, 37, object, testTransients); return reflectionHashCode(17, 37, object, testTransients);
} }
/**
* This method uses reflection to build a valid hash code.
* <p>
* It uses Field.setAccessible to gain access to private fields. This means
* that it will throw a security exception if run under a security manger, if
* the permissions are not set up.
* 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.
* <p>
* 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
* @param multiplierNonZeroOddNumber
* @param object the object to create a hash code for
* @return int hash code
* @throws IllegalArgumentException if the object is null
* @throws IllegalArgumentException if the number is zero or even
*/
public static int reflectionHashCode(
int initialNonZeroOddNumber, int multiplierNonZeroOddNumber,
Object object) {
return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false);
}
/** /**
* This method uses reflection to build a valid hash code. * This method uses reflection to build a valid hash code.
* <p> * <p>
@ -235,6 +238,7 @@ public class HashCodeBuilder {
* If the TestTransients parameter is set to true, transient members will be * If the TestTransients parameter is set to true, transient members will be
* tested, otherwise they are ignored, as they are likely derived fields, and * tested, otherwise they are ignored, as they are likely derived fields, and
* not part of the value of the object. * not part of the value of the object.
* Static fields will not be tested.
* <p> * <p>
* Two randomly chosen, non-zero, odd numbers must be passed in. Ideally * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
* these should be different for each class, however this is not vital. * these should be different for each class, however this is not vital.
@ -261,12 +265,14 @@ public class HashCodeBuilder {
for (int i = 0; i < fields.length; ++i) { for (int i = 0; i < fields.length; ++i) {
Field f = fields[i]; Field f = fields[i];
if (testTransients || !Modifier.isTransient(f.getModifiers())) { if (testTransients || !Modifier.isTransient(f.getModifiers())) {
try { if (!Modifier.isStatic(f.getModifiers())) {
hashCodeBuilder.append(f.get(object)); try {
} catch (IllegalAccessException e) { hashCodeBuilder.append(f.get(object));
//this can't happen. Would get a Security exception instead } catch (IllegalAccessException e) {
//throw a runtime exception in case the impossible happens. //this can't happen. Would get a Security exception instead
throw new InternalError("Unexpected IllegalAccessException"); //throw a runtime exception in case the impossible happens.
throw new InternalError("Unexpected IllegalAccessException");
}
} }
} }
} }