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 }