001 // Copyright 2007 Regents of the University of California. May be used
002 // under the terms of the revised BSD license. See LICENSING for details.
003 /**
004 * @author Tyler Close
005 */
006 package org.joe_e;
007
008 import java.lang.reflect.AccessibleObject;
009 import java.lang.reflect.Field;
010 import java.lang.reflect.Modifier;
011 import java.util.Arrays;
012 import java.util.Comparator;
013
014 /**
015 * This abstract class contains implementations of the equals() and hashCode()
016 * methods that satisfy the Selfless interface. The provided equals() method
017 * computes equality of all fields using reflection.
018 */
019 public abstract class Struct implements Selfless {
020
021 protected Struct() {}
022
023 /**
024 * Tests for equality with another object. An obect is equal to this one
025 * if it is of identical type and each field is equal for the two objects.
026 * The objects' fields are equal if both are null, or if their values
027 * return true for <code>equals()</code>. This implementation uses
028 * reflection to work for any subclass of <code>Struct</code>.
029 * @param other candidate object
030 * @return true if it is equal to this object
031 */
032 public final boolean equals(final Object other) {
033 if (other == null || getClass() != other.getClass()) {
034 return false;
035 }
036
037 // traverse class hierarchy, finding declared fields. This is
038 // necessary since getFields() only returns public fields.
039 for (Class<?> i = getClass(); i != Struct.class; i = i.getSuperclass()) {
040 final Field[] fields = i.getDeclaredFields();
041 AccessibleObject.setAccessible(fields, true);
042 Arrays.sort(fields,
043 new Comparator<Field>() {
044 public int compare(final Field a, final Field b) {
045 return a.getName().compareTo(b.getName());
046 }
047 });
048 for (final Field f : fields) {
049 if (!Modifier.isStatic(f.getModifiers())) {
050 try {
051 final Object a = f.get(this);
052 final Object b = f.get(other);
053 if (a == null ? b != null : !a.equals(b)) {
054 return false;
055 }
056 } catch (final IllegalAccessException e) {
057 // Should never happen.
058 throw new IllegalAccessError();
059 }
060 }
061 }
062 }
063
064 return true;
065 }
066
067 /**
068 * Calculates the hash code.
069 *
070 * This method will satisfy the contract of the hashCode method for any
071 * subclass of <code>Struct</code>. (two structs that are
072 * <code>equal()</code> structs will always have the same hashCode). The
073 * precise return value of this method is unspecified, and may change in
074 * future releases.
075 * @return a hash value
076 */
077 public final int hashCode() {
078 return getClass().getName().hashCode();
079 }
080 }